jjzjj

xml - XPath/XSLT : how to select all elements that satisfy a condition involving another set of elements

coder 2024-07-04 原文

我有一个类似于以下内容的 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正在检查的元素。我不知 Prop 体怎么做。

最佳答案

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

"If one object to be compared is a node-set and the other is a number, then the comparison will be true if and only if there is a node in the node-set such that the result of performing the comparison on the number to be compared and on the result of converting the string-value of that node to a number using the number function is true. If one object to be compared is a node-set and the other is a string, then the comparison will be true if and only if there is a node in the node-set such that the result of performing the comparison on the string-value of the node and the other string is true"

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

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

关于xml - XPath/XSLT : how to select all elements that satisfy a condition involving another set of elements,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7406444/

有关xml - XPath/XSLT : how to select all elements that satisfy a condition involving another set of elements的更多相关文章

随机推荐