【问题标题】:Removing duplicate XML node by keeping the first occurence using XSLT通过使用 XSLT 保留第一次出现来删除重复的 XML 节点
【发布时间】:2012-05-16 07:08:23
【问题描述】:

输入文件:

    <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,我们只保留第一次出现而忽略其他节点。 文件中还有另一个元素,即&lt;nodeB&gt;&lt;/nodeB&gt;&lt;nodeC&gt;&lt;/nodeC&gt;。等等 非常感谢。 约翰

【问题讨论】:

    标签: xml xslt


    【解决方案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>
    

    【讨论】:

    • 嗨.. 谢谢您的回复.. 但是为了被认为是重复的,它必须是相同的 id 和方法。您的解决方案只考虑&lt;item&gt;&lt;/item&gt;&lt;part&gt;&lt;/part&gt; 中的相同ID。您介意更新您的解决方案吗?谢谢。
    • xsl:key 确实包含父级sectioncell 的@id 属性,所以我相信它可以正常工作。也许您可以扩展您的 XML 示例以涵盖我的解决方案不起作用的情况,因为这可能会有所帮助。谢谢!
    • 我想说的是&lt;item&gt;&lt;/item&gt;&lt;cell&gt;&lt;/cell&gt; 中的@id 和@method。我扩展了示例以使其更清晰。非常感谢您的宝贵时间。
    • 我已经修改了 XSLT 以包含 @method 属性。
    • 谢谢.. 它工作得很好.. 但是它只适用于一个&lt;nodeA id="a"&gt;&lt;/nodeA&gt;only,正如我在问题中指出的那样,会有另一个 nodeB、nodeC 或相同的 nodeA 但具有不同的 id。只需指出要更改的内容,就可以了。非常感谢。
    猜你喜欢
    • 2021-11-12
    • 2018-06-18
    • 2016-09-10
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多