使用xslt在XML中的同一父项下删除具有相同属性的同一节点

时间:2012-04-23 02:59:28

标签: xml xslt

我需要转换这个XML输入:

<root>
    <node id="a">
        <section id="a_1" method="run">
            <item id="0" method="a">
                <attribute>
                    <color>Red</color>
                    <status>1</status>
                    <condition>good</condition>
                </attribute>

            </item>

            <item id="0" method="a">
                <attribute>
                    <color>Red</color>
                    <status>1</status>
                    <condition>good</condition>
                </attribute>

            </item>
        </section>

        <section id="a_2" method="run">
            <item id="0" method="a">
                <attribute>
                    <color>Red</color>
                    <status>1</status>
                    <condition>good</condition>
                </attribute>

            </item>
        </section>

    </node>

    <node id="b">
        <section id="b_1" method="create">
            <user id="b_1a" method="x">
                <attribute>

                    <origin>us</origin>
                </attribute>

            </user>
            <user id="b_1a" method="x">
                <attribute> 
                    <origin>us</origin>
                </attribute>
            </user>
            <user id="b_1b">
                <attribute>a</attribute>
            </user>
        </section>

        <section id="b_2">
            <user id="b_1a" method="x">
                <attribute>
                    <name>John</name>
                    <origin>us</origin>
                </attribute>
            </user>
        </section>
    </node>
</root>

这是预期的输出:

<root>
    <node id="a">
        <section id="a_1" method="run">
            <item id="0" method="a">
                <attribute>
                    <color>Red</color>
                    <status>1</status>
                    <condition>good</condition>
                </attribute>                    
            </item>               
        </section>

        <section id="a_2" method="run">
            <item id="0" method="a">
                <attribute>
                    <color>Red</color>
                    <status>1</status>
                    <condition>good</condition>
                </attribute>

            </item>
        </section>
    </node>

    <node id="b">
        <section id="b_1" method="create">
            <user id="b_1a" method="x">
                <attribute>
                    <origin>us</origin>
                </attribute>

            </user>

            <user id="b_1b">
                <attribute>a</attribute>
            </user>
        </section>

        <section id="b_2">
            <user id="b_1a" method="x">
                <attribute>
                    <name>John</name>
                    <origin>us</origin>
                </attribute>
            </user>
        </section>
    </node>
</root>

注意:重复意味着所有子/子具有相同的值,只要节点是同一个父节点(id和方法相同),节点就可以有1个或多个子节点,我们可以认为它总是在同一部分(id和方法是相同的)。

这可能吗?请赐教我

非常感谢。

欢呼声, 约翰

1 个答案:

答案 0 :(得分:2)

<强>予。这个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(generate-id(..), '+', 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(generate-id(..),
                             '+',name(), '+', @id, '+', @method)
                             )[1]
                        )
             )
         ]"/>
</xsl:stylesheet>

应用于提供的源XML文档时:

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

会产生想要的正确结果:

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

解释:使用复合键正确使用 Muenchian method for grouping

  1. 身份规则“按原样”复制每个节点。

  2. xsl:key定义将元素组与字符串键值相关联。如此定义的任何组都包含具有idmethod属性的所有元素,并且(组中的所有)具有相同的父级,相同的名称,{{的相同字符串值1}}属性和id属性的相同字符串值。

  3. 有一个模板会覆盖身份模板。它匹配具有methodid属性且不是其各自组中的第一个(按文档顺序排列)元素的任何元素。由于此模板没有正文,因此根本不会处理所有此类匹配元素,也不会将其复制到输出中(我们可以说它们已被“删除”)。

  4. 由于上面的3.,只有作为其组的第一个元素的元素才会与覆盖模板匹配。因此,这些元素由身份模板匹配并复制到输出 - 完全符合要求。


  5. <强> II。 XSLT 2.0解决方案:

    method

    解释:正确使用 xsl:for-each-group <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="*[@id]"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:for-each-group select="*" group-by= "concat(generate-id(..), '+', name(), '+', @id, '+', @method)"> <xsl:apply-templates select="."/> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet> 属性。