Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XPath: how to select following siblings until a certain sibling

Tags:

For the example HTML below, an XPath query that returns the siblings of the "a" elements with class='A' that have class='B' can be written as: //a[@class='A']/following-sibling::a[@class='B']. This query outputs 4 <a class="B"/> elements.

However, I would only like the <a class="B"/> elements that follow the current <a class="A"/> element, and no others that follow other <a class="B"/> elements/nodes. In other words, I only want the following <a class="B"/> sibling elements until the next <a class="B"/> element shows up.

Example HTML:

<a class='A' /> <a class='B' /> <a class='A' /> <a class='B' /> <a class='B' /> <a class='B' /> 

Any ideas on how to limit my current XPath query to just those siblings would be much appreciated :)

like image 607
user3674248 Avatar asked May 25 '14 23:05

user3674248


People also ask

How can XPath follow siblings?

We can use the concept of following-sibling in xpath for identifying elements in Selenium. It identifies the siblings of the context node. The siblings should be located at the equal level of the existing node and should have the same parent.

What is the difference between preceding and preceding-sibling?

In this diagram, the preceding:: nodes are circled, and the more specific preceding-sibling:: nodes are given a red border. The preceding-siblings are nodes that share the same parent node, and come before the current node in the document. The preceding:: node is any node that comes before the element in the document.

What is preceding and following in XPath?

The following-sibling and preceding-sibling axes contain the siblings before or after the context node, and the following and preceding axes contain all nodes in the document before or after the context node, but: None of these axes contain attribute or namespace nodes.


1 Answers

To select all a elements having a class attribute of B between some specific a with a class equal to A and the next such occurrence:

/*/a[@class='A'][$n]/following-sibling::a[     @class='B' and count(preceding-sibling::a[@class='A'])=$n] 

This selects everything between the nth a[@class='A'] and the next such element. For a specific example, consider the following input:

<r>   <a class="A"/>     <a class="B"/>     <a class="A"/>     <a class="B"/>     <a class="B"/>     <a class="A"/>     <a class="B"/>     <a class="B"/>     <a class="B"/> </r> 

To get the two elements between the second <a class="A"/> and the third <a class="A"/>:

/*/a[@class='A'][2]/following-sibling::a[     @class='B' and count(preceding-sibling::a[@class='A'])=2] 

In English, this says:

Give me all of the a elements having a class attribute whose value is equal to B that come after the second a having a class attribute equal to A and that have only two preceding siblings having a class attribute equal to A

Similarly, and more generally, we can apply the Kayessian method for finding the intersection of two node sets. In the example given, we want the intersection of all the @class='B' elements in 1) the set of siblings after the second <a class="A"/> and 2) the set of siblings before the third <a class="A"/>. The intersection of these two sets is precisely the nodes that come between those two divider elements and can be expressed like this:

/*/a[@class='A'][2]/following-sibling::a[@class='B'][     count(.|/*/a[@class='A'][3]/preceding-sibling::a[@class='B'])=     count(/*/a[@class='A'][3]/preceding-sibling::a[@class='B'])] 
like image 57
Wayne Avatar answered Oct 05 '22 23:10

Wayne