XPath axis, get all following nodes until

2019-01-09 01:53发布

I have the following example of HTML:

<!-- lots of html -->
<h2>Foo bar</h2>
<p>lorem</p>
<p>ipsum</p>
<p>etc</p>

<h2>Bar baz</h2>
<p>dum dum dum</p>
<p>poopfiddles</p>
<!-- lots more html ... -->

I'm looking to extract all paragraphs following the 'Foo bar' header, until I reach the 'Bar baz' header (the text for the 'Bar baz' header is unknown, so unfortunately I can't use the answer provided by bougyman). Now I can of course using something like //h2[text()='Foo bar']/following::p but that of course will grab all paragraphs following this header. So I have the option to traverse the nodeset and push paragraphs into an Array until the text matches that of the next following header, but let's be honest, that's never as cool as being able to do it in XPath.

Is there a way to do this that I'm missing?

7条回答
小情绪 Triste *
2楼-- · 2019-01-09 02:20

Use:

(//h2[. = 'Foo bar'])[1]/following-sibling::p
   [1 = count(preceding-sibling::h2[1] | (//h2[. = 'Foo bar'])[1])]

In case it is guaranteed that every h2 has a distinct value, this may be simplified to:

//h2[. = 'Foo bar']/following-sibling::p
   [1 = count(preceding-sibling::h2[1] | ../h2[. = 'Foo bar'])]

This means: Select all p elements that are following siblings of the h2 (first or only one in the document) whose string value is 'Foo bar' and also the first preceding sibling h2 for all these p elements is exactly the h2(first or only one in the document) whose string value is'Foo bar'`.

Here we use a method of finding whether two nodes are identical:

count($n1 | $n2) = 1

is true() exactly when the nodes $n1 and $n2 are the same node.

This expression can be generalized:

$x/following-sibling::p
       [1 = count(preceding-sibling::node()[name() = name($x)][1] | $x)]

selects all "immediate following siblings" of any node specified by $x.

查看更多
登录 后发表回答