使用 xslt 删除 XML 中相同父项下具有相同属性的相同节点 [英] remove the same node with same attribute under the same parent in XML using xslt

查看:28
本文介绍了使用 xslt 删除 XML 中相同父项下具有相同属性的相同节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要转换这个 XML 输入:

I need to transform this XML input:

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

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

Note: the duplicate means all the child/children is having the same value, the node can have 1 or more children as long as it is the same parent (id and method are the same) and we can assume that it always in the same section (id and method are the same).

这能做到吗?请赐教

非常感谢.

干杯,约翰

推荐答案

I.这个 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>

说明:正确使用慕尼黑方法用于分组,使用复合键:

Explanation: Proper use of the Muenchian method for grouping, using a composite key:

  1. 身份规则按原样"复制每个节点.

  1. The identity rule copies every node "as-is".

xsl:key 定义将元素组与字符串键值相关联.任何这样定义的组都由所有元素组成,这些元素同时具有 idmethod 属性,并且(都在组中)具有相同的父级、相同的名称、相同的id 属性的字符串值和 method 属性的相同字符串值.

The xsl:key definition associates groups of elements with a string key-value. Any group so defined consists of all elements that have both an id and a method attributes and that (all in the group) have the same parent, the same name, the same string value of the id attribute and the same string value of the method attribute.

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

There is a single template overriding the identity template. It matches any elements that have both an id and a method attributes and are not the first (in document order) element in their respective group). Because this template has no body, all such matched elements are not processed at all and aren't copied to the output (we could say they are "deleted").

由于上面的 3.,只有作为其组的第一个元素的元素不会被覆盖模板匹配.因此,这些元素由身份模板匹配并复制到输出——完全按照要求.

Because of 3. above, only elements that are the first element of their group aren't matched by the overriding template. Thus these elements are matched by the identity template and copied to the output -- exactly as required.

<小时>

二.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="*[@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>

说明:正确使用xsl:for-each-groupgroup-by 属性.

Explanation: Proper use of xsl:for-each-group with the group-by attribute.

这篇关于使用 xslt 删除 XML 中相同父项下具有相同属性的相同节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆