XPath轴,获取所有后续节点,直到

Lee*_*vis 14 ruby xpath nokogiri

我有以下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 ... -->
Run Code Online (Sandbox Code Playgroud)

我想要提取'Foo bar'标题后的所有段落,直到我到达'Bar baz'标题('bar baz'标题的文字未知,所以不幸的是我无法使用bougyman提供的答案).现在我当然可以使用类似的东西,//h2[text()='Foo bar']/following::p但当然会抓住这个标题后面的所有段落.因此,我可以选择遍历节点集并将段落推送到数组,直到文本与下一个标题的文本匹配为止,但说实话,这在XPath中无法做到.

有没有办法做到这一点,我错过了?

Dim*_*hev 19

用途:

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

如果保证每个h2都有不同的值,这可以简化为:

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

这意味着:选择p跟随h2其字符串值为(文档中的第一个或仅一个)的'Foo bar'兄弟节点的h2所有p元素,并且所有这些元素的前一个兄弟(first or only one in the document) whose string value is节点正好是h2'Foo bar'.

在这里,我们使用一种方法来查找两个节点是否相同:

count($n1 | $n2) = 1
Run Code Online (Sandbox Code Playgroud)

true()恰好当节点$n1$n2是相同的节点.

这个表达式可以推广:

$x/following-sibling::p
       [1 = count(preceding-sibling::node()[name() = name($x)][1] | $x)]
Run Code Online (Sandbox Code Playgroud)

选择$ x指定的任何节点的所有"紧随其后的兄弟姐妹".

  • *叹气*为什么我甚至懒得和你一起回答xpath问题?我曾希望你睡着了;)我的概念上比较简单(对我而言),但我确信你的表现更好.+1 (9认同)
  • @phrogz:我真的很抱歉,我在星期六早上6点醒来,没有更好的事情要做:) (6认同)