Selecting a last word from a string in xslt - xslt

I just want to take the last element from a string which is like this "aaa-bbb-ccc-ddd" in xslt.
Out put should be "ddd" irrecspective of '-'s.

XSLT/Xpath 2.0 - using the tokenize() function to split the string on the "-" and then use a predicate filter to select the last item in the sequence:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="tokenize('aaa-bbb-ccc-ddd','-')[last()]"/>
</xsl:template>
</xsl:stylesheet>
XSLT/XPath 1.0 - using a recursive template to look for the last occurrence of "-" and selecting the substring following it:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:call-template name="substring-after-last">
<xsl:with-param name="input" select="'aaa-bbb-ccc-ddd'" />
<xsl:with-param name="marker" select="'-'" />
</xsl:call-template>
</xsl:template>
<xsl:template name="substring-after-last">
<xsl:param name="input" />
<xsl:param name="marker" />
<xsl:choose>
<xsl:when test="contains($input,$marker)">
<xsl:call-template name="substring-after-last">
<xsl:with-param name="input"
select="substring-after($input,$marker)" />
<xsl:with-param name="marker" select="$marker" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$input" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

Related

XSLT 1.0 to remove leading and trailing spaces

I have to remove leading and trailing spaces using XSL 1.0
cannot use normalize-space for this .
and tried the below code
<xsl:template match="text()">
<xsl:value-of select="replace(.,'^\s+|\s+$','')"/>
</xsl:template>
before commands to start the actual mapping
but does not help
how to achieve this ?
Well, in XSLT 1.0, you can use recursive template (NOT preferable) method to remove leading and trailing spaces (In case you don't want to use normalize-space())
Let's assume your input as following:
<?xml version="1.0" encoding="UTF-8"?>
<body>
<h1> A text having so many leading and trailing spaces! </h1>
</body>
Note: The below solution uses xmlns:str="xalan://org.apache.commons.lang.StringUtils" to use it's two functions ends-with and substringBeforeLast
An XSLT 1.0 solution to achieve the task:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="xalan://org.apache.commons.lang.StringUtils"
exclude-result-prefixes="str">
<xsl:output method="xml" indent="yes" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="h1">
<h1>
<xsl:variable name="leadingSpaceRemoved">
<xsl:call-template name="removeLeadingSpace">
<xsl:with-param name="text" select="." />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="trailingSpaceRemoved">
<xsl:call-template name="removeTrailingSpace">
<xsl:with-param name="text" select="$leadingSpaceRemoved" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$trailingSpaceRemoved" />
</h1>
</xsl:template>
<xsl:template name="removeLeadingSpace">
<xsl:param name="text" />
<xsl:variable name="h1" select="$text" />
<xsl:choose>
<xsl:when test="starts-with($h1,' ')">
<xsl:call-template name="removeLeadingSpace">
<xsl:with-param name="text" select="substring-after($h1,' ')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$h1" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="removeTrailingSpace">
<xsl:param name="text" />
<xsl:variable name="h1" select="$text" />
<xsl:choose>
<xsl:when test="str:ends-with($h1,' ')">
<xsl:call-template name="removeTrailingSpace">
<xsl:with-param name="text" select="str:substringBeforeLast($h1,' ')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$h1" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Also, if you can call a java library/class in your environment, it will be more easier to achieve the same as below:
Your XSLT would be:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:stringparser="xalan://com.example.commons.xsl.StringUtil"
exclude-result-prefixes="stringparser">
<xsl:output method="xml" indent="yes" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="h1">
<h1>
<xsl:value-of select="stringparser:trim(.)" />
</h1>
</xsl:template>
</xsl:stylesheet>
And the StringUtil.java would be:
import org.apache.commons.lang.StringUtils;
public class StringUtil {
/**
*
* #param input
* #return remove leading and trailing spaces.
*/
public static String trim(final String input) {
if (StringUtils.isNotBlank(input)) {
return input.trim();
}
return input;
}
}
One of possible solutions is to use normalize-space()
function (works even in XSLT 1.0).
It does even more, i.e. it replaces multiple white chars inside
with a single space.
To apply it to all text nodes, add such a template:
<xsl:template match="text()">
<xsl:value-of select="normalize-space()"/>
</xsl:template>
But if you have also the identity template, the above template
must be in your script after the identity template.

String Split to new Elements using XSL 1.0

Can any guide me to split the given xml element values into multiple child elements based on a token. Here is my sample input xml and desired output. I have a limitation to use xsl 1.0. Thank you.
Input XML:
<?xml version='1.0' encoding='UTF-8'?>
<SQLResults>
<SQLResult>
<ACTION1>Action1</ACTION1>
<ACTION2>Action2</ACTION2>
<Encrypt>Program=GPG;Code=23FCS;</Encrypt>
<SENDER>Program=WebPost;Protocol=WS;Path=/home/Inbound</SENDER>
</SQLResult>
</SQLResults>
Output XML:
<?xml version='1.0' encoding='UTF-8'?>
<SQLResults>
<SQLResult>
<ACTION1>Action1</ACTION1>
<ACTION2>Action2</ACTION2>
<Encrypt>
<Program>GPG</Program>
<Code>23FCS</Code>
</Encrypt>
<SENDER>
<Program>Action4</Program>
<Protocol>WS</Protocol>
<Path>/home/Inbound</Path>
</SENDER>
</SQLResult>
</SQLResults>
In XSLT 2 it would be easy, just with the following template:
<xsl:template match="Encrypt|SENDER">
<xsl:copy>
<xsl:analyze-string select="." regex="(\w+)=([\w/]+);?">
<xsl:matching-substring>
<element name="{regex-group(1)}">
<xsl:value-of select="regex-group(2)"/>
</element>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:copy>
</xsl:template>
Because you want to do it in XSLT 1, you have to express it another way.
Instead of analyze-string you have to:
Tokenize the content into non-empty tokens contained between ; chars.
You have to add tokenize template.
Each such token divide into 2 substrings, before and after = char.
Create an element with the name equal to the first substring.
Write the content of this element - the second substring.
XSLT 1 has also such limitation that the result of the tokenize template
is a result tree fragment (RTF) not the node set and thus it cannot be
used in XPath expressions.
To circumvent this limitation, you must use exsl:node-set function.
So the whole script looks like below:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="Encrypt|SENDER">
<xsl:copy>
<xsl:variable name="tokens">
<xsl:call-template name="tokenize">
<xsl:with-param name="txt" select="."/>
<xsl:with-param name="delim" select="';'"/>
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="exsl:node-set($tokens)/token">
<xsl:variable name="t1" select="substring-before(., '=')"/>
<xsl:variable name="t2" select="substring-after(., '=')"/>
<xsl:element name="{$t1}">
<xsl:value-of select="$t2" />
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="txt" />
<xsl:param name="delim" select="' '" />
<xsl:choose>
<xsl:when test="$delim and contains($txt, $delim)">
<token>
<xsl:value-of select="substring-before($txt, $delim)" />
</token>
<xsl:call-template name="tokenize">
<xsl:with-param name="txt" select="substring-after($txt, $delim)" />
<xsl:with-param name="delim" select="$delim" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$txt">
<token><xsl:value-of select="$txt" /></token>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
</xsl:transform>

XSLT 1.0 eliminate duplicates and split comma separated string [duplicate]

I would like to ask if there is a function that can be use to to remove a duplicate value inside a string separated by | simplest possible way. I have below example of the string
1111-1|1111-1|1111-3|1111-4|1111-5|1111-3
the output that I'm expecting is:
1111-1|1111-3|1111-4|1111-5
Thanks in advance.
All presented XSLT 1.0 solutions so far produce the wrong result:
1111-1|1111-4|1111-5|1111-3
whereas the wanted, correct result is:
1111-1|1111-3|1111-4|1111-5
Now, the following transformation (no extensions, pure XSLT 1.0):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="text()" name="distinctSubstrings">
<xsl:param name="pText" select="."/>
<xsl:param name="poutDelim"/>
<xsl:param name="pFoundDistinctSubs" select="'|'"/>
<xsl:param name="pCountDistinct" select="0"/>
<xsl:if test="$pText">
<xsl:variable name="vnextSub" select="substring-before(concat($pText, '|'), '|')"/>
<xsl:variable name="vIsNewDistinct" select=
"not(contains(concat($pFoundDistinctSubs, '|'), concat('|', $vnextSub, '|')))"/>
<xsl:variable name="vnextDistinct" select=
"substring(concat($poutDelim,$vnextSub), 1 div $vIsNewDistinct)"/>
<xsl:value-of select="$vnextDistinct"/>
<xsl:variable name="vNewFoundDistinctSubs"
select="concat($pFoundDistinctSubs, $vnextDistinct)"/>
<xsl:variable name="vnextOutDelim"
select="substring('|', 2 - ($pCountDistinct > 0))"/>
<xsl:call-template name="distinctSubstrings">
<xsl:with-param name="pText" select="substring-after($pText, '|')"/>
<xsl:with-param name="pFoundDistinctSubs" select="$vNewFoundDistinctSubs"/>
<xsl:with-param name="pCountDistinct" select="$pCountDistinct + $vIsNewDistinct"/>
<xsl:with-param name="poutDelim" select="$vnextOutDelim"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document (with string value the provided string in the question):
<t>1111-1|1111-1|1111-3|1111-4|1111-5|1111-3</t>
produces the wanted, correct result:
1111-1|1111-3|1111-4|1111-5
Explanation:
All found distinct substrings are concatenated in the parameter $pFoundDistinctSubs -- whenever we get the next substring from the delimited input, we compare it to the distinct substrings passed in this parameter. This ensures that the first in order distinct substring will be output -- not the last as in the other two solutions.
We use conditionless value determination, based on the fact that XSLT 1.0 implicitly converts a Boolean false() to 0 and true() to 1 whenever it is used in a context that requires a numeric value. In particular, substring($x, 1 div true()) is equivalent to substring($x, 1 div 1) that is: substring($x, 1) and this is the entire string $x. On the other side, substring($x, 1 div false()) is equivalent to substring($x, 1 div 0) -- that is: substring($x, Infinity) and this is the empty string.
To know why avoiding conditionals is important: watch this Pluralsight course:
Tactical Design Patterns in .NET: Control Flow, by Zoran Horvat
To do this in pure XSLT 1.0, with no extension functions, you will need to use a recursive named template:
<xsl:template name="distinct-values-from-list">
<xsl:param name="list"/>
<xsl:param name="delimiter" select="'|'"/>
<xsl:choose>
<xsl:when test="contains($list, $delimiter)">
<xsl:variable name="token" select="substring-before($list, $delimiter)" />
<xsl:variable name="next-list" select="substring-after($list, $delimiter)" />
<!-- output token if it is unique -->
<xsl:if test="not(contains(concat($delimiter, $next-list, $delimiter), concat($delimiter, $token, $delimiter)))">
<xsl:value-of select="concat($token, $delimiter)"/>
</xsl:if>
<!-- recursive call -->
<xsl:call-template name="distinct-values-from-list">
<xsl:with-param name="list" select="$next-list"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$list"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Full demo: http://xsltransform.net/ncdD7mM
Added:
The above method outputs the last occurrence of each value in the list, because that's the simplest way to remove the duplicates.
The side effect of this is that the original order of the values is not preserved. Or - more correctly - it is the reverse order that is being preserved.
I would not think preserving the original forward order is of any importance here. But in case you do need it, it could be done this way (which I believe is much easier to follow than the suggested alternative):
<xsl:template name="distinct-values-from-list">
<xsl:param name="list"/>
<xsl:param name="delimiter" select="'|'"/>
<xsl:param name="result"/>
<xsl:choose>
<xsl:when test="$list">
<xsl:variable name="token" select="substring-before(concat($list, $delimiter), $delimiter)" />
<!-- recursive call -->
<xsl:call-template name="distinct-values-from-list">
<xsl:with-param name="list" select="substring-after($list, $delimiter)"/>
<xsl:with-param name="result">
<xsl:value-of select="$result"/>
<!-- add token if this is its first occurrence -->
<xsl:if test="not(contains(concat($delimiter, $result, $delimiter), concat($delimiter, $token, $delimiter)))">
<xsl:value-of select="concat($delimiter, $token)"/>
</xsl:if>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($result, 2)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Assuming that you can use XSLT 2.0, and assuming that the input looks like
<?xml version="1.0" encoding="UTF-8"?>
<root>1111-1|1111-1|1111-3|1111-4|1111-5|1111-3</root>
you could use the distinct-values and tokenize functions:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/root">
<result>
<xsl:value-of separator="|" select="distinct-values(tokenize(.,'\|'))"/>
</result>
</xsl:template>
</xsl:transform>
And the result will be
<?xml version="1.0" encoding="UTF-8"?>
<result>1111-1|1111-3|1111-4|1111-5</result>
I have adapted a stylesheet below from (XSLT 1.0 How to get distinct values)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="/">
<output>
<xsl:call-template name="distinctvalues">
<xsl:with-param name="values" select="root"/>
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="distinctvalues">
<xsl:param name="values"/>
<xsl:variable name="firstvalue" select="substring-before($values, '|')"/>
<xsl:variable name="restofvalue" select="substring-after($values, '|')"/>
<xsl:if test="not(contains($values, '|'))">
<xsl:value-of select="$values"/>
</xsl:if>
<xsl:if test="contains($restofvalue, $firstvalue) = false">
<xsl:value-of select="$firstvalue"/>
<xsl:text>|</xsl:text>
</xsl:if>
<xsl:if test="$restofvalue != ''">
<xsl:call-template name="distinctvalues">
<xsl:with-param name="values" select="$restofvalue" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
with a sample input of:
<root>1111-1|1111-1|1111-3|1111-4|1111-5|1111-3</root>
and the output is
<output>1111-1|1111-4|1111-5|1111-3</output>
**** EDIT ****
per Michael's comment below, here is the revised stylesheet which uses a saxon extension:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:saxon="http://icl.com/saxon"
exclude-result-prefixes="saxon"
version="1.1">
<xsl:output omit-xml-declaration="yes"/>
<xsl:variable name="aaa">
<xsl:call-template name="tokenizeString">
<xsl:with-param name="list" select="root"/>
<xsl:with-param name="delimiter" select="'|'"/>
</xsl:call-template>
</xsl:variable>
<xsl:template match="/">
<xsl:for-each select="saxon:node-set($aaa)/token[not(preceding::token/. = .)]">
<xsl:if test="position() > 1">
<xsl:text>|</xsl:text>
</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
<xsl:template name="tokenizeString">
<!--passed template parameter -->
<xsl:param name="list"/>
<xsl:param name="delimiter"/>
<xsl:choose>
<xsl:when test="contains($list, $delimiter)">
<token>
<!-- get everything in front of the first delimiter -->
<xsl:value-of select="substring-before($list,$delimiter)"/>
</token>
<xsl:call-template name="tokenizeString">
<!-- store anything left in another variable -->
<xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$list = ''">
<xsl:text/>
</xsl:when>
<xsl:otherwise>
<token>
<xsl:value-of select="$list"/>
</token>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
given an input of:
<root>cat|cat|catalog|catalog|red|red|wired|wired</root>
it outputs
cat|catalog|red|wired
and with this input:
<root>1111-1|1111-1|1111-3|1111-4|1111-5|1111-3</root>
the output is
1111-1|1111-3|1111-4|1111-5

XSL to capture URL Params

Not able to extract the params using XSLT,
for eg.: http://www.example.com/AB/100/123456/09/8
using XSLT need to extract like var1=AB, Var2=100, Var3=123456, var4=09, var5=8, All the params are mandatory. and var3 can accept 1-999999, could somebody share some ideas
tried Substring but it didn't help much
Though the input is not clear, just as example: given an input XML
<root>
<url>http://www.example.com/AB/100/123456/09/8</url>
</root>
following XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="url">
<xsl:call-template name="parse">
<xsl:with-param name="url" select="substring-after(.,'//')" />
<xsl:with-param name="position" select="1" />
</xsl:call-template>
</xsl:template>
<xsl:template name="parse">
<xsl:param name="url" />
<xsl:param name="position" />
<xsl:choose>
<xsl:when test="contains(substring-after($url, '/'),'/')">
<xsl:value-of select="concat('Var', $position, ': ')" />
<xsl:value-of select="substring-before(substring-after($url, '/'),'/')" />
<xsl:text>, </xsl:text>
<xsl:call-template name="parse">
<xsl:with-param name="url" select="substring-after($url, '/')" />
<xsl:with-param name="position" select="$position + 1" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('Var', $position, ': ')" />
<xsl:value-of select="substring-after($url,'/')" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:transform>
produces the ouput
Var1: AB, Var2: 100, Var3: 123456, Var4: 09, Var5: 8
using the template parse which recursively calls itself when the url contains a /.
For every call the parameter url is reduced using substring-after() and the parameter position is incremented.

Adding numbers in a string using XSLT

I have a string (in a variable) that has a list of numbers separated by space or comma.
I need to sum the numbers in the string.
example string "1,2,5,12,3"
or "1 2 5 12 3"
Is there a way to add the numbers within the string and return the total?
This much shorter transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="text()" name="sumStringList">
<xsl:param name="pText" select="."/>
<xsl:param name="pSum" select="0"/>
<xsl:param name="pDelim" select="','"/>
<xsl:choose>
<xsl:when test="not(string-length($pText) >0)">
<xsl:value-of select="$pSum"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vnewList"
select="concat($pText,$pDelim)"/>
<xsl:variable name="vHead" select=
"substring-before($vnewList, $pDelim)"/>
<xsl:call-template name="sumStringList">
<xsl:with-param name="pText" select=
"substring-after($pText, $pDelim)"/>
<xsl:with-param name="pSum" select="$pSum+$vHead"/>
<xsl:with-param name="pDelim" select="$pDelim"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
when applied on the following XML document:
<t>1,2,5,12,3</t>
produces the wanted, correct result:
23
Explanation: Recursively called named template that also matches a text node. A sentinel (appended comma) is added to speed up and streamline processing.
II. XSLT 2.0 solution:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:param name="pDelim" select="','"/>
<xsl:template match="text()">
<xsl:sequence select=
"sum(for $s in tokenize(.,$pDelim)
return number($s)
)
"/>
</xsl:template>
</xsl:stylesheet>
When applied on the same XML document (above), this transformation produces the same wanted, correct answer:
23
Here we use the standard XPath 2.0 function tokenize() and we must convert every resulting token to number (using the number() function) before finally applying the standard XPath function sum().
I don't know XSLT, but generally you would split the string using spaces and commas as separators.
After a quick search I found that you can use tokenize(string, separator) as the split function if you are using XSLT 2.0. This page has an example on how to use tokenize.
Here is an XSLT 1.0 solution
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<xsl:variable name="listOfValues" select="'1,2,5,12,3'" />
<xsl:call-template name="splitAndAdd">
<xsl:with-param name="list" select="$listOfValues"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="splitAndAdd">
<xsl:param name="list" />
<xsl:param name="delimiter" select="','"/>
<xsl:param name="total" select="0" />
<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="token"
select="substring-before($newList, $delimiter)" />
<xsl:variable name="remaining"
select="normalize-space(substring-after($newList, $delimiter))" />
<xsl:variable name="newTotal" select="$total + number($token)" />
<xsl:choose>
<xsl:when test="$remaining">
<xsl:call-template name="splitAndAdd">
<xsl:with-param name="delimiter" select="$delimiter"/>
<xsl:with-param name="list" select="$remaining"/>
<xsl:with-param name="total" select="$newTotal" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$newTotal" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>