通过使用XSLT保持第一次出现来删除重复的XML节点

时间:2012-05-16 07:08:23

标签: xml xslt

输入文件:

    <myroot>
        <nodeA id="a">
            <section id="i">  
                <item id="0" method="a"> <!-- parent section id="i" , keep this node-->
                    <somechild>a</somechild>
                </item>

                <item id="1" method="a">
                    <otherchild>a</otherchild>
                </item>
            </section>        

            <cell id="i">
                <part id="1" method="b"> <!-- parent cell id="i", keep this node-->
                    <attr>u</attr>
                </part>
            </cell>

            <section id="i">
                <item id="0" method="a"> <!-- parent section id="i", remove this node-->
                    <type>blah</type>
                </item>
                <item id="3" method="a">
                   <other>xx</other>    
                </item>

                <item id="0" method="b"> <!-- this has same id but different method, so we keep this -->
                    <otherchild>a</otherchild>
                </item>
            </section>

            <cell id="i">
                <part id="1" method="b"> <!-- parent cell id="i", remove this node -->
                    <attr>y</attr>
                </part>
            </cell>
        </nodeA>

        <nodeA id="b">
            <section id="i">
                <item id="1" method="a">
                    <otherchild>a</otherchild>
                </item>
            </section>        

            <section id="i">
                <item id="0" method="a">
                    <type>blah</type>
                </item>
                <item id="1" method="a">
                   <other>xx</other>    
                </item>
            </section>
           </nodeA>

        <nodeB id="a">
            <cell id="i">
                <part id="1" method="b">
                    <attr>u</attr>
                </part>
            </cell>

            <section id="i">
                <item id="0" method="a">
                    <type>blah</type>
                </item>                    
            </section>

            <cell id="i">
                <part id="1" method="b">
                    <attr>y</attr>
                </part>
            </cell>
        </nodeB>
</myroot>

输出:

<myroot>
        <nodeA id="a">
            <section id="i">
                <item id="0" method="a">
                    <somechild>a</somechild>
                </item>

                <item id="1" method="a">
                    <otherchild>a</otherchild>
                </item>
            </section>

            <cell id="i">
                <part id="1" method="b">
                    <attr>u</attr>
                </part>
            </cell>

            <section id="i">
                <item id="3" method="a">
                   <other>xx</other>    
                </item>

              <item id="0" method="b"> <!-- this has same id but different method, so we keep this -->
                    <otherchild>a</otherchild>
                </item>
                </section>
        </nodeA>

        <nodeA id="b">
            <section id="i">
                <item id="1" method="a">
                    <otherchild>a</otherchild>
                </item>
            </section>        

            <section id="i">
                <item id="0" method="a">
                    <type>blah</type>
                </item>
            </section>
           </nodeA>

        <nodeB id="a">
            <cell id="i">
                <part id="1" method="b">
                    <attr>u</attr>
                </part>
            </cell>

            <section id="i">
                <item id="0" method="a">
                    <type>blah</type>
                </item>                    
            </section>
        </nodeB>

</myroot>

任何人都可以帮助我进行转换,这样如果一个节点出现两次或更多次且具有相同的父ID,我们只保留第一次出现并忽略其他节点。 此外,文件中还有另一个元素<nodeB></nodeB><nodeC></nodeC>。等等 非常感谢。 约翰

1 个答案:

答案 0 :(得分:1)

我认为您需要定义一个键来“复制”重复项。它们似乎根据节点名称,@ id和@method属性以及父节点和@id进行分组。因此,您可以像这样定义键:

<xsl:key 
   name="duplicates" 
   match="*" 
    use="concat(local-name(), '|', @id, '|', @method, '|', local-name(..), '|', ../@id, '|', local-name(../..), '|', ../../@id)"/> 

然后,您需要忽略键中不是第一个的元素。我认为你还需要一个子句来匹配作为'子'元素的元素(否则将忽略哪些节元素)

<xsl:template 
   match="*
      [@id!='']
      [not(.//*[@id!=''])]
      [generate-id() != generate-id(key('duplicates', concat(local-name(), '|', @id, '|', @method, '|', local-name(..), '|', ../@id, '|', local-name(../..), '|', ../../@id))[1])]/>

为了增加复杂性,看起来你不想输出所有子元素都是重复的元素。

<xsl:template 
   match="*
     [@id!='']
     [.//*[@id!='']]
     [not(.//*
        [not(.//*[@id!=''])]
        [generate-id() = generate-id(key('duplicates', concat(local-name(), '|', @id, '|', @method, '|', local-name(..), '|', ../@id, '|', local-name(../..), '|', ../../@id))[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="duplicates" match="*" use="concat(local-name(), '|', @id, '|', @method, '|', local-name(..), '|', ../@id, '|', local-name(../..), '|', ../../@id)"/> 
   <xsl:template match="@*|node()"> 
      <xsl:copy> 
         <xsl:apply-templates select="@*|node()"/> 
      </xsl:copy> 
   </xsl:template> 
   <xsl:template match="*[@id!=''][not(.//*[@id!=''])][generate-id() != generate-id(key('duplicates', concat(local-name(), '|', @id, '|', @method, '|', local-name(..), '|', ../@id, '|', local-name(../..), '|', ../../@id))[1])]"/> 
   <xsl:template match="*[@id!=''][.//*[@id!='']][not(.//*[not(.//*[@id!=''])][generate-id() = generate-id(key('duplicates', concat(local-name(), '|', @id, '|', @method, '|', local-name(..), '|', ../@id, '|', local-name(../..), '|', ../../@id))[1])])]"/> 
</xsl:stylesheet> 

当应用于您的示例XML时,输出以下内容:

<myroot>
   <nodeA id="a">
      <section id="i">
         <item id="0" method="a"><!-- parent section id="i" , keep this node-->
            <somechild>a</somechild>
         </item>
         <item id="1" method="a">
            <otherchild>a</otherchild>
         </item>
      </section>
      <cell id="i">
         <part id="1" method="b"><!-- parent cell id="i", keep this node-->
            <attr>u</attr>
         </part>
      </cell>
      <section id="i">
         <item id="3" method="a">
            <other>xx</other>
         </item>
         <item id="0" method="b"><!-- this has same id but different method, so we keep this -->
            <otherchild>a</otherchild>
         </item>
      </section>
   </nodeA>
   <nodeA id="b">
      <section id="i">
         <item id="1" method="a">
            <otherchild>a</otherchild>
         </item>
      </section>
      <section id="i">
         <item id="0" method="a">
            <type>blah</type>
         </item>
      </section>
   </nodeA>
   <nodeB id="a">
      <cell id="i">
         <part id="1" method="b">
            <attr>u</attr>
         </part>
      </cell>
      <section id="i">
         <item id="0" method="a">
            <type>blah</type>
         </item>
      </section>
   </nodeB>
</myroot>