我有一个类似于以下内容的XML文档:
<tt>
<a text="1"/>
<a text="2"/>
...
<a text="n"/>
<b text="14">data</b>
<b text="2">data</b>
...
</tt>
如何选择<b>
属性不等于任何text
元素的text
属性的所有<a>
元素?我正在使用XPath 1.0。
我在想tt/b[not (tt/a[@text = xxx::@text])]
之类的内容,其中xxx
应该引用正在检查的tt/b
元素。我不知道到底能做到什么。
答案 0 :(得分:6)
/tt/b[@text != ../a/@text]
等答案错误,并选择了错误的节点集:
<b text="14">data</b>
<b text="2">data</b>
如我们所见,第二个选定节点的text
属性为2
,而 是a
元素,其text
属性为{{ 1}}。
这是一个正确的XPath表达式:
2
根据提供的XML文档进行评估:
/tt/b[not(@text = ../a/@text)]
它只能正确选择一个节点:
<tt>
<a text="1"/>
<a text="2"/>
...
<a text="n"/>
<b text="14">data</b>
<b text="2">data</b>
...
</tt>
<强>解释强>:
根据定义, the XPath !=
operator 在其至少一个参数是节点集时会有非常不直观的行为:
来自W3C XPath 1.0 Recommendation :
“如果要比较的一个对象是节点集而另一个是数字, 那么当且仅当有一个节点时,比较才会成立 node-set使得执行比较的结果 要比较的数字和转换字符串值的结果 该节点使用数字函数的数字是真的。如果一个 要比较的对象是节点集,另一个是字符串 当且仅当有一个节点时,比较才是真的 node-set使得执行比较的结果 节点的字符串值和另一个字符串为真“
在元素的这种特殊情况下:
<b text="14">data</b>
比较:
<b text="2">data</b>
即使存在:,仍为@text != ../a/@text
true()
因为至少存在一个<a text="2"/>
元素(实际上多于一个),其../a
属性不等于text
的字符串(或数字)值。< / p>
这是一个众所周知的事实和常见问题解答:除非您完全知道自己在做什么,否则请务必避免使用"2"
运算符!
此问题的正确解决方法是使用!=
这样的功能:
not()
仅当not(@text = ../a/@text)
为true()
时,此表达式才会计算为@text = ../a/@text
- 仅当没有单个false()
时,其字符串值等于上下文节点的../a/@text
属性的字符串值。
基于XSLT的验证:
text
在提供的XML文档(上面)上应用此转换时,会生成正确的结果:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="/tt/b[not(@text = ../a/@text)]"/>
</xsl:template>
</xsl:stylesheet>