I would like to implement a "split function / template" that takes a string and a separator as input and returns a broken array of string

I would like to implement a split function/template in XSLT that takes a string and a separator as input and returns a broken array of string.

Or rather, I would like to do something in accordance with:

 <xsl:call-template name="F"> <xsl:with-param name="input" select="'a,b,c,d,e'"/> <xsl:with-param name="replacement"> <option value='$x'>$x</option> </xsl:with-param> </xsl:call-template> 

which will give me

 <option value='a'>a</option><option value='b'>b</option><option value='c'>c</option><option value='d'>d</option><option value='e'>e</option> 

XSLT 1.0 oriented question (but I don't mind finding out how XSLT 2.0 does it)

+2
source share
2 answers

I. XSLT 2.0 Solution

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/"> <xsl:variable name="vStr" select="'a,b,c,d,e'"/> <xsl:for-each select="tokenize($vStr, ',')"> <option value="{.}"><xsl:value-of select="."/></option> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

when this conversion is applied to the ant XML document (not used), the desired, correct result is created :

 <option value="a">a</option> <option value="b">b</option> <option value="c">c</option> <option value="d">d</option> <option value="e">e</option> 

The explanation . Using the standard XPath 2.0 tokenize() function.

II. XSLT 1.0: Using FXSL 1.x str-split-to-words function / template

This is the XSLT 1.0 conversion:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext"> <xsl:import href="strSplit-to-Words.xsl"/> <xsl:output indent="yes" omit-xml-declaration="yes"/> <xsl:template match="/"> <xsl:variable name="vwordNodes"> <xsl:call-template name="str-split-to-words"> <xsl:with-param name="pStr" select="/"/> <xsl:with-param name="pDelimiters" select="', '"/> </xsl:call-template> </xsl:variable> <xsl:apply-templates select= "ext:node-set($vwordNodes)/*"/> </xsl:template> <xsl:template match="word"> <option value="{.}"><xsl:value-of select="."/></option> </xsl:template> </xsl:stylesheet> 

when applied to this XML document :

 <t>a,b,cd,e</t> 

creates the desired, correct result :

 <option value="a">a</option> <option value="b">b</option> <option value="c">c</option> <option value="d">d</option> <option value="e">e</option> 

Note The pDelimiters parameter (according to him) may contain more than one separator character - in this case we use both ',' and ' ' .

III. XSLT 1.0 solution using a handwritten recursive named template :

This conversion is:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="text()" name="tokenize"> <xsl:param name="pText" select="."/> <xsl:param name="pDelim" select="','"/> <xsl:if test="string-length($pText) > 0"> <xsl:variable name="vToken" select= "substring-before(concat($pText,','), ',')"/> <option value="{$vToken}"> <xsl:value-of select="$vToken"/> </option> <xsl:call-template name="tokenize"> <xsl:with-param name="pText" select= "substring-after($pText,',')"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet> 

when applied to this XML document :

 <t>a,b,c,d,e</t> 

creates the desired, correct result :

 <option value="a">a</option> <option value="b">b</option> <option value="c">c</option> <option value="d">d</option> <option value="e">e</option> 

IV. Going to the tokenize template in III above as a template / function parameter for processing each token

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://fxsl.sf.net" exclude-result-prefixes="f"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <f:processToken/> <xsl:variable name="vFunc" select= "document('')/*/f:processToken[1]"/> <xsl:template match="text()" name="tokenize"> <xsl:param name="pText" select="."/> <xsl:param name="pDelim" select="','"/> <xsl:param name="pProcessFunc" select="$vFunc"/> <xsl:if test="string-length($pText) > 0"> <xsl:variable name="vToken" select= "substring-before(concat($pText,','), ',')"/> <xsl:apply-templates select="$pProcessFunc"> <xsl:with-param name="arg1" select="$vToken"/> </xsl:apply-templates> <xsl:call-template name="tokenize"> <xsl:with-param name="pText" select= "substring-after($pText,',')"/> </xsl:call-template> </xsl:if> </xsl:template> <xsl:template match="f:processToken"> <xsl:param name="arg1"/> <option value="{$arg1}"> <xsl:value-of select="$arg1"/> </option> </xsl:template> </xsl:stylesheet> 

when this conversion is applied to the same XML document as in III, the same desired, correct result is obtained :

 <option value="a">a</option> <option value="b">b</option> <option value="c">c</option> <option value="d">d</option> <option value="e">e</option> 

Now, if we replace the last template with this :

  <xsl:template match="f:processToken"> <xsl:param name="arg1"/> <p> <xsl:value-of select="$arg1"/> </p> </xsl:template> 

again the desired result is obtained :

 <p>a</p> <p>b</p> <p>c</p> <p>d</p> <p>e</p> 
+3
source

The answer you saw is missing a separator parameter:

 <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:value-of select="$first" /> <!-- token --> <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> 
0
source

All Articles