我有以下架构:
<parent>
<child id="1" name="Child 1 Version 1" />
</parent>
<parent>
<child id="2" name="Child 2 Version 1" />
</parent>
<parent>
<child id="1" name="Child 1 Version 2" />
</parent>
我想只处理每个id的最后一个节点。以下是我根据一些阅读尝试的内容:
<xsl:for-each select="//parent/child">
<xsl:sort select="@id"/>
<xsl:if test="not(@id=following-sibling::*/@id)">
<xsl:element name="child">
<xsl:value-of select="@name"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
但它似乎不起作用。我的输出仍然包含所有三个元素。关于我如何纠正我的问题的任何想法?
答案 0 :(得分:2)
我想只处理最后一次 每个id的节点。以下是我所拥有的 尝试基于一些阅读:
<xsl:for-each select="//parent/child">
<xsl:sort select="@id"/>
<xsl:if test="not(@id=following-sibling::*/@id)">
<xsl:element name="child">
<xsl:value-of select="@name"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
但它似乎不起作用。我的 输出仍然包含所有三个 元素。关于我能做什么的任何想法 纠正我的问题?
此代码的问题是,即使节点位于已排序的节点集中,它们的following-sibling
仍然是文档中的那些。
为了使这个代码能够工作,首先要创建一个全新的文档,其中节点按照所需的方式排序,然后(在XSLT 1.0中,必须使用生成的xxx:node-set()
扩展名RTF使其成为普通的XML文档)在这个文档中,节点可以根据需要拥有兄弟姐妹。
<强>解决方案强>:
此转换提供了一种可能不需要使用扩展函数的XSLT 1.0解决方案:
<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:key name="kchildById" match="child" use="@id"/>
<xsl:template match="/*">
<t>
<xsl:apply-templates select=
"*/child[generate-id()
=
generate-id(key('kchildById',
@id)[last()]
)
]
"/>
</t>
</xsl:template>
<xsl:template match="child">
<child>
<xsl:value-of select="@name"/>
</child>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML片段(包装在顶部元素中以成为格式良好的XML文档并为id="2"
添加第二个版本):
<t>
<parent>
<child id="1" name="Child 1 Version 1" />
</parent>
<parent>
<child id="2" name="Child 2 Version 1" />
</parent>
<parent>
<child id="1" name="Child 1 Version 2" />
</parent>
<parent>
<child id="2" name="Child 2 Version 2" />
</parent>
</t>
产生想要的结果:
<t>
<child>Child 1 Version 2</child>
<child>Child 2 Version 2</child>
</t>
请注意:使用Muenchian方法进行分组。
答案 1 :(得分:1)
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kParentByChildId" match="parent" use="child/@id"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="parent[count(.|key('kParentByChildId',
child/@id)[last()]) != 1]"/>
</xsl:stylesheet>
输出:
<root>
<parent>
<child id="2" name="Child 2 Version 1"></child>
</parent>
<parent>
<child id="1" name="Child 1 Version 2"></child>
</parent>
</root>
注意即可。按@id分组,选择最后一个组。
修改:以防万一令人困惑。上面的样式表意味着:复制那些child
没有同类<{em>}的@id
的所有内容。因此,它不是选择组中的最后一个,而是作为反向逻辑,条带化不是组中的最后一个。
二。为什么你的不工作?好吧,因为following-sibling
轴。您找到第一种方法的方法是从处理器实现密钥很少的旧时代开始。那些日子已经过去了。
所以,这个样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="t">
<xsl:for-each select="parent/child">
<xsl:sort select="@id"/>
<xsl:if test="not(@id=following::child/@id)">
<xsl:element name="child">
<xsl:value-of select="@name"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
输出:
<child>Child 1 Version 2</child>
<child>Child 2 Version 1</child>
注意:following
轴,因为child
元素没有兄弟姐妹。