Transforming one XML format to another via XSL

Tags: xslt xslt-2.0
By : PJE
Source: Stackoverflow.com
Question!

The existing format is

<A>
  <B>
    <C>hello</C>
    <C>how</C>
    <C>are</C>
    <C>you</C> 
  </B>
</A>

I want to transform it to something like this

<start>
  <A>
    <B>
      <tag1> hello </tag1>
      <tag2> hello </tag2>
    </B>
  </A>
  <A>
    <B>
      <tag1> are </tag1>
      <tag2> you </tag2>
    </B>
  </A>
</start>

Now this <C> tag can occur n number of times and for each bunches of 2 <C> tag a new <A> </A> tag with the same tag names (see tag1 and tag2 names are same in both the cases) should be created. The entire process is dynamic.

Update:

I have a existing dynamic XML structute something like this

<LSR_RESP>
    <HDR> 
        <ORD>AAAAA</ORD>   
        <ORD>BBBBB</ORD>  
        <ORD>CCCCC</ORD>   
        <ORD>DDDDD</ORD> 
        <ORD>EEEEE</ORD> 
        <ORD>FFFFF</ORD>
        <ORD>GGGGG</ORD>
        <ORD>RRRRR</ORD>
        <ORD>KKKKK</ORD>
    </HDR>
</LSR_RESP>

I want to transform it via XSLT to something like this

<entity>
<r>
  <c>
  <f ID="OrderNumber1">AAAAA</f> 
  <f ID="OrderNumber2">BBBBB</f> 
  <f ID="OrderNumber3">CCCCC</f> 
  <f ID="OrderNumber4">DDDDD</f> 
  <f ID="OrderNumber5">EEEEE</f> 
  <f ID="OrderNumber6">FFFFF</f> 
  <f ID="OrderNumber7">GGGGG</f> 
  </c>
  </r>
  <r>
  <c>
  <f ID="OrderNumber1">RRRRR</f> 
  <f ID="OrderNumber2">KKKKK</f> 
  </c>
  </r>
  </entity>

Now as you can see above each row tag is made by taking tag values in group of 7. And the name of the new tags will also get repearted in groups of 7 like "OrderNumber1" to "OrderNumber7". The field can occur n number of times but the new structure will be formed in groups of 7.

Like in the above example the are 9 tags so it forms 2 groups one of 7 which leaves (9-7) i.e 2 tags for the next group, so in the next group you can see only OrderNumber1 and OrderNumber2. Had there been 10 tags it would have been a group of 7 and then another group of 3. Had there been 15 tags it would have been two groups of 7 and then another group of 1.

By : PJE


Answers
Simplest approach (XSLT 1.0 is by far sufficient):

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

<xsl:template match="/">
  <start>
    <xsl:apply-templates select="
      A/B/C[position() mod 2 = 1 and following-sibling::C]" 
    />
  </start>
</xsl:template>

<xsl:template match="C">
  <A>
    <B>
      <tag1>
        <xsl:value-of select="text()" />
      </tag1>
      <tag2>
        <xsl:value-of select="following-sibling::C[1]/text()" />
      </tag2>
    </B>
  </A>
</xsl:template>

</xsl:stylesheet>

Also possible, maybe more flexible due to the use separate templates and <xsl:copy>/<xsl:copy-of>:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:template match="/">
    <start>
      <xsl:for-each select="
        A/B/C[position() mod 2 = 1 and following-sibling::C]
      ">
        <xsl:apply-templates select="ancestor::A">
          <xsl:with-param name="C" select="." />
        </xsl:apply-templates>
      </xsl:for-each>
    </start>
  </xsl:template>

  <xsl:template match="A">
    <xsl:param name="C" />
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <xsl:apply-templates select="B">
        <xsl:with-param name="C" select="$C" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="B">
    <xsl:param name="C" />
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <xsl:apply-templates select="$C" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="C">
    <tag1>
      <xsl:value-of select="text()" />
    </tag1>
    <tag2>
      <xsl:value-of select="following-sibling::C[1]/text()" />
    </tag2>
  </xsl:template>

</xsl:stylesheet>

But then again, maybe this is over-complicated, it depends on your actual data. Key point is to select only the interesting <C> nodes (those at odd positions) and build the rest of the transformation around them.

Both templates result in:

<start>
  <A>
    <B>
      <tag1>hello</tag1>
      <tag2>how</tag2>
    </B>
  </A>
  <A>
    <B>
      <tag1>are</tag1>
      <tag2>you</tag2>
    </B>
  </A>
</start>
By : Tomalak


This video can help you solving your question :)
By: admin