Reputation: 17
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
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
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