我一直试图弄清楚如何使用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代码中引入此数据?以下解决方案删除了我发现的任何其他数据,尽管我理解了要复制所有的身份转换,以及仅修改匹配模板的匹配。
答案 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>