Jack Fleeting
Jack Fleeting

Reputation: 24930

Confused about the effects of preceding-sibling and following-sibling

I'm confused about what must be something basic, and previous questions (and the documentation) don't really help.

Say we have these 6 siblings:

<a_tag>... a1 ...</a_tag>
<b_tag>... b1 ...</b_tag>
<a_tag>... a2 ...</a_tag>
<b_tag>... b2 ...</b_tag>
<a_tag>... a3 ...</a_tag>
<b_tag>... b3 ...</b_tag>

Some xpath expressions work as I expect. For example, //a_tag selects all 3 a_tags; //a_tag[2] selects only a2.

Using //a_tag[following-sibling::b_tag] selects, again, all 3 a_tags.

Getting a little fancier, //a_tag[following-sibling::b_tag[2]] correctly selects a1 and a2. However, using //a_tag[following-sibling::b_tag[3]], selects only a1, while I expected it to select all 3 a_tags (because they are all followed by b_tag[3].

And then //a_tag[preceding-sibling::b_tag[1]][following-sibling::b_tag[2]] selects a2, as expected, but //a_tag[preceding-sibling::b_tag[2]][following-sibling::b_tag[3]], which I expected to select a3 comes up empty.

If you throw at it something which I would expect to select nothing, like //a_tag[preceding-sibling::b_tag[2]][following-sibling::b_tag[1]], selects a3 instead.

There are more like these, but I believe the problem is clear enough. Any light thrown on this would be appreciated.

Upvotes: 1

Views: 410

Answers (2)

kjhughes
kjhughes

Reputation: 111541

However, using //a_tag[following-sibling::b_tag[3]], selects only a1, while I expected it to select all 3 a_tags (because they are all followed by b_tag[3]).

Here's how to adjust your model to match XPath's actual behavior:

  • //a_tag
    • Select all a_tag elements (as you mentioned).
  • //a_tag[following-sibling::b_tag[3]]
    • Of all selected a_tag elements, select only those that have a third following sibling b_tag element, which is only the single <a_tag>a1</a_tag>, as observed.

Upvotes: 1

supputuri
supputuri

Reputation: 14135

Ok, Let me explain how this works.

//a_tag[following-sibling::b_tag[$n]]

In general language this means get me all a_tags which have $n of following-siblings. Consider the below example:

//a_tag[following-sibling::b_tag[1]]

This says get me all the a_tags which have 1 b_tag after. Now, that all the a_tags in the example have 1 b_tag after a_tags, you will see all 3 a_tags selected.

You will see only the first a_tag selected when used below xpath, because that's the only tag which have 3 b_tags after.

//a_tag[following-sibling::b_tag[3]]


Coming to the below xpath

//a_tag[preceding-sibling::b_tag[1]][following-sibling::b_tag[2]]

When you have multiple conditions [] in xpath, it will execute from left to right meaning it will complete the left side condition then apply the next condition. So, the meaning of above xpath is get me all a_tags which have b_tags 1 before and 2 after, so a2 is the only node which have b1 (1 b_tag) before and b2 and b3 (2 b_tags) after.

//a_tag[preceding-sibling::b_tag[2]][following-sibling::b_tag[3]] give you empty because you don't have a_tag which have 2 b_tags before and 3 b_tags after.

Now you should under why //a_tag[preceding-sibling::b_tag[2]][following-sibling::b_tag[1]] selected a3.

Hope I am clear.

Upvotes: 2

Related Questions