24

I have a quite simple problem but i can't seem to resolve it. Let's say i have the following code:

<a>
    <b property="p1">zyx</b>
    <b>wvu</b>
    <b>tsr</b>
    <b property="p2">qpo</b>
    <b>qcs</b>
</a>

I want to select the nodes between the b node who has a property="p1" and the b node who has property="p2". I can do either of those with the preceding-sibling and the following-sibling axis but I can't seem to find how to combine both.

Abel
  • 56,041
  • 24
  • 146
  • 247
raph.amiard
  • 2,755
  • 2
  • 20
  • 23

3 Answers3

21

XPath 1.0:

/a/b[preceding-sibling::b/@property='p1' and following-sibling::b/@property='p2']

XPath 2.0:
The expression above has some quirks in XSLT 2.0, it is better to use the new and safer operators << (before) and >> (after).

/a/b[../b[@property='p2'] << . and . >> ../b[@property='p1']]
Abel
  • 56,041
  • 24
  • 146
  • 247
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
8

Also, this XPath 1.0:

/a/b[preceding-sibling::b/@property='p1'][following-sibling::b/@property='p2']

Note: Don't use // as first step. Whenever you can replace and operator by predicates, do it.

In XPath 2.0:

/a/b[. >> ../b[@property='p1']][../b[@property='p2'] >> .]
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • Thank you for your answer, exactly what i need. But i'm curious as to why would you replace and by another predicate ? – raph.amiard Aug 03 '10 at 08:09
  • @raph.amiard: From http://www.w3.org/TR/xpath/#booleans: "An and expression is evaluated by evaluating each operand". So, if left operand is false, right operand will be evaluate any way. With predicates, only for those nodes that pass first filter, the second predicate will be apply on them. For XPath 2.0, this MAY be not the case. –  Aug 03 '10 at 12:59
  • Was trying this solution and it works great. However what if eh example above had another downline? How do you stop at the first occurrence? – sinDizzy Nov 14 '18 at 21:52
-1

You can combine the tests in the predicate using and.

Paul Butcher
  • 6,902
  • 28
  • 39
  • 2
    Indeed, spelled out it would read something like: `//b[preceding-sibling::b/@property='p1' and following-sibling::b/@property='p2']` – Wrikken Aug 02 '10 at 15:08
  • Wrikken : ok thank you. I didn't know i could use preceding and following sibling like that, i only ever saw it used like "b[@property="p1"]/following-sibling::*" Paul Butcher : i knew that, but thank you for taking the time to answer – raph.amiard Aug 02 '10 at 15:15