【问题标题】:XPath/XSLT: how to select all elements that satisfy a condition involving another set of elementsXPath/XSLT:如何选择满足涉及另一组元素的条件的所有元素
【发布时间】:2011-09-13 18:09:37
【问题描述】:

我有一个类似于以下内容的 XML 文档:

<tt>
  <a text="1"/>
  <a text="2"/>
  ...
  <a text="n"/>

  <b text="14">data</b>
  <b text="2">data</b>
  ...
</tt>

如何选择所有&lt;b&gt; 元素的text 属性不等于任何&lt;a&gt; 元素的text 属性?我正在使用 XPath 1.0。

我正在考虑类似tt/b[not (tt/a[@text = xxx::@text])] 的东西,其中xxx 应该指代正在检查的tt/b 元素。我不知道具体是怎么做的。

【问题讨论】:

  • 对我来说重要的是not(tt/a[@text = xxx::@text])可以写成not(@text = tt/a/@text。但无论如何,感谢您指出这一点。

标签: xml xslt xpath


【解决方案1】:

/tt/b[@text != ../a/@text] 等答案是错误的,选择了错误的节点集

<b text="14">data</b>
<b text="2">data</b>

如我们所见,第二个选定节点的text 属性为2有一个a 元素,其text 属性为2

这是一个正确的 XPath 表达式

/tt/b[not(@text = ../a/@text)]

根据提供的 XML 文档进行评估时

<tt>
  <a text="1"/>
  <a text="2"/>
  ...
  <a text="n"/>

  <b text="14">data</b>
  <b text="2">data</b>
  ...
</tt>

它只正确选择了一个节点

<b text="14">data</b>

解释

根据定义 the XPath != operator 至少有一个参数是节点集时具有非常不直观的行为:

来自W3C XPath 1.0 Recommendation

"如果要比较的一个对象是一个节点集,另一个是一个数字, 那么当且仅当在 节点集,使得对 要比较的数字和转换字符串值的结果 使用 number 函数将该节点转换为数字为真。如果一个 要比较的对象是一个节点集,另一个是一个字符串,那么 当且仅当在 节点集,使得对 节点的字符串值和其他字符串为真"

在这个元素的特殊情况下:

<b text="2">data</b>

比较:

@text != ../a/@text

true(),即使存在:

<a text="2"/> 

因为至少存在一个../a元素(实际上不止一个),其text属性的字符串(或数字)值不等于"2"

这是众所周知的事实和常见问题解答:除非您完全知道自己在做什么,否则请始终避免使用 != 运算符!

这个问题的正确解决方法是像这样使用not()函数

not(@text = ../a/@text)

仅当 @text = ../a/@textfalse() 时,此表达式才计算为 true() —— 即仅当甚至没有一个 ../a/@text 的字符串值等于 text 属性的字符串值时上下文节点。

基于 XSLT 的验证

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

当此转换应用于提供的 XML 文档(上图)时,会产生正确的结果

<b text="14">data</b>

【讨论】:

  • 很遗憾,我无法删除已接受的答案。我看到了问题。 +1
  • @empo:谢谢。这样的事情有时会发生在 SO。重要且好的事情是,每个人都能从这些事件中学到很多东西。您的回答不再被接受——请决定如何处理它。
  • @empo:好的,我更新了我的答案,更不用说不再存在的错误答案了。
猜你喜欢
  • 1970-01-01
  • 2012-01-07
  • 2015-07-09
  • 1970-01-01
  • 1970-01-01
  • 2021-06-07
  • 1970-01-01
  • 2017-06-20
  • 2021-01-03
相关资源
最近更新 更多