I want to find all the immediately adjacent siblings of a node using a single XPath expression, if at all possible. Given the input
<a id="1"/>
<start/>
<a id="2"/>
<a id="3"/>
<b/>
<a id="4"/>
and an XPath expression similar to //start/following-sibling::a, I want to select a[2], and a[3], but not a[4]. Also, if there are any intervening elements between start and a[2], nothing should be selected.
The simplest one I can find was this:
//start/following-sibling::a intersect //start/following-sibling::*[name()!='a'][1]/preceding-sibling::a
What this does is:
a siblings following start: //start/following-sibling::a. (Result: a2, a3, a4.) Set this to one side for now.start: //start/following-sibling::*[name()!='a'][1] (Result: b.)a nodes that precede it: /preceding-sibling::a. (Result: a1, a2, a3)Update: Another way to phrase it is //start/following-sibling::*[name()!='a'][1]/preceding-sibling::a[preceding-sibling::start], this roughly translates to: take the first non-a sibling following start, count backwards but only choose elements that are still preceded by start.
Update 2: If you know that b will always be called b, you can of course replace the rather hard to read following-sibling::*[name()!='a'][1] part with following-sibling::b[1].
Following a solution that works with XPath 1.0:
//start[following-sibling::*[1][name() = 'a']]/following-sibling::a[last() = count(preceding-sibling::*[name() != 'a'][1]/following-sibling::a)]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With