选择具有共同属性的所有节点的XPath表达式

11

我正在阅读的一本关于XML的书中提到,要选取XML文件中所有具有特定属性的节点,请使用以下语法:

//*/@_attribute_

我不明白为什么需要星号。据我理解,表达式 // 选择根节点的所有后代。那么,//@lang 是否会选择根节点的所有具有名为“lang”的属性的后代?我甚至不能解释上述表达式中星号的含义(我知道星号通常表示“所有”)。如果有人能为我分析一下,我将非常感激。

谢谢


好问题,+1。请看我的回答,对@Alejandro的说法进行了一点纠正,即您的XPath表达式是“错误”的。@Alejandro的回答很好,但这个XPath表达式没有任何问题。 - Dimitre Novatchev
2个回答

17
嗨,我正在阅读一本关于XML的书,它说要选择XML文件中具有特定属性的所有节点,请使用以下语法://*/@attribute
但是这是错误的。它将被扩展为:
/descendant-or-self::node()/child::*/attribute::attribute

意义:

所有节点的子元素中,无论是根文档本身还是其后代之一,都具有属性属性。

您需要:

/descendant::*[attribute::attribute]

或者缩写形式

//*[@attribute]

关于*:正式上是一个名称测试而不是节点类型测试。在XPath 1.0中,没有元素类型测试。在XPath 2.0中,您有element()。那么,为什么只选择元素?好吧,它并不是。轴具有主要节点类型,来自http://www.w3.org/TR/xpath/#node-tests

每个轴都有一个主要节点类型。 如果轴可以包含元素,则 主要节点类型是元素; 否则,它是轴可以包含的节点的类型。因此,

  • 对于属性轴,主要节点类型是属性。
  • 对于命名空间轴,主要节点类型是命名空间。
  • 对于其他轴,主要节点类型是元素。

这就是为什么*child::*self::*descendant::*等选择元素,但@*attribute::*namespace::*选择属性或在范围内的命名空间。

关于谓词([@attribute]部分):该表达式对上一步选择的每个节点进行评估。它期望一个布尔值进行过滤。节点集的布尔值(这是attribute::attribute的结果)对于空节点集为false,否则为true。


@Alejandro。//*/@x 没有任何问题,只是它比它应该的长度长了一些。 - Dimitre Novatchev

15

这个问题的标题是:

用XPath表达式选择所有具有共同属性的节点

然而,问题的正文中没有讨论如何找到所有具有共同属性的节点--因此标题可能不正确。

要查找所有具有名为x的共同属性的节点(顺便提一下,只有元素节点才能具有属性),请使用

//*[@x]

使用:

//@x

选择 XML 文档中所有名为 x 的属性。这可能是最短的表达式。

以下写法没有问题:

//*/@x

除了稍微更长外,它与之相同。

它是以下内容的速记:

/descendant-or-self::node()/child::*/attribute::x

它还选择了XML文档中所有x属性。

有人可能认为这个表达式没有选择文档中顶层元素的x属性。这是错误的结论,因为第一个定位步骤:

/descendant-or-self::node()

选择文档中的每个节点,包括根节点 (/) 本身。

这意味着:

/descendant-or-self::node()/child::*

选择每个元素,包括在格式良好的XML文档中根节点的唯一子节点。

因此,当最后一个位置步骤 /@x 被添加时,这将选择到目前为止由前两个位置步骤选定的所有节点的所有 x 属性 -- 即XML文档中所有元素节点的所有 x 属性。


2
+1 感谢你的澄清。我总是喜欢阅读你的答案。 - Garett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接