3

Assuming we have such a structure (the number of b in every a is unknown):

<a>
    <b/>
    <b/>
    <b/>
</a>
<a>
    <b/>
    <b/>
    <b/>
</a>

How would we express the following phrase in xpath: "top 4 b elements nested into a"

The a/b[position() <= 4] for obvious reasons returns all 6 elements.

How would I limit it to 4?

I've found that (a/b)[position() <= 4] should work, but seems it's xpath 2.0. Any ideas for 1.0 version?

zerkms
  • 249,484
  • 69
  • 436
  • 539

2 Answers2

4

Not pretty, but this checks how many <b>s there are earlier in the document.

a/b[count(preceding::b) < 4]

It's not perfect. If there are other <b>s not inside of <a>s it'll fail. For example:

<b>oops</b>
<a>
    <b/>
    <b/>
    <b/>
</a>
<a>
    <b/>
    <b/>
    <b/>
</a>

This one doesn't get tripped up by the <b>oops</b> element.

a/b[count(preceding::b/parent::a) < 4]
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
2

Why do you say

(a/b)[position() <= 4] should work, but seems it's xpath 2.0

? That's perfectly legitimate XPath 1.0, and in fact is a common idiom for this purpose. I just tested it to confirm that it's accepted and works correctly.

It may also be more efficient than using count(preceding::b), depending on the XPath processor.

LarsH
  • 27,481
  • 8
  • 94
  • 152
  • Well, I tried it with PHP DOM XPath, and it says the expression is wrong. So as soon as it only supports 1.0, I assumed that syntax isn't 1.0 – zerkms Jul 03 '13 at 20:43
  • Checked it now once again, and now it works. Feeling stupid :-S – zerkms Jul 03 '13 at 20:46