mantlex
mantlex

Reputation: 17

XSLT - Create duplicate nodes from an XML

I have a multi level XML, I need to duplicate a set of nodes with a new node using XSLT 1.0 Below is a sample xml.

<?xml version="1.0"?>
<Parent>
   <ChildL1 Childtype="A">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1>
         <ChildL1L2/>
      </ChildL1L1>
   </ChildL1>
   <ChildL1 Childtype="B">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1/>
   </ChildL1>
</Parent>

Desired output:

<?xml version="1.0"?>
<Parent>
   <ChildL1 Childtype="A">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1>
         <ChildL1L2/>
      </ChildL1L1>
   </ChildL1>
   <ChildL1 Childtype="B">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1/>
   </ChildL1>
<NewNode>
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1/>
</NewNode>    
</Parent>

Here the NewNode has the Children nodes of ChildL1 only when Childtype="B".

Thanks in Advance; Let me know if this question is not clear. It is my first time posting this type of question.

Editing to show deeper xml nodes:

<?xml version="1.0"?>
<Parent>
   <ChildL1 Childtype="A">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1>
         <ChildL1L2>
            <ChildL1L3 index="1"/>
            <ChildL1L3 index="2"/>
            <ChildL1L3 index="3"/>
         </ChildL1L2>
      </ChildL1L1>
   </ChildL1>
   <ChildL1 Childtype="B">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1/>
   </ChildL1>
</Parent>

desired output(pick Parent/ChildL1/ChildL1L1/ChildL1L2/ChildL1L3 where ChildL1/Childtype='A')

<?xml version="1.0"?>
<Parent>
   <ChildL1 Childtype="A">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1>
         <ChildL1L2>
            <ChildL1L3 index="1"/>
            <ChildL1L3 index="2"/>
            <ChildL1L3 index="3"/>
         </ChildL1L2>
      </ChildL1L1>
   </ChildL1>
   <ChildL1 Childtype="B">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1/>
   </ChildL1>
<NewNode>
            <ChildL1L3 index="1"/>
            <ChildL1L3 index="2"/>
            <ChildL1L3 index="3"/>
</NewNode>    
</Parent>

Upvotes: 1

Views: 2363

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 116959

In response to your edited question - this too is fairly straightforward:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/Parent">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <NewNode>
            <xsl:apply-templates select="ChildL1[@Childtype='A']/ChildL1L1/ChildL1L2/ChildL1L3"/>
        </NewNode>    
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Result:

<?xml version="1.0" encoding="UTF-8"?>
<Parent>
   <ChildL1 Childtype="A">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1>
         <ChildL1L2>
            <ChildL1L3 index="1"/>
            <ChildL1L3 index="2"/>
            <ChildL1L3 index="3"/>
         </ChildL1L2>
      </ChildL1L1>
   </ChildL1>
   <ChildL1 Childtype="B">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1/>
   </ChildL1>
   <NewNode>
      <ChildL1L3 index="1"/>
      <ChildL1L3 index="2"/>
      <ChildL1L3 index="3"/>
   </NewNode>
</Parent>

Upvotes: 1

StuartLC
StuartLC

Reputation: 107237

This is reasonably straightforward with the identity transform (and a variant to copy child nodes)

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="ChildL1[@Childtype='B']">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
        <NewNode>
            <xsl:copy-of select="child::node()"></xsl:copy-of>
        </NewNode>
    </xsl:template>

</xsl:stylesheet>

As per LeBarton's comment, you'll want to fix your Xml, e.g.:

<?xml version="1.0"?>
<Parent>
   <ChildL1 Childtype="A">
      <ChildL1L1/>
      <ChildL1L1/>
      <ChildL1L1>
         <ChildL1L2 />
      </ChildL1L1>
   </ChildL1>
   <ChildL1 Childtype="B">
      <ChildL1L1/>
      <ChildL1L1 foo="bar"/>
      <ChildL1L1/>
   </ChildL1>
</Parent>

The result is (assuming ChildL1/@Childtype='B's nodes are to be copied)

<?xml version="1.0" encoding="utf-8"?>
<Parent>
    <ChildL1 Childtype="A">
        <ChildL1L1 />
        <ChildL1L1 />
        <ChildL1L1>
            <ChildL1L2 />
        </ChildL1L1>
    </ChildL1>
    <ChildL1 Childtype="B">
        <ChildL1L1 />
        <ChildL1L1 foo="bar" />
        <ChildL1L1 />
    </ChildL1>
    <NewNode>
        <ChildL1L1 />
        <ChildL1L1 foo="bar" />
        <ChildL1L1 />
    </NewNode>
</Parent>

Upvotes: 0

Related Questions