2

这适用于 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>不包含 a 的,直到下一个包含a或直到封闭元素的结尾。<iframe><p><iframe><div>

为了使事情稍微复杂一些,出于特定原因,我需要使用 each<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元素,而不是在包含 a<p>的下一个元素处停止。<p><iframe>

我已经有一段时间了,尽管我通常对这类事情很方便,但我不能完全按照自己的方式工作,而且谷歌等的搜索结果都没有帮助。

谢谢。任何帮助总是受到赞赏。

编辑:可以假设<div class="entry">文档中只有一次出现。

4

2 回答 2

1

如果没有帮助,您所要求的无法在一个 XPath 1.0 表达式中完成。问题是你想问的问题是

从元素 X(包含 p-with-an-iframe)开始,找到与p该元素最近的前面 p-with-an-iframe 是原始节点 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一个的元素。preceding-sibling::p[iframe]$x

那么问题的关键是如何从内部谓词内部到达外部上下文节点——纯 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是第一个表达式/迭代计数器的结果)并使用相同的上下文节点对其进行评估,将最终结果作为节点集。

于 2015-01-09T17:29:54.940 回答
0

我不确定我是否完全理解,但有时对尝试的解决方案发表评论而不是试图解释会有所帮助。

请尝试以下 XPath 表达式:

//div[@class='entry']//iframe//p[not(descendant::iframe)]

让我知道这是否会产生正确的结果。

如果不,

  • 解释结果与您需要的结果有何不同
  • 请展示一个更完整的 HTML 示例:一个包含多个元素的合理文档div,并且不止一个 where div[@class = 'entry']- 否则涵盖您描述的所有复杂性。
  • 解释你为什么添加[1][2]你的表达
  • 提供有关您使用 XPath 的平台的更多详细信息,可能是发布代码
于 2015-01-09T09:31:26.590 回答