当您可以按特定属性或值对这些元素进行分组时,有many questions关于如何删除重复元素的情况,但是,在我的情况下,属性是在XSLT中动态生成的,我不想要必须为每个元素编写每个元素的程序,以用作分组键。
如何在不事先了解其属性的情况下删除重复元素?到目前为止,我已经尝试在每个元素上使用generate-id()
并按其分组,但问题是generate-id
没有为具有相同属性的元素生成相同的ID:
<xsl:template match="root">
<xsl:variable name="tempIds">
<xsl:for-each select="./*>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="tempID">
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
<xsl:copy-of select="node()"/>
</xsl:copy>
</xsl:for-each>
</xsl:variable>
<xsl:for-each-group select="$tempIds" group-by="@tempID">
<xsl:sequence select="."/>
</xsl:for-each-group>
</xsl:template>
测试数据:
<root>
<child1>
<etc/>
</child1>
<dynamicElement1 a="2" b="3"/>
<dynamicElement2 c="3" d="4"/>
<dynamicElement2 c="3" d="5"/>
<dynamicElement1 a="2" b="3"/>
</root>
最终结果只剩下两个dynamicElement1
元素中的一个:
<root>
<child1>
<etc/>
</child1>
<dynamicElement1 a="2" b="3"/>
<dynamicElement2 c="3" d="4"/>
<dynamicElement2 c="3" d="5"/>
</root>
答案 0 :(得分:3)
在https://xsltfiddle.liberty-development.net/pPqsHTi中所示的XSLT 3中,您可以使用所有属性的复合键,例如。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" composite="yes" group-by="@*">
<xsl:sequence select="."/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
请注意,技术上的属性不是有序的,所以通过node-name()或类似的某种属性进行分组可能更安全,就像在https://xsltfiddle.liberty-development.net/pPqsHTi/2中没有高阶函数的XSLT 3所做的那样
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mf="http://example.com/mf"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:function name="mf:node-sort" as="node()*">
<xsl:param name="input-nodes" as="node()*"/>
<xsl:perform-sort select="$input-nodes">
<xsl:sort select="namespace-uri()"/>
<xsl:sort select="local-name()"/>
</xsl:perform-sort>
</xsl:function>
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" composite="yes" group-by="mf:node-sort(@*)">
<xsl:sequence select="."/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
或者只需使用
就可以使用Saxon EE<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" composite="yes" group-by="sort(@*, (), function($att) { namespace-uri($att), local-name($att) })">
<xsl:sequence select="."/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
答案 1 :(得分:0)
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/*[@a= following-sibling::*/@a]|root/*[@c= following-sibling::*/@c and @d= following-sibling::*/@d]"/>
You may try this