Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XPath expression

Tags:

xml

xpath

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

like image 944
Luca Avatar asked Jul 05 '26 08:07

Luca


1 Answers

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.

like image 59
Dimitre Novatchev Avatar answered Jul 07 '26 10:07

Dimitre Novatchev