QnA
QnA

Reputation: 75

Consolidation of Data using certain keys in XSLT

I have an input XML file:

<root>
   <row>
     <col1>cust001</col1>
     <col2>cc1</col2>
     <col3>po1</col3>
     <col4>2020-02-22</col4>
     <col5>Men</col5>
     <col6>item1</col6>
     <col7>60</col7>
   </row>
   <row>
     <col1>cust001</col1>
     <col2>cc1</col2>
     <col3>po1</col3>
     <col4>2020-02-22</col4>
     <col5>Men</col5>
     <col6>item2</col6>
     <col7>50</col7>
   </row>
</root> 

Desired output: (if col1 to col5 are the same, consolidate into one row.)

<root>
       <row>
         <col1>cust001</col1>
         <col2>cc1</col2>
         <col3>po1</col3>
         <col4>2020-02-22</col4>
         <col5>Men</col5>
         <col6>item1</col6>
         <col7>60</col7>
         <col6>item2</col6>
         <col7>50</col7>
       </row>
    </root> 

I'm trying the code here XSLT Consolidating data when ID is the same but I'm getting, Error in Expression current-group(): Unknown system function: current group.

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

   <xsl:output method="xml" indent="yes"/>

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

   <xsl:template match="resultSet">
      <xsl:apply-templates select="@*"/>
      <xsl:for-each-group select="root/row" group-by="concat(col1,col2,col3,col4,col5)">            
            <xsl:value-of select="current-grouping-key()"/>
            <xsl:apply-templates select="current-group()" />            
      </xsl:for-each-group>
   </xsl:template>

Upvotes: 0

Views: 39

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167716

Assuming you use an XSLT 3 processor like Saxon 9.8 or later or AltovaXML 2017 R3 or later you can use a composite grouping key of the elements you want to use as a grouping key, then, inside, you of course need to make sure you create a single row for each group and only process the items forming the grouping key once (e.g. for the first item in the group which is the context item inside of the for-each-group) and then all the other elements for all items in the group:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output indent="yes"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="root">
      <xsl:copy>
          <xsl:for-each-group select="row" composite="yes" group-by="col1, col2, col3, col4, col5">
              <xsl:copy>
                  <xsl:apply-templates select="col1, col2, col3, col4, col5, current-group()/(* except (col1, col2, col3, col4, col5))"/>
              </xsl:copy>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/jz1Q1yt

Or, perhaps, the body of the for-each-group is a bit less repetitive in terms of the grouping key elements with

  <xsl:template match="root">
    <xsl:copy>
        <xsl:for-each-group select="row!copy-of()" composite="yes" group-by="col1, col2, col3, col4, col5">
            <xsl:copy>
                <xsl:apply-templates select="current-group()/(if (position() eq 1) then * else (* except (col1, col2, col3, col4, col5)))"/>
            </xsl:copy>
        </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

https://xsltfiddle.liberty-development.net/jz1Q1yt/1

Upvotes: 0

Related Questions