XPath (1.0) 匹配连续元素直到特定的子元素或结束
XPath (1.0) Match consecutive elements until specific child or end
这是针对 XPath 1.0 的。
这是我匹配的标记示例。元素的实际数量不是提前知道的,因此会有所不同,但遵循这种模式:
<div class="entry">
<p><iframe /></p>
<p>Text 1</p>
<p>Text 2</p>
<p>Test 3</p>
<p><iframe /></p>
<p>
<a>Test 4</a>
<br />
<a>Test 5</a>
</p>
</div>
我正在尝试匹配 而不是 的每个 <p>
包含 <iframe>
,直到 的下一个 <p>
包含一个 <iframe>
或直到封闭的 <div>
元素结束。
为了让事情稍微复杂一些,出于特定原因我需要使用每个 <iframe>
作为基础,a la //div[@class='entry']//iframe
,这样每个节点集都基于
(//div[@class='entry']//iframe)[1]
(//div[@class='entry']//iframe)[2]
...
因此,在这种情况下,匹配
<p>Text 1</p>
<p>Text 2</p>
<p>Test 3</p>
和
<p>
<a>Test 4</a>
<br />
<a>Test 5</a>
</p>
分别
我尝试了以下一些测试无济于事:
(//div[@class='entry']//iframe)/ancestor::p/following-sibling::p[preceding-sibling::p[iframe]]
(或用于测试):
(//div[@class='entry']//iframe)[1]/ancestor::p/following-sibling::p[preceding-sibling::p[iframe]]
(//div[@class='entry']//iframe)[2]/ancestor::p/following-sibling::p[preceding-sibling::p[iframe]]
及其一些变体,但第一组发生的事情是它获取所有 <iframe>
-less <p>
元素一直到最后,而不是在下一个 <p>
处停止包含 <iframe>
.
我已经有一段时间了,尽管我通常对这类事情很得心应手,但我无法完全按照自己的方式工作,[=54 的搜索结果都没有=] 等等有帮助。
谢谢。任何帮助总是感激。
编辑:可以假定 <div class="entry">
在文档中只出现一次。
我不确定我是否完全理解,但有时对尝试的解决方案发表评论比尝试解释更有帮助。
请尝试以下 XPath 表达式:
//div[@class='entry']//iframe//p[not(descendant::iframe)]
如果结果正确,请告诉我。
如果没有,
- 解释结果与您需要的有何不同
- 请展示一个更完整的 HTML 示例:一个包含多个
div
元素的合理文档,以及多个 div[@class = 'entry']
元素 - 否则涵盖您描述的所有复杂性。
- 解释为什么要在表达式中添加
[1]
和 [2]
- 提供有关您使用 XPath 的平台的更多详细信息,也许 post 代码
如果没有帮助,您无法用一个 XPath 1.0 表达式完成您的要求。问题是你想问的问题是
Starting from an element X (the p-containing-an-iframe), find the other p
elements for which that element's nearest preceding p-with-an-iframe is the original node X
如果我们有一个变量 $x
保存对顶级上下文节点(我们开始的 p[iframe]
)的引用,那么您可以说类似下面的内容(在 XPath 2.0 中) )
following-sibling::p[not(iframe)][preceding-sibling::p[iframe][1] is $x]
XPath 1.0 没有 is
运算符来比较节点身份,但您可以使用其他代理,例如
following-sibling::p[not(iframe)][count(preceding-sibling::p[iframe])
= (count($x/preceding-sibling::p[iframe]) + 1)]
即p
之后比 $x
多 preceding-sibling::p[iframe]
的元素。
那么问题的核心是如何从内部谓词内部获取外部上下文节点——纯 XPath 1.0 无法做到这一点。在 XSLT 中,您有 current()
函数,但除此之外,您有两个基本选择:
- 如果您的 XPath 库允许您为表达式提供变量绑定,则注入一个包含上下文节点的变量
$x
并使用我在上面给出的表达式。
- 如果您不能注入变量,则按顺序使用两个单独的 XPath 查询。
首先执行表达式
count(preceding-sibling::p[iframe]) + 1
与相关的p[iframe]
作为上下文节点,并将结果作为数字。或者,如果您已经在宿主语言中迭代这些 p[iframe]
元素,那么只需直接从那里获取迭代编号,您不需要使用 XPath 对其进行计数。无论哪种方式,您都可以动态构建第二个表达式:
following-sibling::p[not(iframe)][count(preceding-sibling::p[iframe]) = N]
(其中 N
是第一个 expression/iteration 计数器的结果)并使用相同的上下文节点对其进行评估,将最终结果作为节点集。
这是针对 XPath 1.0 的。
这是我匹配的标记示例。元素的实际数量不是提前知道的,因此会有所不同,但遵循这种模式:
<div class="entry">
<p><iframe /></p>
<p>Text 1</p>
<p>Text 2</p>
<p>Test 3</p>
<p><iframe /></p>
<p>
<a>Test 4</a>
<br />
<a>Test 5</a>
</p>
</div>
我正在尝试匹配 而不是 的每个 <p>
包含 <iframe>
,直到 的下一个 <p>
包含一个 <iframe>
或直到封闭的 <div>
元素结束。
为了让事情稍微复杂一些,出于特定原因我需要使用每个 <iframe>
作为基础,a la //div[@class='entry']//iframe
,这样每个节点集都基于
(//div[@class='entry']//iframe)[1]
(//div[@class='entry']//iframe)[2]
...
因此,在这种情况下,匹配
<p>Text 1</p>
<p>Text 2</p>
<p>Test 3</p>
和
<p>
<a>Test 4</a>
<br />
<a>Test 5</a>
</p>
分别
我尝试了以下一些测试无济于事:
(//div[@class='entry']//iframe)/ancestor::p/following-sibling::p[preceding-sibling::p[iframe]]
(或用于测试):
(//div[@class='entry']//iframe)[1]/ancestor::p/following-sibling::p[preceding-sibling::p[iframe]]
(//div[@class='entry']//iframe)[2]/ancestor::p/following-sibling::p[preceding-sibling::p[iframe]]
及其一些变体,但第一组发生的事情是它获取所有 <iframe>
-less <p>
元素一直到最后,而不是在下一个 <p>
处停止包含 <iframe>
.
我已经有一段时间了,尽管我通常对这类事情很得心应手,但我无法完全按照自己的方式工作,[=54 的搜索结果都没有=] 等等有帮助。
谢谢。任何帮助总是感激。
编辑:可以假定 <div class="entry">
在文档中只出现一次。
我不确定我是否完全理解,但有时对尝试的解决方案发表评论比尝试解释更有帮助。
请尝试以下 XPath 表达式:
//div[@class='entry']//iframe//p[not(descendant::iframe)]
如果结果正确,请告诉我。
如果没有,
- 解释结果与您需要的有何不同
- 请展示一个更完整的 HTML 示例:一个包含多个
div
元素的合理文档,以及多个div[@class = 'entry']
元素 - 否则涵盖您描述的所有复杂性。 - 解释为什么要在表达式中添加
[1]
和[2]
- 提供有关您使用 XPath 的平台的更多详细信息,也许 post 代码
如果没有帮助,您无法用一个 XPath 1.0 表达式完成您的要求。问题是你想问的问题是
Starting from an element X (the p-containing-an-iframe), find the other
p
elements for which that element's nearest preceding p-with-an-iframe is the original node X
如果我们有一个变量 $x
保存对顶级上下文节点(我们开始的 p[iframe]
)的引用,那么您可以说类似下面的内容(在 XPath 2.0 中) )
following-sibling::p[not(iframe)][preceding-sibling::p[iframe][1] is $x]
XPath 1.0 没有 is
运算符来比较节点身份,但您可以使用其他代理,例如
following-sibling::p[not(iframe)][count(preceding-sibling::p[iframe])
= (count($x/preceding-sibling::p[iframe]) + 1)]
即p
之后比 $x
多 preceding-sibling::p[iframe]
的元素。
那么问题的核心是如何从内部谓词内部获取外部上下文节点——纯 XPath 1.0 无法做到这一点。在 XSLT 中,您有 current()
函数,但除此之外,您有两个基本选择:
- 如果您的 XPath 库允许您为表达式提供变量绑定,则注入一个包含上下文节点的变量
$x
并使用我在上面给出的表达式。 - 如果您不能注入变量,则按顺序使用两个单独的 XPath 查询。
首先执行表达式
count(preceding-sibling::p[iframe]) + 1
与相关的p[iframe]
作为上下文节点,并将结果作为数字。或者,如果您已经在宿主语言中迭代这些 p[iframe]
元素,那么只需直接从那里获取迭代编号,您不需要使用 XPath 对其进行计数。无论哪种方式,您都可以动态构建第二个表达式:
following-sibling::p[not(iframe)][count(preceding-sibling::p[iframe]) = N]
(其中 N
是第一个 expression/iteration 计数器的结果)并使用相同的上下文节点对其进行评估,将最终结果作为节点集。