XPath / XSLT:如何选择满足涉及另一组元素的条件的所有元素

时间:2011-09-13 18:09:38

标签: xml xslt xpath

我有一个类似于以下内容的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元素。我不知道到底能做到什么。

1 个答案:

答案 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>