I have an XML file like this:
<lib:library>
<lib:book> XML </lib:book>
<lib:book> XPath </lib:book>
<lib:book> XSLT </lib:book>
<lib:book> Java </lib:book>
<lib:book> C++ </lib:book>
</lib:library>
and I want to go the book[2]...I can of course doing something like //lib:Book[2]...and it works. It could happen that in the same XML file I have, for example , same tag name but different namespace; in this case my XPath expression does not work...
I can replace it doing:
//*[local-name() = "book"]
This expression returns all the book containined in the XML file...but what if I want to get the number [2]...how should I rewrite the XPath expression adding condition about number? Of course I do not want to consider namespaces, it must be valid for every used namespace.
Thanks Luca
The currently-selected answer is wrong.
In fact //someExpression[2] can select many nodes.
For example, if we have the following XML document:
<lib:library xmlns:lib="UNDEFINED!!!">
<topic name="XML">
<lib:book> XML </lib:book>
</topic>
<topic name="XPath">
<lib:book> XPath </lib:book>
</topic>
<topic name="XSLT">
<lib:book> XSLT1 </lib:book>
<lib:book> XSLT2 </lib:book>
</topic>
<topic name="Imperative PLs">
<lib:book> Java </lib:book>
<lib:book> C++ </lib:book>
</topic>
</lib:library>
When the expression:
//*[local-name() = "book"][2]
is evaluated against the document above, two nodes are selected (and none of them is the second node in the document with the wanted properties):
<lib:book xmlns:lib="UNDEFINED!!!"> XSLT2 </lib:book>
<lib:book xmlns:lib="UNDEFINED!!!"> C++ </lib:book>
Solution: One way to select the Nth (say 2nd) node (say lib:book) in the whole document is:
(//*[local-name() = "book"])[2]
When this expression is evaluated on the document above, the correct, single node is selected:
<lib:book xmlns:lib="UNDEFINED!!!"> XPath </lib:book>
Explanation: As defined in the W3C XPath recommendations:
//is short for/descendant-or-self::node()/
Therefore:
//someName[2]
is a shorthand for:
/descendant-or-self::node()/someName[2]
and this selects any element in the document named someName and which is the second someName child of its parent.
To put it in other words, the [] operator binds more strongly (has higher precedence) than the // pseudo-operator. This is why we need brackets to override the default operator precedence.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With