【问题标题】:Remove duplicate node based on more than one attribute in xml using xslt使用 xslt 删除基于 xml 中多个属性的重复节点
【发布时间】:2012-04-22 07:22:48
【问题描述】:

我有这个需要用 xslt 转换的输入 XML

<root>
    <node id="a">
        <section id="a_1" method="run">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
        <section id="a_2">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
        <section id="a_1" method="run">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
    </node>
    <node id="b">
        <section id="b_1" method="create">
            <user id="b_1a">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
            <user id="b_1b">
                <attribute>a</attribute>
            </user>
        </section>
        <section id="b_1" method="create">
            <user id="b_1c">
                <attribute>a</attribute>
            </user>
        </section>
        <section id="b_2">
            <user id="b_1a">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
        </section>
    </node>
</root>

预期输出:

<root>
    <node id="a">
        <section id="a_1">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
        <section id="a_2">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
    </node>
    <node id="b">
        <section id="b_1" method="create">
            <user id="b_1a">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
            <user id="b_1b">
                <attribute>a</attribute>
            </user>
        </section>

        <section id="b_2">
            <user id="b_1a">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
        </section>
    </node>
</root>

淘汰哪个节点无所谓,只要元素名、id、方法相同,其中一个就会被淘汰。 知道 xsl 是什么样子的吗?

注意:元素名称可以是任何东西,不必是任何东西,并且在整个文件中有多个元素名称;只要它具有相同的元素名称、id 和属性(例如 method=create),其中之一就会被淘汰。

非常感谢。 干杯, 约翰

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    我。这是一个简短而高效(使用键)的 XSLT 1.0 转换:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:key name="kElemWithAttribs" match="*[@id and @method]"
      use="concat(name(), '+', @id, '+', @method)"/>
    
     <xsl:template match="node()|@*">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>
    
     <xsl:template match=
      "*[@id and @method
        and
         not(generate-id()
            =
             generate-id(key('kElemWithAttribs',
                             concat(name(), '+', @id, '+', @method)
                             )[1]
                        )
             )
         ]"/>
    </xsl:stylesheet>
    

    当此转换应用于提供的 XML 文档时:

    <root>
        <node id="a">
            <section id="a_1" method="run">
                <item id="0">
                    <attribute>
                        <color>Red</color>
                    </attribute>
                </item>
            </section>
            <section id="a_2">
                <item id="0">
                    <attribute>
                        <color>Red</color>
                    </attribute>
                </item>
            </section>
            <section id="a_1" method="run">
                <item id="0">
                    <attribute>
                        <color>Red</color>
                    </attribute>
                </item>
            </section>
        </node>
        <node id="b">
            <section id="b_1" method="create">
                <user id="b_1a">
                    <attribute>
                        <name>John</name>
                    </attribute>
                </user>
                <user id="b_1b">
                    <attribute>a</attribute>
                </user>
            </section>
            <section id="b_1" method="create">
                <user id="b_1c">
                    <attribute>a</attribute>
                </user>
            </section>
            <section id="b_2">
                <user id="b_1a">
                    <attribute>
                        <name>John</name>
                    </attribute>
                </user>
            </section>
        </node>
    </root>
    

    产生了想要的正确结果:

    <root>
       <node id="a">
          <section id="a_1" method="run">
             <item id="0">
                <attribute>
                   <color>Red</color>
                </attribute>
             </item>
          </section>
          <section id="a_2">
             <item id="0">
                <attribute>
                   <color>Red</color>
                </attribute>
             </item>
          </section>
       </node>
       <node id="b">
          <section id="b_1" method="create">
             <user id="b_1a">
                <attribute>
                   <name>John</name>
                </attribute>
             </user>
             <user id="b_1b">
                <attribute>a</attribute>
             </user>
          </section>
          <section id="b_2">
             <user id="b_1a">
                <attribute>
                   <name>John</name>
                </attribute>
             </user>
          </section>
       </node>
    </root>
    

    解释

    Muenchian method for grouping 与复合键一起使用。在这里,我们忽略(删除)不是组中第一个节点的每个节点。


    二。 XSLT 2.0 解决方案——甚至更短,效率也不低

    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="node()|@*">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>
    
     <xsl:template match="node">
      <xsl:copy>
        <xsl:apply-templates select="@*"/>
    
        <xsl:for-each-group select="*"
             group-by="concat(name(), '+', @id, '+', @method)">
          <xsl:apply-templates select="."/>
        </xsl:for-each-group>
      </xsl:copy>
     </xsl:template>
    </xsl:stylesheet>
    

    解释

    正确使用 xsl:for-each-groupgroup-by 属性。

    【讨论】:

    • 还有一件事.. 如果删除重复项只能在同一父项下(部分 id)发生,如何修复此代码。谢谢。
    • @John:请问您能否提出一个新问题——包含源 XML 文档和想要的结果,并解释新的要求?然后通知我,我很乐意回答。
    • 我会在几分钟后发布并通知您。感谢您的宝贵时间。
    • 这是stackoverflow.com/questions/10274305/…的问题,如果这很复杂,我深表歉意。真的不知道。再次感谢。
    【解决方案2】:

    XSL 文件:

    <?xml version='1.0'?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>
    
    <xsl:template match="root">
        <root>
            <xsl:apply-templates/>
        </root>
    </xsl:template>
    
    <xsl:template match="node">
        <node>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </node>
    </xsl:template>
    
    <xsl:template match="section[@id = 'b_1'][1]">  
        <section>
            <xsl:copy-of select="node()|@*"/>
        </section>  
    </xsl:template>
    
    <xsl:template match="section[@id != 'b_1']">
        <section>       
            <xsl:copy-of select="node()|@*"/>
        </section>
    </xsl:template>
    
    <xsl:template match="section[@id = 'b_1'][position() &gt; 1]"/> 
    
    </xsl:stylesheet>
    

    转变:

    <root>
            <node id="a">
                <section id="a_1">
                    <item id="0">
                        <attribute>
                            <color>Red</color>
                        </attribute>
                    </item>
                </section>
                <section id="a_2">
                    <item id="0">
                        <attribute>
                            <color>Red</color>
                        </attribute>
                    </item>
                </section>
            </node>
            <node id="b">
                <section id="b_1" method="create">
                    <user id="b_1a">
                        <attribute>
                            <name>John</name>
                        </attribute>
                    </user>
                    <user id="b_1b">
                        <attribute>a</attribute>
                    </user>
                </section>
                <section id="b_2">
                    <user id="b_1a">
                        <attribute>
                            <name>John</name>
                        </attribute>
                    </user>
                </section>
            </node>
        </root>
    

    希望这会有所帮助。

    [编辑] 在同一个输入文件上试试这个 XSL:

    <?xml version='1.0'?>
    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
        <xsl:template match="/">
            <xsl:apply-templates/>
        </xsl:template>
    
        <xsl:template match="*[not(@id eq preceding::*[local-name() eq local-name(.)]/@id)]">
            <xsl:element name="{name()}">
                <xsl:copy-of select="node()|@*"/>
            </xsl:element>
        </xsl:template>
    
    </xsl:stylesheet>
    

    结果:

    <root>
      <node id="a">
        <section id="a_1">
          <item id="0">
            <attribute>
              <color>Red</color>
            </attribute>
          </item>
        </section>
        <section id="a_2">
          <item id="0">
            <attribute>
              <color>Red</color>
            </attribute>
          </item>
        </section>
      </node>
      <node id="b">
        <section id="b_1" method="create">
          <user id="b_1a">
            <attribute>
              <name>John</name>
            </attribute>
          </user>
          <user id="b_1b">
            <attribute>a</attribute>
          </user>
        </section>
        <section id="b_1" method="create">
          <user id="b_1c">
            <attribute>a</attribute>
          </user>
        </section>
        <section id="b_2">
          <user id="b_1a">
            <attribute>
              <name>John</name>
            </attribute>
          </user>
        </section>
      </node>
    </root>
    

    [/编辑]

    【讨论】:

    • 感谢您的回复,但正如我在问题中提到的,我们只需要删除 1 个重复的节点节点即可。所以在这种情况下,我们仍然需要保留
      和相应的孩子。您介意更新解决方案吗?非常感谢。
    • 谢谢@Cylian!真的很感激。还有一件事可以概括,我的意思是它可以是任何元素,不必是
      只要元素名称、id 和属性(方法=创建)相同,其中之一将被淘汰
    • 您使用的是哪个 XSLT 版本?
    • 看到这个postthis
    • 没有属性的不一样
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-20
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    相关资源
    最近更新 更多