Suppose I have following xml
<root>
<x>
<y />
<z>
<y />
</z>
<n>
<m>
<y />*
</m>
</n>
</x>
<x>
<y />
<z>
<y />
</z>
<y />*
</x>
</root>
I would like to retrieve those y nodes which are followed with *
So it is always third node in x ancestor node
I tried something like:
//x//y[3]
However it doesn't work I guess it would work only if y nodes are on the same level.
So I tried
(//x//y)[3] but it retrieves only one node (third one) in whole document
So I tried something like:
//x(//y)[3]
//x(//y[3])
//x//(y[3])
etc. but I get parse error
Is there any way to retrieve what I need using xpath?
Use:
//x/descendant::y[3]
This selects every third y descendant of each x in the document. It sometimes helps to write out an expanded expression to see what's really going on. In this case, the following:
//x//y[3]
is equivalent to:
/descendant-or-self::node()/child::x/descendant-or-self::node()/child::y[3]
Written this way it becomes obvious why it doesn't do what you wanted (i.e. it's looking for any y that is the third child of an x element and there isn't one). What you really wanted was every third y descendant. Here it is fully expanded:
/descendant-or-self::node()/child::x/descendant::y[3]
The important lesson here is that it pays to know what the XPath abbreviated syntax is really doing. The spec is actually quite readable. I recommend taking a look.
Update: both of these examples are XPath 2.0 only.
In XPath 1.0:
/row//y/(ancestor::x//y)[3]
In XPath 2.0:
for $x in /row//x
return ($x//y)[3]
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