I want to split an address on semicolons (;
) into rows separated by <br />
:
e.g. if address
=123 Elm Street
, I want to output 123 Elm Street
,
but if address
=123 Elm Street;PO Box 222
, I want to output
123 Elm Street<br />PO Box 222
and if address
=123 Elm Street;PO Box 222;c/o James Jones
, I want to output
123 Elm Street<br />PO Box 222<br />c/o James Jones
Is there a way to do this? (probably easy but I'm not that familiar with XSLT)
The plain XSL selector is
<xsl:value-of select="address"/>
and I would like to modify this XSLT fragment to split on semicolon.
update: Apparently the answer involves the use of <xsl:call-template>
and the functions substring-before()
and substring-after()
.
But I'm a beginner to XSLT and I could really use some help for how to do this.
Substring is primarily used to return a section of a string or truncating a string with the help of the length provided. XSLT is incorporated with XPath while manipulating strings of text when XSLT access. The Substring function takes a string as an argument with the numbers one or two and an optional length.
substring-after() Function — Returns the substring of the first argument after the first occurrence of the second argument in the first argument. If the second argument does not occur in the first argument, the substring-after() function returns an empty string.
XSLT/XPath Reference: XSLT elements, EXSLT functions, XPath functions, XPath axes. str:tokenize() splits a string using a set of characters as delimiters that determine where the splits should occur, returning a node-set containing the resulting strings.
Used to construct arbitrary sequences. It may select any sequence of nodes and/or atomic values, and essentially adds these to the result sequence.
I. Plain XSLT 1.0 solution:
This transformation:
<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="split"> <xsl:param name="pText" select="."/> <xsl:if test="string-length($pText)"> <xsl:if test="not($pText=.)"> <br /> </xsl:if> <xsl:value-of select= "substring-before(concat($pText,';'),';')"/> <xsl:call-template name="split"> <xsl:with-param name="pText" select= "substring-after($pText, ';')"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet>
when applied on this XML document:
<t>123 Elm Street;PO Box 222;c/o James Jones</t>
produces the wanted, corrected result:
123 Elm Street<br />PO Box 222<br />c/o James Jones
II. FXSL 1 (for XSLT 1.0):
Here we just use the FXSL template str-map
(and do not have to write recursive template for the 999th time):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://fxsl.sf.net/" xmlns:testmap="testmap" exclude-result-prefixes="xsl f testmap" > <xsl:import href="str-dvc-map.xsl"/> <testmap:testmap/> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/"> <xsl:variable name="vTestMap" select="document('')/*/testmap:*[1]"/> <xsl:call-template name="str-map"> <xsl:with-param name="pFun" select="$vTestMap"/> <xsl:with-param name="pStr" select= "'123 Elm Street;PO Box 222;c/o James Jones'"/> </xsl:call-template> </xsl:template> <xsl:template name="replace" mode="f:FXSL" match="*[namespace-uri() = 'testmap']"> <xsl:param name="arg1"/> <xsl:choose> <xsl:when test="not($arg1=';')"> <xsl:value-of select="$arg1"/> </xsl:when> <xsl:otherwise><br /></xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
when this transformation is applied on any XML document (not used), the same, wanted correct result is produced:
123 Elm Street<br/>PO Box 222<br/>c/o James Jones
III. Using XSLT 2.0
<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="text()"> <xsl:for-each select="tokenize(.,';')"> <xsl:sequence select="."/> <xsl:if test="not(position() eq last())"><br /></xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet>
when this transformation is applied on this XML document:
<t>123 Elm Street;PO Box 222;c/o James Jones</t>
the wanted, correct result is produced:
123 Elm Street<br />PO Box 222<br />c/o James Jones
If your XSLT processor supports EXSLT, you can use str:tokenize, otherwise, the link contains an implementation using functions like substring-before.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With