开发者

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>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜