【问题标题】:XPath: limit scope of result setXPath:限制结果集的范围
【发布时间】:2011-01-10 20:46:01
【问题描述】:

给定 XML

<a>
    <c>
        <b id="1" value="noob"/>
    </c>
    <b id="2" value="tube"/>
    <a>
        <c>
            <b id="3" value="foo"/>
        </c>
        <b id="4" value="goo"/>
        <b id="5" value="noob"/>
        <a>
            <b id="6" value="near"/>
            <b id="7" value="bar"/>
        </a>
    </a>
</a>

和 Xpath 1.0 查询

//b[@id=2]/ancestor::a[1]//b[@value="noob"]

上面的 Xpath 返回节点 id 1 和 5。目标是将结果限制为节点 id=1,因为它是唯一的 @value="noob" 元素,它是同一 &lt;a&gt; 的后代(@987654326 @) 也是的后代。

换句话说,“查找所有 b 元素,其值为“noob”,它们是 a 元素的后代,该元素也有一个 id 为 2 的后代,但是不是任何其他 a 元素的后代”。怎么这么纠结?实际上,id 编号和值是可变的,并且会有数百种节点类型。

如果 id=2,我们期望返回元素 id=1 而不是 id=5,因为它包含在另一个 a 元素中。如果 id=4,我们期望返回 id=5,但不返回 id=1,因为它不在第一个祖先中的元素为 id=4。

编辑: 基于 Dimitre 和 Alejandro 的 cmets,我发现 this 有用的博客条目解释了 count() 与 | union 运算符以及其他一些出色的技巧。

【问题讨论】:

  • 好问题,+1。请参阅我的答案以获得比当前接受的答案更简单的解决方案以及可以理解的解释。 :)

标签: xpath


【解决方案1】:

使用

//b[@value='noob']
      [count(ancestor::a[1] | //b[@id=2]/ancestor::a[1]) = 1]

解释

第二个谓词确保两个b 元素具有相同的最近祖先a

记住:在 XPath 1.0 中,节点身份的测试是:

count($n1 | $n2) = 1

【讨论】:

  • 简洁、清晰、实际回答了这个问题。非常感谢。
  • @Laramie:正如@Dimitre 已经知道的那样,集合身份由simetric 成员正式证明。在 XPath 中,这将是 count($A|$B)=count($B) and count($B|$A)=count($A) 或相同的 count($A|$B)=count($B) and count($B)=count($A)。只要您可以假设 A 和 B 是 singleton,那么您可以将其简化为提供的 count($A | $B) = 1
  • @Alejandro:我不知道对称联合可以应用于 XPath。现在我看到它是完全有道理的。感谢您的跟进。
【解决方案2】:

首先,这个

有没有办法限制结果 设置为只有 &lt;b&gt; 的元素 直接&lt;a&gt;的孩子们 起始节点的元素 (//b[@id=2])?

//b[@value='noob'][ancestor::a[1]/b/@id=2]

不一样:

从一个 id 相等的节点开始 到 2,找到所有的元素 值是“noob”,它们是后代 直接父 c 元素的 不经过另一个 c 元素

就是:

//c[b/@id=2]//*[.='noob'][ancestor::c[1][b/@id=2]]

除了这些表达式之外,当您处理“上下文标记”时,您可以使用集合的成员资格测试,如下所示:

$node[count(.|$node-set)=count($node-set)]

我把它在这个案例中的用途留给你作为练习......

【讨论】:

  • 你是对的,当我说“父 c 元素而不通过另一个 c 元素”时,我说错了。我打算说,“父元素而不通过另一个元素”作为没有标记的澄清。现实中的 XML 由高度非结构化格式的数百个节点类型组成。将其移植到这里一直是一个挑战。请参阅编辑。我欢迎详细说明“您可以使用该系列的成员资格测试...”。谢谢。
【解决方案3】:

//b[@id=2]/ancestor::a[1]//b[@value="noob" and not(ancestor::a[2]=//b[@id=2]/ancestor::a[1])] ? 但这仅适用于您的情况,但不确定它应该有多通用!

【讨论】:

  • 感谢您的回答,但上面的 XML 是对生产中遇到的内容的超级简化表示。该结构将基于人类语言,并且会非常多变。不幸的是,硬编码路径不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 2012-06-24
  • 2013-08-25
  • 1970-01-01
  • 1970-01-01
  • 2014-03-28
  • 1970-01-01
相关资源
最近更新 更多