Discussion:
how to test if a child node have a specific name?
Chen Yi
2004-05-28 12:52:45 UTC
Permalink
ALl,
I want to test if the first child node is a specific name "NodeName" node.I
use the following expression.

<xsl:if test="child::node()[1]=NodeName">
...
</xsl:if>

But it doesn't work.
Then I changed the expression to

<xsl:if test="child::node()[1]='NodeName'">
...
</xsl:if>

or

<xsl:if test="name(child::node()[1])='NodeName'">
...
</xsl:if>

They all seem work.

I want to know which one is the correct one?
Thanks.


Chen Yi

_________________________________________________________________
与联机的朋友进行交流,请使用 MSN Messenger: http://messenger.msn.com/cn
G. Ken Holman
2004-05-28 13:14:35 UTC
Permalink
Post by Chen Yi
I want to test if the first child node is a specific name "NodeName"
node.I use the following expression.
<xsl:if test="child::node()[1]=NodeName">
...
</xsl:if>
But it doesn't work.
Two problems:

(1) the first of the child nodes might not be an element (when people type
XML they often put newline sequences at the end of start tags creating text
nodes as the first child node)

(2) your second operand is evaluated as the text content of the first child
name "NodeName", which isn't what you want.
Post by Chen Yi
Then I changed the expression to
<xsl:if test="child::node()[1]='NodeName'">
...
</xsl:if>
or
<xsl:if test="name(child::node()[1])='NodeName'">
...
</xsl:if>
They all seem work.
But they are not namespace-safe (even though you aren't yet using
namespaces), and it seems you are lucky that the first child node is not a
text node. And I'm surprised the first of those actually works since you
are not testing the name of the node but rather you are testing the text
content of the node.
Post by Chen Yi
I want to know which one is the correct one?
I suggest "none of the above" ... I would suggest the "correct" answer
would be:

test="child::*[1][self::NodeName]"

as this first looks at all children elements (ignoring child text nodes),
filters out only the first one, and then filters that one as being an
element with the name "NodeName". The resulting node set is empty if the
element is not as desired, and non-empty if the element is as desired,
resulting in the associated false/true boolean test. Using this style of
check will allow you to migrate safely to namespace-qualified element
types, as in:

test="child::*[1][self::ns:NodeName]"

I hope this helps.

............................ Ken

--
Public courses: Spring 2004 world tour of hands-on XSL instruction
Next: 3-day XSLT/XPath; 2-day XSL-FO - Birmingham, UK June 14,2004

World-wide on-site corporate, govt. & user group XML/XSL training.
G. Ken Holman mailto:***@CraneSoftwrights.com
Crane Softwrights Ltd. http://www.CraneSoftwrights.com/s/
Box 266, Kars, Ontario CANADA K0A-2E0 +1(613)489-0999 (F:-0995)
Male Breast Cancer Awareness http://www.CraneSoftwrights.com/s/bc
Legal business disclaimers: http://www.CraneSoftwrights.com/legal
Chen Yi
2004-05-28 13:30:17 UTC
Permalink
Thanks for you advise.
But I still have a question.
I think the following expresstion is correct.
Post by Chen Yi
<xsl:if test="name(child::node()[1])='NodeName'">
...
</xsl:if>
And as I am a new beginner of XSLT, I am confused what's the difference
between the term Node and Element, Can you kindly
explain it to me ? Thanks.

Chen Yi
Subject: Re: [xsl] how to test if a child node have a specific name?
Date: Fri, 28 May 2004 09:14:35 -0400
Post by Chen Yi
I want to test if the first child node is a specific name
"NodeName" node.I use the following expression.
<xsl:if test="child::node()[1]=NodeName">
...
</xsl:if>
But it doesn't work.
(1) the first of the child nodes might not be an element (when
people type XML they often put newline sequences at the end of start
tags creating text nodes as the first child node)
(2) your second operand is evaluated as the text content of the
first child name "NodeName", which isn't what you want.
Post by Chen Yi
Then I changed the expression to
<xsl:if test="child::node()[1]='NodeName'">
...
</xsl:if>
or
<xsl:if test="name(child::node()[1])='NodeName'">
...
</xsl:if>
They all seem work.
But they are not namespace-safe (even though you aren't yet using
namespaces), and it seems you are lucky that the first child node is
not a text node. And I'm surprised the first of those actually
works since you are not testing the name of the node but rather you
are testing the text content of the node.
Post by Chen Yi
I want to know which one is the correct one?
I suggest "none of the above" ... I would suggest the "correct"
test="child::*[1][self::NodeName]"
as this first looks at all children elements (ignoring child text
nodes), filters out only the first one, and then filters that one as
being an element with the name "NodeName". The resulting node set
is empty if the element is not as desired, and non-empty if the
element is as desired, resulting in the associated false/true
boolean test. Using this style of check will allow you to migrate
test="child::*[1][self::ns:NodeName]"
I hope this helps.
............................ Ken
--
Public courses: Spring 2004 world tour of hands-on XSL instruction
Next: 3-day XSLT/XPath; 2-day XSL-FO - Birmingham, UK June 14,2004
World-wide on-site corporate, govt. & user group XML/XSL training.
Crane Softwrights Ltd. http://www.CraneSoftwrights.com/s/
Box 266, Kars, Ontario CANADA K0A-2E0 +1(613)489-0999 (F:-0995)
Male Breast Cancer Awareness http://www.CraneSoftwrights.com/s/bc
Legal business disclaimers: http://www.CraneSoftwrights.com/legal
--+------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
--+--
_________________________________________________________________
享用世界上最大的电子邮件系统― MSN Hotmail。 http://www.hotmail.com
G. Ken Holman
2004-05-28 14:03:23 UTC
Permalink
Post by Chen Yi
Thanks for you advise.
But I still have a question.
I think the following expresstion is correct.
Post by Chen Yi
<xsl:if test="name(child::node()[1])='NodeName'">
...
</xsl:if>
And as I am a new beginner of XSLT, I am confused what's the difference
between the term Node and Element, Can you kindly explain it to me ? Thanks.
There are four different types of nodes found along the child:: axis -
elements, comments, processing instructions, and text nodes. When you use
"node()" you are checking *all* four kinds of node along the given
axis. When you use "*" you are checking only elements along the given axis.

And, yes, it happens to be true that your expression works regarding the
node name, but I did qualify my suggestion by saying that it works in this
limited situation where your element types are not namespace-qualified ...
you asked for the "correct" expression, and I maintain that the "correct"
expression is to use the self:: axis and not to use the name() function.

When I teach XSLT I underscore that the name() function is suitable for
exposition but not suitable for node checking.

I maintain that your expression above is not sufficient in the general case
because of possible text nodes at the start of your child nodes and of
possible future use of namespace-qualified element types, therefore I will
stick to:

test="child::*[1][self::NodeName]"

as being the "correct" way to do what you have requested.

I hope this helps.

......................... Ken


--
Public courses: Spring 2004 world tour of hands-on XSL instruction
Next: 3-day XSLT/XPath; 2-day XSL-FO - Birmingham, UK June 14,2004

World-wide on-site corporate, govt. & user group XML/XSL training.
G. Ken Holman mailto:***@CraneSoftwrights.com
Crane Softwrights Ltd. http://www.CraneSoftwrights.com/s/
Box 266, Kars, Ontario CANADA K0A-2E0 +1(613)489-0999 (F:-0995)
Male Breast Cancer Awareness http://www.CraneSoftwrights.com/s/bc
Legal business disclaimers: http://www.CraneSoftwrights.com/legal
David Carlisle
2004-05-28 13:25:47 UTC
Permalink
Post by Chen Yi
I want to know which one is the correct one?
they are all correct XSLT but I suspect none of them really tests what
you want,

Note that in
<a>
<b/>
<c/>
</a>

the first node of a does not have name "b" as it is a text node with
string value a newline and name "". So you probably want to test with
element nodes (*) rather than all nodes (node() )

test="child::node()[1]=NodeName"

This tests if the string value (ie, the content, not the name) of the
first node is equal to the string value of any child element with name
NodeName

so it would be true on

<a><x>hello</x> <hh/> <NodeName>hello</NodeName></x>

as the two "hello" are equal.

test="child::node()[1]='NodeName'"

tests if the string value of the first node is the string "Nodename"
so it would be true on


<a><x>NodeName</x> <hh/> </x>


test="name(child::node()[1])='NodeName'"

This is nearly what you want and would be true on
<a><NodeName>hello</NodeName> ....</x>
But it is false on
<a>
<NodeName>hello</NodeName> ....
</x>

I suspect you want

test="*[1][self::NodeName]"

David
--
The LaTeX Companion
http://www.awprofessional.com/bookstore/product.asp?isbn=0201362996
http://www.amazon.co.uk/exec/obidos/tg/detail/-/0201362996/202-7257897-0619804


________________________________________________________________________
This e-mail has been scanned for all viruses by Star Internet. The
service is powered by MessageLabs. For more information on a proactive
anti-virus service working around the clock, around the globe, visit:
http://www.star.net.uk
________________________________________________________________________
Chen Yi
2004-05-28 14:52:50 UTC
Permalink
Thanks for you explanation.
Your explanation is easily understand.
I think you have grasp the prime of XSLT.
I have two basic questions.
(1) what can I do to skip the text with newline and name ""?
(2) <xsl:variable name="Operator">
<xsl:if test="child::*[1][self::AND]>
<xsl:value-of select="'AND'"/>
</xsl:if>
</xsl:variable>

So if the first element have the name 'AND', the Operator variable will
have a text of AND.
And I use the following expression to test if Operator is set.

<xsl:if test="$Operator = 'AND'">
....
</xsl:if>

I konw the content of Vairable Oprator is a tree segment with a root
node and a text. What the Oprator will like if the first child element is
not AND?

Thanks in advance
Chen Yi
Subject: Re: [xsl] how to test if a child node have a specific name?
Date: Fri, 28 May 2004 14:25:47 +0100
Post by Chen Yi
I want to know which one is the correct one?
they are all correct XSLT but I suspect none of them really tests what
you want,
Note that in
<a>
<b/>
<c/>
</a>
the first node of a does not have name "b" as it is a text node with
string value a newline and name "". So you probably want to test with
element nodes (*) rather than all nodes (node() )
test="child::node()[1]=NodeName"
This tests if the string value (ie, the content, not the name) of the
first node is equal to the string value of any child element with name
NodeName
so it would be true on
<a><x>hello</x> <hh/> <NodeName>hello</NodeName></x>
as the two "hello" are equal.
test="child::node()[1]='NodeName'"
tests if the string value of the first node is the string "Nodename"
so it would be true on
<a><x>NodeName</x> <hh/> </x>
test="name(child::node()[1])='NodeName'"
This is nearly what you want and would be true on
<a><NodeName>hello</NodeName> ....</x>
But it is false on
<a>
<NodeName>hello</NodeName> ....
</x>
I suspect you want
test="*[1][self::NodeName]"
David
--
The LaTeX Companion
http://www.awprofessional.com/bookstore/product.asp?isbn=0201362996
http://www.amazon.co.uk/exec/obidos/tg/detail/-/0201362996/202-7257897-0619804
________________________________________________________________________
This e-mail has been scanned for all viruses by Star Internet. The
service is powered by MessageLabs. For more information on a proactive
http://www.star.net.uk
________________________________________________________________________
--+------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
--+--
_________________________________________________________________
与联机的朋友进行交流,请使用 MSN Messenger: http://messenger.msn.com/cn
Loading...