Wednesday, October 10, 2018

XSLT transformation Metadata/Item/Group to Metadata/Group/Item aka Grouped elements

Lets say, we have input xml as the list of items. Each of them has subelement group. 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
   <Metadata>
      <Item>
         <key>Item1</key>
         <value>Value1</value>
         <group>Group1</group>
      </Item>
      <Item>
         <key>Item2</key>
         <value>2</value>
         <group>Group2</group>
      </Item>
      <Item>
         <key>Item3</key>
         <value>3</value>
         <group>Group2</group>
      </Item>
   </Metadata>

We need to transform that xml, so that each item with same group will be subelements of that group (element).

Output xml will look like this.

1
2
3
4
5
6
7
<Group1>
  <Item1>1</Item1>
</Group1>
<Group2>
  <Item2>2</Item2>
  <Item3>3</Item3>
</Group2>

This we can achieve by following XSLT transformation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!--Identity template,
        provides default behavior that copies all content into the output -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!--More specific template for our xml structure -->
    <xsl:template match="Metadata">
      <xsl:element name="Metadata" namespace="">
      <Item><key>
      <xsl:for-each select="Item">
        <xsl:variable name="group" select="./group/@text()" />
        <xsl:if test="not(preceding-sibling::Item[1]/group=./group)">
             <xsl:if test="position() > 1">
              <xsl:text>&lt;</xsl:text>/<xsl:value-of select="preceding-sibling::Item[1]/group"/><xsl:text>&gt;</xsl:text>
             </xsl:if>
             <xsl:text>&lt;</xsl:text><xsl:value-of select="group"/><xsl:text>&gt;</xsl:text>
        </xsl:if>
             <xsl:text>&lt;</xsl:text><xsl:value-of select="key"/>
             <xsl:if test="value=''"><xsl:text> xsi:nil="true"</xsl:text></xsl:if><xsl:text>&gt;</xsl:text><xsl:value-of select="value"/><xsl:text>&lt;</xsl:text>/<xsl:value-of select="key"/><xsl:text>&gt;</xsl:text>
        <xsl:if test="position() = last()">
          <xsl:text>&lt;</xsl:text>/<xsl:value-of select="./group"/><xsl:text>&gt;</xsl:text>
        </xsl:if>
     </xsl:for-each>
   </key></Item></xsl:element>

    </xsl:template>

</xsl:stylesheet>

No comments:

Post a Comment