<root> <parent> <child> <name>John</name> </child> <child> <name>Ben</name> </child> </parent> <parent> <child> <name>John</name> </child> <child> <name>Mark</name> </child> <child> <name>Luke</name> </child> </parent> </root>
我只想要唯一的子节点,即只有一个子节点,如果有多个子节点具有相同的名称。
如:
John Ben Mark Luke
我试过了:
<xsl:for-each select="parent"> <xsl:for-each select="child[name != preceding::name]"> <xsl:value-of select="name"/> </xsl:for-each> </xsl:for-each>
但我明白了:
Ben Mark Luke
?!
答案 0 :(得分:7)
您的问题是您使用!=
运算符来比较值和节点集。
这是错误的 - 始终避免使用!=
运算符,并始终使用not()
函数和=
运算符时,其中一个操作数比较是一个节点集。
以下是正确的解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:for-each select="parent">
<xsl:for-each select="child[not(name = preceding::name)]">
<xsl:value-of select="concat(name, ' ')"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
将此转换应用于提供的XML文档:
<root>
<parent>
<child>
<name>John</name>
</child>
<child>
<name>Ben</name>
</child>
</parent>
<parent>
<child>
<name>John</name>
</child>
<child>
<name>Mark</name>
</child>
<child>
<name>Luke</name>
</child>
</parent>
</root>
产生了想要的正确结果:
John Ben Mark Luke
解释:以下是W3C XPath 1.0规范如何定义!=
运算符的语义:
“如果要比较的一个对象是a node-set和另一个是字符串, 那么比较将是真的,如果 并且只有在节点中有节点 node-set这样的结果 进行比较 节点的字符串值和另一个 字符串是真的。“
这意味着
's' != node-set
如果node-set
中只有一个节点不等于's'
,则始终为真。
这不是想要的语义。
另一方面,
not('s' = node-set())
仅当node-set
中的节点不等于's'
时,才为真。
这正是想要的比较。
请注意:您选择的分组技术是O(N ^ 2),并且只能用于要进行重复数据删除的非常小的值集。如果需要效率,一定要使用Muenchian方法进行分组(讨论或演示这不属于本问题的范围)。