Java 如何使用xslt删除xml文件中的重复项?
示例xml如下所示:Java 如何使用xslt删除xml文件中的重复项?,java,xml,xslt,xml-parsing,xslt-1.0,Java,Xml,Xslt,Xml Parsing,Xslt 1.0,示例xml如下所示: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <check> <val> <Samsung> <name value="galaxy"/> <name value="galaxy"/> <name va
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<check>
<val>
<Samsung>
<name value="galaxy"/>
<name value="galaxy"/>
<name value="galaxys"/>
<id value="123"/>
<id value="123"/>
<name2 value="galaxy"/>
</Samsung>
<htc>
<name value="galaxy"/>
<name value="galaxy"/>
<name value="galaxys"/>
<id value="123"/>
<id value="123"/>
<name2 value="galaxy"/>
</htc>
</val>
</check>
如何删除重复项
和
标记也具有匹配的值。。。另外,如果除了
和
之外还有更多的标记,那么如何在xslt中编写循环?我不知道如何编写xslt。请帮忙
输出xml应该如下所示:
<check>
<val>
<Samsung>
<name value="galaxy"/>
<name value="galaxys"/>
<id value="123"/>
<name2 value="galaxy"/>
</Samsung>
<htc>
<name value="galaxy"/>
<name value="galaxys"/>
<id value="123"/>
<name2 value="galaxy"/>
</htc>
</val>
</check>
当此转换
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="name">
<xsl:if test="self::name/text()= following-sibling::name/text()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="name2">
<xsl:if test="self::name2/text()= following-sibling::name2/text()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
在下面的XML上运行
<?xml version="1.0"?>
<check>
<val>
<sai>
<name> A</name>
<name> A</name>
<name2> B</name2>
<name2> B</name2>
</sai>
<dinesh>
<name> A</name>
<name> A</name>
<name2> B</name2>
<name2> B</name2>
</dinesh>
</val>
</check>
A.
A.
B
B
A.
A.
B
B
获取所需的输出
<?xml version='1.0' ?>
<check>
<val>
<sai>
<name> A</name>
<name2> B</name2>
</sai>
<dinesh>
<name> A</name>
<name2> B</name2>
</dinesh>
</val>
</check>
A.
B
A.
B
当此转换
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="name">
<xsl:if test="self::name/text()= following-sibling::name/text()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="name2">
<xsl:if test="self::name2/text()= following-sibling::name2/text()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
在下面的XML上运行
<?xml version="1.0"?>
<check>
<val>
<sai>
<name> A</name>
<name> A</name>
<name2> B</name2>
<name2> B</name2>
</sai>
<dinesh>
<name> A</name>
<name> A</name>
<name2> B</name2>
<name2> B</name2>
</dinesh>
</val>
</check>
A.
A.
B
B
A.
A.
B
B
获取所需的输出
<?xml version='1.0' ?>
<check>
<val>
<sai>
<name> A</name>
<name2> B</name2>
</sai>
<dinesh>
<name> A</name>
<name2> B</name2>
</dinesh>
</val>
</check>
A.
B
A.
B
与@siva2012的回答几乎相同。但如果只有一个名字child,则更正确
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" />
<xsl:template match="name">
<xsl:variable name="text" select="text()"/>
<xsl:if test="not(following-sibling::name[text()= $text])" >
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
与@siva2012的回答几乎相同。但如果只有一个名字child,则更正确
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" />
<xsl:template match="name">
<xsl:variable name="text" select="text()"/>
<xsl:if test="not(following-sibling::name[text()= $text])" >
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
如果您可以确保重复的节点始终是连续的,那么最简单的方法就是在XSTL标识转换的基础上构建一个额外的模板,这样就可以去掉模板
<xsl:template
match="*[not(*)]
[name() = preceding-sibling::*[1]/name()]
[@value = preceding-sibling::*[1]/@value]" />
这会匹配任何子元素,如果它与上一个元素具有相同的名称和值,则会忽略它。在这种情况下,不需要在任何地方硬编码元素名称
下面是本例中的完整XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*)][name() = preceding-sibling::*[1]/name()][@value = preceding-sibling::*[1]/@value]" />
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="duplicate" match="*[not(*)]" use="concat(generate-id(..), '|', name(), '|', @value)" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*)][generate-id() != generate-id(key('duplicate', concat(generate-id(..), '|', name(), '|', @value))[1])]" />
</xsl:stylesheet>
然而,如果您的XML看起来像这样,并且重复的节点是连续的,那么这将失败
<Samsung>
<name value="galaxy"/>
<name value="galaxys"/>
<id value="123"/>
<name value="galaxy"/>
<id value="123"/>
<name2 value="galaxy"/>
</Samsung>
您可以通过更改模板以检查所有以前的节点来修复此问题
<xsl:template match="*[not(*)]
[name() = preceding-sibling::*/name()]
[@value = preceding-sibling::*/@value]" />
然而,由于大量的元素,这开始变得低效。如果您有100个元素,那么每个前序同级检查将重复涉及检查100个元素(即第100个元素必须检查99个前序元素,第101个元素检查100个前序元素,以此类推)
一种更有效的方法(在XSLT1.0中)是使用一种称为的技术。如果您经常使用XSLT,这当然是值得学习的
首先定义一个键来“分组”元素。在本例中,您正在查找由其父元素、元素名称和值定义的不同元素
<xsl:key name="duplicate" match="*[not(*)]" use="concat(generate-id(..), '|', name(), '|', @value)" />
然后,为了忽略重复项,您需要为给定的“lookup”值匹配键中第一个位置未出现的任何元素
<xsl:template match="*[not(*)]
[generate-id() !=
generate-id(key('duplicate', concat(generate-id(..), '|', name(), '|', @value))[1])]" />
下面是本例中的完整XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*)][name() = preceding-sibling::*[1]/name()][@value = preceding-sibling::*[1]/@value]" />
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="duplicate" match="*[not(*)]" use="concat(generate-id(..), '|', name(), '|', @value)" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*)][generate-id() != generate-id(key('duplicate', concat(generate-id(..), '|', name(), '|', @value))[1])]" />
</xsl:stylesheet>
如果您可以确保重复的节点始终是连续的,那么最简单的方法就是在XSTL标识转换的基础上构建一个额外的模板,这样就可以去掉模板
<xsl:template
match="*[not(*)]
[name() = preceding-sibling::*[1]/name()]
[@value = preceding-sibling::*[1]/@value]" />
这会匹配任何子元素,如果它与上一个元素具有相同的名称和值,则会忽略它。在这种情况下,不需要在任何地方硬编码元素名称
下面是本例中的完整XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*)][name() = preceding-sibling::*[1]/name()][@value = preceding-sibling::*[1]/@value]" />
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="duplicate" match="*[not(*)]" use="concat(generate-id(..), '|', name(), '|', @value)" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*)][generate-id() != generate-id(key('duplicate', concat(generate-id(..), '|', name(), '|', @value))[1])]" />
</xsl:stylesheet>
然而,如果您的XML看起来像这样,并且重复的节点是连续的,那么这将失败
<Samsung>
<name value="galaxy"/>
<name value="galaxys"/>
<id value="123"/>
<name value="galaxy"/>
<id value="123"/>
<name2 value="galaxy"/>
</Samsung>
您可以通过更改模板以检查所有以前的节点来修复此问题
<xsl:template match="*[not(*)]
[name() = preceding-sibling::*/name()]
[@value = preceding-sibling::*/@value]" />
然而,由于大量的元素,这开始变得低效。如果您有100个元素,那么每个前序同级检查将重复涉及检查100个元素(即第100个元素必须检查99个前序元素,第101个元素检查100个前序元素,以此类推)
一种更有效的方法(在XSLT1.0中)是使用一种称为的技术。如果您经常使用XSLT,这当然是值得学习的
首先定义一个键来“分组”元素。在本例中,您正在查找由其父元素、元素名称和值定义的不同元素
<xsl:key name="duplicate" match="*[not(*)]" use="concat(generate-id(..), '|', name(), '|', @value)" />
然后,为了忽略重复项,您需要为给定的“lookup”值匹配键中第一个位置未出现的任何元素
<xsl:template match="*[not(*)]
[generate-id() !=
generate-id(key('duplicate', concat(generate-id(..), '|', name(), '|', @value))[1])]" />
下面是本例中的完整XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*)][name() = preceding-sibling::*[1]/name()][@value = preceding-sibling::*[1]/@value]" />
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="duplicate" match="*[not(*)]" use="concat(generate-id(..), '|', name(), '|', @value)" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*)][generate-id() != generate-id(key('duplicate', concat(generate-id(..), '|', name(), '|', @value))[1])]" />
</xsl:stylesheet>
所有xml的开头都不正确。请修正你的例子。也许一点搜索就会给你提示如何开始。所有xml中的第一个甚至都不正确。请修正你的例子。也许稍微搜索一下就会提示您如何开始。循环match=“check/val/*/nam*”是否有效,因为我也在其他节点上运行过它?我在哪里可以找到您编写的语法定义..因为我发现在不理解语法的情况下很难尝试。请尝试此
这是我尝试的xml。。银河123银河123银河ONex ONex 564 564