Comma separated string parsing XSLT to for-each node

xslt

I have an input string which has csv values. Eg., 1,2,3
I would need to separate each values and assign to target node in for-each loop.

I got this below template that splits the input string based on delimiter. How can I assign each of the delimited values to the target element in for-each loop.

<xsl:template name="output-tokens">
<xsl:param name="list"/>
<xsl:param name="delimiter"/>
<xsl:variable name="newlist">
  <xsl:choose>
    <xsl:when test="contains($list, $delimiter)">
      <xsl:value-of select="normalize-space($list)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="concat(normalize-space($list), $delimiter)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>
<xsl:variable name="first" select="substring-before($newlist, $delimiter)"/>
<xsl:variable name="remaining"
              select="substring-after($newlist, $delimiter)"/>
<xsl:variable name="count" select="position()"/>
<num>
  <xsl:value-of select="$first"/>
</num>
<xsl:if test="$remaining">
  <xsl:call-template name="output-tokens">
    <xsl:with-param name="list" select="$remaining"/>
    <xsl:with-param name="delimiter">
      <xsl:value-of select="$delimiter"/>
    </xsl:with-param>
  </xsl:call-template>
</xsl:if>
</xsl:template>

Input xml:

<out1:AvailableDates>
<out1:AvailableDate>15/12/2011,16/12/2011,19/12/2011,20/12/2011,21/12/2011</out1:AvailableDate>
</out1:AvailableDates>

Expected Output:

<tns:AvailableDates>
<tns:AvailableDate>15/12/2011</tns:AvailableDate>
<tns:AvailableDate>16/12/2011</tns:AvailableDate>
<tns:AvailableDate>120/12/2011</tns:AvailableDate>
</tns:AvailableDates>

Best Answer

Here is a complete and short, true XSLT 1.0 solution:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:out1="undefined" xmlns:tns="tns:tns"
  exclude-result-prefixes="out1 tns">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="out1:AvailableDate">
  <tns:AvailableDates>
    <xsl:apply-templates/>
  </tns:AvailableDates>
 </xsl:template>

 <xsl:template match="text()" name="split">
  <xsl:param name="pText" select="."/>
  <xsl:param name="pItemElementName" select="'tns:AvailableDate'"/>
  <xsl:param name="pItemElementNamespace" select="'tns:tns'"/>

    <xsl:if test="string-length($pText) > 0">
     <xsl:variable name="vNextItem" select=
      "substring-before(concat($pText, ','), ',')"/>

      <xsl:element name="{$pItemElementName}"
                   namespace="{$pItemElementNamespace}">
       <xsl:value-of select="$vNextItem"/>
      </xsl:element>

      <xsl:call-template name="split">
        <xsl:with-param name="pText" select=
                       "substring-after($pText, ',')"/>
        <xsl:with-param name="pItemElementName" select="$pItemElementName"/>
        <xsl:with-param name="pItemElementNamespace" select="$pItemElementNamespace"/>
      </xsl:call-template>
    </xsl:if>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document (corrected to be made well-formed):

<out1:AvailableDates xmlns:out1="undefined">
    <out1:AvailableDate>15/12/2011,16/12/2011,19/12/2011,20/12/2011,21/12/2011</out1:AvailableDate>
</out1:AvailableDates>

the wanted, correct result is produced:

<tns:AvailableDates xmlns:tns="tns:tns">
   <tns:AvailableDate>15/12/2011</tns:AvailableDate>
   <tns:AvailableDate>16/12/2011</tns:AvailableDate>
   <tns:AvailableDate>19/12/2011</tns:AvailableDate>
   <tns:AvailableDate>20/12/2011</tns:AvailableDate>
   <tns:AvailableDate>21/12/2011</tns:AvailableDate>
</tns:AvailableDates>
Related Topic