Merge two or more XML node using XSLT [closed]

2019-07-30 15:54发布

This is the input file:

<root> 
    <node id="N1">
        <fruit id="1" action="aaa">
            <orange id="x" action="create">
                <attribute>
                    <color>Orange</color>
                    <year>2012</year>
                </attribute>
            </orange>
            <orange id="x" action="change">
                <attribute>
                    <color>Red</color>
                </attribute>
            </orange>
            <orange id="x" action="change">
                <attribute>
                    <color>Blue</color>
                    <condition>good</condition>
                </attribute>
            </orange>
        </fruit>

    </node>

    <node id="N2">
        <car id="1">    
            <bmw id="i" action="change">
                <attribute>
                    <color>Blue</color>    
                </attribute>
            </bmw>      
            <bmw id="i" action="change">
                <attribute>
                    <color>Yellow</color>    
                </attribute>
            </bmw>
            <bmw id="i" action="change">
                <attribute>
                    <color>Pink</color>    
                </attribute>
            </bmw>


        <bmw id="j" action="delete">
            <attribute>
                <color>Blue</color>    
            </attribute>
        </bmw>
        <bmw id="j" action="delete">
            <attribute>
                <color>Yellow</color>    
            </attribute>
        </bmw>

    </car>
    </node>
</root>

This is the expected output:

<root> 
    <node id="N1">
        <fruit id="1" action="aaa">
            <orange id="x" action="create">
                <attribute>
                    <color>Blue</color>
                    <year>2012</year>
                    <condition>good</condition>
                </attribute>
            </orange>                      
        </fruit>       
    </node>

    <node id="N2">
        <car id="1">    

            <bmw id="i" action="change">
                <attribute>
                    <color>Pink</color>    
                </attribute>
            </bmw>


        <bmw id="j" action="delete">
            <attribute>
                <color>Yellow</color>    
            </attribute>
        </bmw>
      </car>
    </node>
</root>

The rule:

  1. if there is node with 'create' method followed by one or more 'change' method, we merge them together and use ALL children from the last 'change' into the node with 'create' method. (Note: good is added )

  2. if there is one or more 'change' method we merge them and use only children from the last 'change' method.

  3. if there is one or more 'delete' method we merge them and use only children from the last 'delete' method.

Note that the id must be the same for node to be merged.

Please advise me on XSLT solution for this problem. Thanks so much.

kind regards, John

标签: xml xslt
1条回答
Emotional °昔
2楼-- · 2019-07-30 16:44

This transformation:

<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:template match="node()|@*">
      <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
     </xsl:template>

     <xsl:template match="node/*/*[1]">
      <xsl:copy>
       <xsl:apply-templates select="@* | ../*[last()]/*"/>
      </xsl:copy>
     </xsl:template>

     <xsl:template match=
      "node/*/*
        [@action='delete'
       and
         following-sibling::*[1][@action='delete']
        ]"/>

     <xsl:template match=
      "node/*/*
        [@action='change'
       and
         following-sibling::*[1][@action='change']
       or
         preceding-sibling::*[@action='create']
        ]"/>
</xsl:stylesheet>

when applied on the provided XML document:

<root>
    <node id="N1">
        <fruit id="1" action="aaa">
            <orange id="x" action="create">
                <attribute>
                    <color>Orange</color>
                </attribute>
            </orange>
            <orange id="x" action="change">
                <attribute>
                    <color>Red</color>
                </attribute>
            </orange>
            <orange id="x" action="change">
                <attribute>
                    <color>Blue</color>
                    <condition>good</condition>
                </attribute>
            </orange>
        </fruit>
    </node>
    <node id="N2">
        <car id="1">
            <bmw id="i" action="change">
                <attribute>
                    <color>Blue</color>
                </attribute>
            </bmw>
            <bmw id="i" action="change">
                <attribute>
                    <color>Yellow</color>
                </attribute>
            </bmw>
            <bmw id="i" action="change">
                <attribute>
                    <color>Pink</color>
                </attribute>
            </bmw>
            <bmw id="j" action="delete">
                <attribute>
                    <color>Blue</color>
                </attribute>
            </bmw>
            <bmw id="j" action="delete">
                <attribute>
                    <color>Yellow</color>
                </attribute>
            </bmw>
        </car>
    </node>
</root>

produces the wanted, correct result:

<root>
   <node id="N1">
      <fruit id="1" action="aaa">
         <orange id="x" action="create">
            <attribute>
               <color>Blue</color>
               <condition>good</condition>
            </attribute>
         </orange>
      </fruit>
   </node>
   <node id="N2">
      <car id="1">
         <bmw id="i" action="change">
            <attribute>
               <color>Pink</color>
            </attribute>
         </bmw>
         <bmw id="j" action="delete">
            <attribute>
               <color>Yellow</color>
            </attribute>
         </bmw>
      </car>
   </node>
</root>
查看更多
登录 后发表回答