Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for n-th instance of x node in root node

Tags:

xpath

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?

like image 487
zimi Avatar asked Feb 22 '26 09:02

zimi


2 Answers

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.

like image 108
Wayne Avatar answered Feb 27 '26 02:02

Wayne


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]
like image 37
joemfb Avatar answered Feb 27 '26 02:02

joemfb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!