XSLT2.0删除节点中的重复值

时间:2016-01-20 13:49:12

标签: xml xslt duplicates

我一直试图弄清楚如何使用XSLT从XML文档中删除具有重复值的元素。

例如: 输入:

<main>
   <h1>
      <node1>duplicate</node1>
      <node1>duplicate</node1>
      <node1>New data</node1>
      <node1>New data 2</node1>
      <node1>duplicate</node1>
   </h1>
</main>

预期产出:

<main>
   <h1>
      <node1>duplicate</node1>
      <node1>New data</node1>
      <node1>New data 2</node1>
   </h1>
</main>

我确定这一定不能太复杂,但我无法理解到目前为止我所看到的任何方法。 谢谢!

感谢迈克尔以下!如果以上示例有更多节点(永远不会重复),我还有一个问题,例如

 <main>
   <h1>
      <node1>duplicate</node1>
      <node1>duplicate</node1>
      <node1>New data</node1>
      <node1>New data 2</node1>
      <node1>duplicate</node1>
      <node2> Data </node2>

   </h1>
</main>

如何在XSLT代码中引入此数据?以下解决方案删除了​​我发现的任何其他数据,尽管我理解了要复制所有的身份转换,以及仅修改匹配模板的匹配。

2 个答案:

答案 0 :(得分:3)

请注意当前接受的答案不正确

即使是没有丢失元素的第3个解决方案也是不正确的,因为它不会保留元素的顺序。

鉴于此XML文档

Content-type

接受答案中的最后一次(第三次)转换

Req

会产生 <main> <h1> <node1>duplicate</node1> <node2> Data </node2> <node1>duplicate</node1> <node1>New data</node1> <node1>New data 2</node1> <node1>duplicate</node1> </h1> </main> 所有<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <!-- identity transform --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="h1"> <xsl:copy> <xsl:for-each-group select="node1" group-by="."> <node1> <xsl:value-of select="."/> </node1> </xsl:for-each-group> <xsl:apply-templates select="* except node1"/> </xsl:copy> </xsl:template> </xsl:stylesheet> 元素之后的结果 - 显然不是人们对丢失重复的“身份”所期望的结果:

<node2>

现在是一个正确且非常简短的解决方案:)

<node1>

这会产生预期的正确结果 - 即使应用于上述XML文档 - 请注意保留<?xml version="1.0" encoding="UTF-8"?> <main> <h1> <node1>duplicate</node1> <node1>New data</node1> <node1>New data 2</node1> <node2> Data </node2> </h1> </main> <xsl:stylesheet version="2.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="kNode1ByVal" match="h1/node1" use="."/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="h1/node1[not(. is key('kNode1ByVal',.)[1])]"/> </xsl:stylesheet> 元素的顺序!:

<node1>

答案 1 :(得分:2)

这是一种方式:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="h1">
    <xsl:copy>
        <xsl:for-each-group select="node1" group-by=".">
            <node1>
                <xsl:value-of select="."/>
            </node1>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

这是另一个:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="h1">
    <xsl:copy>
        <xsl:for-each select="distinct-values(node1)">
            <node1>
                <xsl:value-of select="."/>
            </node1>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

加了:

要处理h1标题下的其他节点,请添加以下指令:

<xsl:apply-templates select="* except node1"/>

例如(在第一种情况下):

<xsl:template match="h1">
    <xsl:copy>
        <xsl:for-each-group select="node1" group-by=".">
            <node1>
                <xsl:value-of select="."/>
            </node1>
        </xsl:for-each-group>
        <xsl:apply-templates select="* except node1"/>
    </xsl:copy>
</xsl:template>