XPath(1.0)匹配连续元素直到特定子项或结尾

时间:2015-01-09 04:10:54

标签: xpath xpath-1.0

这适用于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>作为基础,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> - 少<p>个元素一直到最后,而不是停留在包含的下一个<p> <iframe>

我已经参与了一段时间,虽然我通常对这类事情非常方便,但我不能完全按照这个方式工作,Google和其他搜索结果都没有帮助

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

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

2 个答案:

答案 0 :(得分:1)

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

  

从元素X(包含p的if-iframe)开始,找到该元素的最近前面的p-with-an-iframe是原始节点X的其他p元素

如果我们有一个变量$x持有对顶级上下文节点的引用(我们从p[iframe]开始),那么你可以说下面的内容(在XPath 2.0中)< / p>

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是第一个表达式/迭代计数器的结果)并使用相同的上下文节点对其进行评估,将最终结果作为节点集。

答案 1 :(得分:0)

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

请尝试以下XPath表达式:

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

如果这会产生正确的结果,请告诉我。

如果没有,

  • 解释结果与您需要的结果有何不同
  • 请展示更完整的HTML示例:包含多个div元素的合理文档,以及div[@class = 'entry']以外的多个元素 - 并覆盖您描述的所有复杂性。
  • 解释您为表达式添加[1][2]的原因
  • 提供有关您使用XPath的平台的更多详细信息,可能是邮政编码