0

示例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>

如何删除重复项?

<name>以及<id>具有匹配值的标签...此外,如果还有除<Samsung>and以外的更多标签<htc>,如何在 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>
4

3 回答 3

2

如果您可以确保重复节点始终是连续的,那么最简单的方法是在 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>

但是,如果您的 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 个元素必须检查 99 个前面的元素,第 101 个元素检查 100 个元素等)。

一种更有效的方法(在 XSLT1.0 中)是使用一种称为Muenchian Grouping的技术。如果您经常使用 XSLT,这当然是值得学习的。

首先,您定义一个键来“分组”您的元素。在这种情况下,您正在寻找由其父级、元素名称和值定义的不同元素

<xsl:key name="duplicate" match="*[not(*)]" use="concat(generate-id(..), '|', name(), '|', @value)" />

然后忽略重复项,匹配给定“查找”值的键中第一个位置未出现的任何元素

<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: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>
于 2013-04-19T13:04:19.543 回答
1

当这种转变

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

获得所需的输出

<?xml version='1.0' ?>
<check> 
  <val>    
    <sai>     
      <name> A</name>       
      <name2> B</name2>
    </sai>
    <dinesh>
      <name> A</name>
      <name2> B</name2>
    </dinesh>   
   </val> 
</check>
于 2013-04-19T11:13:25.713 回答
0

与@siva2012 的回答几乎相同。但如果只有一个名字的孩子更正确。

<?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>
于 2013-04-19T11:35:02.737 回答