How to use XPath preceding-sibling correctly?

Viewed 2394

I'm having a trouble selecting preceding siblings. Here's the html:

<div>
  <h2>Apple</h2>
  <div class="row">A</div>
  <h2>Banana</h2>
  <div class="row">B</div>
  <h2>Strawberry</h2>
  <div class="row">C</div>
</div>

My XPath: preceding-sibling::h2.

What I want to do: Select every closest previous h2 element for every div.row .

For example, div.row A gives me Apple h2, div.row B gives me Banana h2 and div.row C gives me Strawberry h2.

The problem is my XPath was wrong, it only selected Apple h2 for every div.row. How can I fix this?

2 Answers

If you want to select closest preceding sibling - just add index [1]:

preceding-sibling::h2[1]

The XPath axis, preceding-sibling, contains all preceding sibling nodes of the context node. The XPath, preceding-sibling::h2, selects all h2 sibling elements starting from the context node.

Therefore, if the context node is <div class="row">C</div> element,

/div/div[.="C"]/preceding-sibling::h2

selects

<h2>Apple</h2>
<h2>Banana</h2>
<h2>Strawberry</h2>

Indexing starts nearest the current node, so

/div/div[.="C"]/preceding-sibling::h2[1]

selects just

<h2>Strawberry</h2>

and

/div/div[.="C"]/preceding-sibling::h2[last()]

selects just

<h2>Apple</h2>

The above examples, of course, would also hold true if you obtained the context node programmatically (rather than as /div/div[.="C"] via XPath) and used preceding-sibling::h2[1] or preceding-sibling::h2[last()] relative to the context node in the hosting language/framework (nokogiri).

Related