Skip to content

Instantly share code, notes, and snippets.

@rnelson
Last active August 31, 2020 10:16
Show Gist options
  • Save rnelson/395bccd30092cedca87f to your computer and use it in GitHub Desktop.
Save rnelson/395bccd30092cedca87f to your computer and use it in GitHub Desktop.
Tokenize a string in XSLT 1
<?xml version="1.0" encoding="UTF-8"?>
<input fields="One|Two|Three|Four|Five|Agree" values="Answer A|Answer B|Answer C|Answer D|Answer E|Yes"/>
$ xsltproc stylesheet.xslt input.xml
<?xml version="1.0"?>
<Output><FirstField><FieldName>One</FieldName><FieldValue>Answer A</FieldValue></FirstField><LastField><FieldName>Agree</FieldName><FieldValue>Yes</FieldValue></LastField></Output>
<xsl:stylesheet
version="1.1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="ext">
<!-- Tokenize a string that's pipe separated -->
<xsl:template name="tokenize">
<xsl:param name="text"/>
<xsl:param name="separator" select="'|'"/>
<xsl:choose>
<xsl:when test="not(contains($text, $separator))">
<item>
<xsl:value-of select="normalize-space($text)"/>
</item>
</xsl:when>
<xsl:otherwise>
<item>
<xsl:value-of select="normalize-space(substring-before($text, $separator))"/>
</item>
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $separator)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/input">
<!-- Tokenize the 'fields' attribute on /input -->
<xsl:variable name="name-set">
<xsl:call-template name="tokenize">
<xsl:with-param name="text">
<xsl:value-of select="@fields"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<!-- Tokenize the 'values' attribute on /input -->
<xsl:variable name="value-set">
<xsl:call-template name="tokenize">
<xsl:with-param name="text">
<xsl:value-of select="@values"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<!-- Generate our output -->
<Output>
<FirstField>
<FieldName><xsl:copy-of select="ext:node-set($name-set)/item[1]/text()"/></FieldName>
<FieldValue><xsl:copy-of select="ext:node-set($value-set)/item[1]/text()"/></FieldValue>
</FirstField>
<LastField>
<FieldName><xsl:copy-of select="ext:node-set($name-set)/item[last()]/text()"/></FieldName>
<FieldValue><xsl:copy-of select="ext:node-set($value-set)/item[last()]/text()"/></FieldValue>
</LastField>
</Output>
</xsl:template>
</xsl:stylesheet>
@Nico-Amplexor
Copy link

Hi,

Thanks for this code.

Just a remark: I think you forgot to insert $separator parameter when you recursively call tokenize template.
If you don't, it doesn't work if your separator is not a pipe.

               <xsl:otherwise>
			<item>
				<xsl:value-of select="normalize-space(substring-before($text, $separator))"/>
			</item>
			<xsl:call-template name="tokenize">
				<xsl:with-param name="text" select="substring-after($text, $separator)"/>
                                <xsl:with-param name="separator" select="$separator"/>
			</xsl:call-template>
		</xsl:otherwise>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment