Java 如何使用xslt删除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如下所示:

   <?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