Search code examples
xsltxslt-2.0saxonxslt-3.0xslt-grouping

Group XML elements with comma seperated values with XSLT program


We are new to xslt programming, can you please help us with xslt program. We need to group xml elements based on "id" tag and concatenate the other xml tag with comma.

input xml file:

<?xml version="1.0" encoding="UTF-8"?>
<root>
 <row>
  <id>123</id>
  <functional_manager__c.users>1234567</functional_manager__c.users>
 </row>
 <row>
  <id>123</id>
  <functional_manager__c.users>1200000</functional_manager__c.users>
 </row>
 <row>
  <id>111</id>
  <functional_manager__c.users>11111111</functional_manager__c.users>
 </row>
 <row>
  <id>111</id>
  <functional_manager__c.users>2222222</functional_manager__c.users>
 </row>
 <row>
  <id>123</id>
  <editor__v.users>1234567</editor__v.users>
  </row>
  <row>
   <id>123</id>
   <editor__v.users>1200000</editor__v.users>
  </row>
  <row>
    <id>111</id>
    <learning_partner__c.users>11111111</learning_partner__c.users>
  </row>
  <row>
    <id>111</id>
    <learning_partner__c.users>2222222</learning_partner__c.users>
  </row>
  </root>

Required Output:

<?xml version="1.0" encoding="UTF-8"?>
<root>
 <row>
  <id>123</id>
  <functional_manager__c.users>1234567,1200000</functional_manager__c.users>
 </row>
 <row>
  <id>111</id>
  <functional_manager__c.users>11111111,2222222</functional_manager__c.users>
 </row>
 <row>
  <id>123</id>
  <editor__v.users>1234567,1200000</editor__v.users>
  </row>
  <row>
    <id>111</id>
    <learning_partner__c.users>11111111,2222222</learning_partner__c.users>
  </row>
  </root>

code we tried:

<?xml version="1.0" encoding="utf-8"?>
 <xsl:stylesheet version="2.0" exclude-result-prefixes="xsl wd xsd this env"
  xmlns:wd="urn:com.workday/bsvc"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
   xmlns:this="urn:this-stylesheet">

    <xsl:output indent="yes" method="xml"/>
   <xsl:template match="/">
   <Sharingsettings>
    <xsl:for-each-group select="/root/row" group-by="id">
    <row>
     <ID>
      <xsl:value-of select="id"/>
      </ID>
      <functional_manager__c.users>
       <xsl:value-of select="//current-group()//functional_manager__c.users">

    </xsl:value-of>
     </functional_manager__c.users>
     </row>
     </xsl:for-each-group>
     </Sharingsettings>
     </xsl:template>
     </xsl:stylesheet>

we are trying with XSLT program but it is not giving required output properly.

Thank you so much in advance


Solution

  • With XSLT 3 you can use

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="3.0"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="#all"
      expand-text="yes">
    
      <xsl:output method="xml" indent="yes"/>
    
      <xsl:mode on-no-match="shallow-copy"/>
      
      <xsl:template match="root">
        <xsl:copy>
          <xsl:for-each-group select="row" group-adjacent="id">
            <xsl:copy>
              <xsl:apply-templates/>
            </xsl:copy>
          </xsl:for-each-group>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="row/*[not(self::id)]">
        <xsl:copy>
          <xsl:value-of select="current-group()/*[node-name() = node-name(current())]" separator=","/>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>