Search code examples
xsltxslt-1.0xslt-grouping

Extract values from a Comma separated field and populate in target using XSLT


Looking for an XSLT 1.0 code which will transform the input xml(where item is repeated segment) like below to the expected output

<root type="array">
  <item type="object">
    <metadata type="object">
      <GTIN type="string">abcd,efwe,sdsf</GTIN>
    </metadata>
  </item>
  <item type="object">
    <metadata type="object">
      <GTIN type="string">xxx,yyy,zzz</GTIN>
    </metadata>
  </item>
</root>

Output expected XML :

<Assets>
 <Asset ID="X.test" UserTypeID="XAsset">
  <Values>
   <MultiValue AttributeID="GTINList"/>
     <value>abcd</value>
     <value>efwe</value>
    <value>sdsf</value>
  </Values>
 </Asset>
 <Asset ID="X.test" UserTypeID="XAsset">
  <Values>
   <MultiValue AttributeID="GTINList"/>
     <value>xxx</value>
     <value>yyy</value>
    <value>zzz</value>
  </Values>
 </Asset>
</Assets>

With the following XSLT, but not getting expected output, after using the nested recursive template as well.


Solution

  • The following stylesheet uses a recursive template:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="GTIN">
        <Values>
          <MultiValue AttributeID="GTINList"/>
          <xsl:call-template name="split">
            <xsl:with-param name="string" select="concat(.,',')"/>
          </xsl:call-template>
        </Values>
      </xsl:template>
      <xsl:template match="metadata">
        <Asset ID="X.test" UserTypeID="XAsset">
          <xsl:apply-templates/>
        </Asset>
      </xsl:template>
      <xsl:template match="root">
        <Assets>
          <xsl:apply-templates/>
        </Assets>
      </xsl:template>
      <xsl:template name="split">
        <xsl:param name="string"/>
        <xsl:if test="$string">
          <value>
            <xsl:value-of select="substring-before($string,',')"/>
          </value>
          <xsl:call-template name="split">
            <xsl:with-param name="string" select="substring-after($string,',')"/>
          </xsl:call-template>
        </xsl:if>
      </xsl:template>
    </xsl:stylesheet>
    

    An extra comma is appended at the end to ensure that the last GTIN is also found by substring-before.