Himanshu Yadav
Himanshu Yadav

Reputation: 13587

Copying Child Nodes under different Parent

I am new to XSLT and got stuck with this issue.
Input XML

<Root>
 <Family>
   <Entity>
     <SomeElement1/>
     <Child1>
       <Element1/>
     </Child1>
     <Child2>
       <Element2/>
     </Child2>
     <Entity>
     <SomeElement1/>
     <Child1>
       <Element111/>
     </Child1>
     <Child2>
       <Element222/>
     </Child2>
   </Entity>
  </Entity>
 </Family>
</Root>

Output Xml

<Response>
 <EntityRoot>
  <SomeElement1/>
 </EntityRoot>

 <Child1Root>
   <Element1>
 </Child1Root>

 <Child2Root>
   <Element2>
 </Child2Root>

 <MetadataEntityRoot>
  <SomeElement1/>
 </MetadataEntityRoot>

 <Child1Root>
   <Element111>
 </Child1Root>

 <Child2Root>
   <Element222>
 </Child2Root>
</Response>

I know how to copy everything from the input xml. But not sure how would exclude child elements and then copy them again in a different root element.

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

Tried this based on the given answer

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
   </xsl:template>
    <xsl:template match="Entity">
      <EntityRoot>
        <xsl:apply-templates select="@* | node()[not(self::Child1 | self::Child2)]" />
      </EntityRoot>
      <xsl:apply-templates select="Child1 | Child2" />
    </xsl:template>
    <xsl:template match="Child1">
      <Child1Root><xsl:apply-templates select="@*|node()" /></Child1Root>
    </xsl:template>
    <xsl:template match="Child2">
      <Child2Root><xsl:apply-templates select="@*|node()" /></Child2Root>
    </xsl:template>
</xsl:stylesheet>

But got the output as:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
 <Family>
   <EntityRoot>
     <SomeElement1/>
   </EntityRoot>
   <Child1Root>
       <Element1/>
    </Child1Root>
    <Child2Root>
       <Element2/>
    </Child2Root>
 </Family>
</Root>

Upvotes: 0

Views: 672

Answers (1)

Ian Roberts
Ian Roberts

Reputation: 122364

In addition to the "copy everything" identity template you already have, you just add specific templates that match the elements you want to process differently. To rename Child1 to Child1Root you can use

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

and similarly to rename Child2 to Child2Root and Root to Response. For Entity you can think of the process as creating an EntityRoot containing (the result of applying templates to) all the child elements except Child1 and Child2, then apply templates to these two afterwards, outside the EntityRoot element:

<xsl:template match="Entity">
  <EntityRoot>
    <xsl:apply-templates select="@* | node()[not(self::Child1 | self::Child2)]" />
  </EntityRoot>
  <xsl:apply-templates select="Child1 | Child2" />
</xsl:template>

To strip out a layer entirely (in this case Family) but still include its children you can use a template without a copy:

<xsl:template match="Family">
  <xsl:apply-templates />
</xsl:template>

Upvotes: 2

Related Questions