Search code examples
xmlxsltbpel

XSLT transformation issue : From plain XML to multi level XML


I need to transform below input XML to output XML. Can you please provide any ideas for this.

I need to transform below input XML to output XML. Can you please provide any ideas for this.

Input XML :

<GenericCollection ParamValue="ParamValue1" xmlns="http://www.example.org">
  <Generic>
    <store>Store1</store>
    <metricName>Metric1</metricName>
    <metricValue>1</metricValue>
  </Generic>
  <Generic>
    <store>Store1</store>
    <metricName>Metric2</metricName>
    <metricValue>1</metricValue>
  </Generic>
  <Generic>
    <store>Store2</store>
    <metricName>Metric1</metricName>
    <metricValue>1</metricValue>
  </Generic>
  <Generic>
    <store>Store2</store>
    <metricName>Metric1</metricName>
    <metricValue>2</metricValue>
  </Generic>
  <Generic>
    <store>Store2</store>
    <metricName>Metric2</metricName>
    <metricValue>1</metricValue>
  </Generic>
  <Generic>
    <store>Store3</store>
    <metricName>Metric1</metricName>
    <metricValue>1</metricValue>
  </Generic>
  <Generic>
    <store>Store3</store>
    <metricName>Metric1</metricName>
    <metricValue>2</metricValue>
  </Generic>
</GenericCollection>

output:

<?xml version = '1.0' encoding = 'UTF-8'?>
<ns4:EnterpriseDocument>
  <ns4:DataSet>
    <ns4:Dimension ref_name="bu_code" value="Store1">
      <ns4:Metric ref_name="Metric1">
        <ns4:Data value="1"/>
      </ns4:Metric>
      <ns4:Metric ref_name="Metric2">
        <ns4:Data value="1"/>
      </ns4:Metric>
    </ns4:Dimension>
    <ns4:Dimension ref_name="bu_code" value="Store2">
      <ns4:Metric ref_name="Metric1">
        <ns4:Data value="1"/>
        <ns4:Data value="2"/>            
      </ns4:Metric>
      <ns4:Metric ref_name="Metric2">
        <ns4:Data value="1"/>
      </ns4:Metric>
    </ns4:Dimension>
    <ns4:Dimension ref_name="bu_code" value="Store3">
      <ns4:Metric ref_name="Metric1">
        <ns4:Data value="1"/>
        <ns4:Data value="2"/>            
      </ns4:Metric>
    </ns4:Dimension>     
  </ns4:DataSet>
</ns4:EnterpriseDocument>
    Thanks,
    Ramesh

Solution

  • If you are able to use XSLT 2.0, then you should probably be using xsl:for-each-group here, rather than xsl:for-each because you are trying to group the elements here.

    Firstly you are grouping by Generic elements by their store value, so you would write this.

    <xsl:for-each-group select="Generic" group-by="store">
    

    Then within this, you would output the *Dimension * element for the group like so:

    <Dimension ref_name="bu_code" value="{current-grouping-key()}">
    

    Next, you want to further group the elements in this group by their metricName value

    <xsl:for-each-group select="current-group()" group-by="metricName">
    

    Note the use of current-group() here. You are only iterating over the elements in the current "store" group, and not over all generic elements.

    Finally, to output all your Data elements, you would do this

    <xsl:for-each select="current-group()">
    

    Try the following XSLT

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
         xpath-default-namespace="http://www.example.org">
    
    <xsl:output method="xml" indent="yes" />
    
    <xsl:template match="/*">
       <EnterpriseDocument>
       <DataSet>
          <xsl:for-each-group select="Generic" group-by="store">
             <Dimension ref_name="bu_code" value="{current-grouping-key()}">
                <xsl:for-each-group select="current-group()" group-by="metricName">
                   <Metric ref_name="{current-grouping-key()}">
                      <xsl:for-each select="current-group()">
                        <Data value="{metricValue}"/>
                      </xsl:for-each>
                   </Metric>
                </xsl:for-each-group>
             </Dimension>
          </xsl:for-each-group>
        </DataSet>
       </EnterpriseDocument>
    </xsl:template>
    
    </xsl:stylesheet>
    

    When run on your XML sample, the following is output (Note, in my sample I am not including any namespaces, just for clarity)

    <EnterpriseDocument>
       <DataSet>
          <Dimension ref_name="bu_code" value="Store1">
             <Metric ref_name="Metric1">
                <Data value="1"/>
             </Metric>
             <Metric ref_name="Metric2">
                <Data value="1"/>
             </Metric>
          </Dimension>
          <Dimension ref_name="bu_code" value="Store2">
             <Metric ref_name="Metric1">
                <Data value="1"/>
                <Data value="2"/>
             </Metric>
             <Metric ref_name="Metric2">
                <Data value="1"/>
             </Metric>
          </Dimension>
          <Dimension ref_name="bu_code" value="Store3">
             <Metric ref_name="Metric1">
                <Data value="1"/>
                <Data value="2"/>
             </Metric>
          </Dimension>
       </DataSet>
    </EnterpriseDocument>