davka
davka

Reputation: 14682

XPATH: select nodes of given name which are immediately following some specific nodes

best shown by a simplified example:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <A name="wrong"></A>
    <B>not this</B>
    <A name="right">
      <subA></subA>
    </A>
    <B>yes, this</B>  <!-- I want only this one -->
    <A name="right">
      <subA></subA>
    </A>
    <C>dont want this</C>
    <B>not this either</B>  <!-- not immediately following -->
</root>

I want all <B> nodes that are immediately following an <A> node with name attribute equals "right".

What I tried:

//A[@name="right"]/following-sibling::*[1]

which selects any node immediately following the "right" <A> (i.e. including <C>). I don't see how to make it only <B>. This didn't work:

//A[@name="right"]/following-sibling::*[1 and B]

This one:

//A[@name="right"]/following-sibling::B[1]

would select the first <B> after the "right" <A>, but not necessarily the immediately following one.

Upvotes: 17

Views: 27601

Answers (3)

Vaman Kulkarni
Vaman Kulkarni

Reputation: 3451

You can try this //B[preceding-sibling::A[1][@name='right']] This returns you node which you are interested in.

Hope this helps

Upvotes: 0

AakashM
AakashM

Reputation: 63338

You were nearly there:

//A[@name='right']/following-sibling::*[position()=1 and self::B]

gives exactly one node on your sample.

To refer to the element name in a condition, you need self. Simply [B] would mean an element with text exactly equal to B.

Upvotes: 10

Emiliano Poggi
Emiliano Poggi

Reputation: 24826

Just to point out that you were not so far with the first XPath shown in your question:

  //A[@name='right']/following-sibling::*[1][local-name()='B']

position() is not indispensable here.

Upvotes: 3

Related Questions