<...">

Summing decimal separator numbers in XSLT?

I have an XML file where the number is separated by commas

<foo> <bar val="1,23"/> <bar val="4,56"/> <bar val="7,89"/> </foo> 

I would like to make a sum over the values ​​of /foo/bar/@val in XSLT, but I'm a bit stuck in formatting. Does anyone know what the correct syntax will be?

+2
source share
3 answers

I assume that the value specified in the "val" attribute is a number that has a comma instead of a decimal point.

Several solutions are possible :

I. XSLT 1.0

This conversion is:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common" > <xsl:output method="text"/> <!-- --> <xsl:template match="foo"> <xsl:variable name="vrtfBars"> <xsl:for-each select="bar"> <bar val="{translate(@val, ',', '.')}"/> </xsl:for-each> </xsl:variable> <!-- --> <xsl:value-of select= "sum(ext:node-set($vrtfBars)/*/@val)"/> </xsl:template> </xsl:stylesheet> 

when applied to the original XML document :

 <foo> <bar val="1,23"/> <bar val="4,56"/> <bar val="7,89"/> </foo> 

creates the desired result :

 13.68 

II. XSLT 2.0

This conversion is :

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="f xs" > <xsl:output method="text"/> <!-- --> <xsl:template match="foo"> <xsl:sequence select= "sum(bar/@val/number(translate(., ',', '.')))" /> </xsl:template> </xsl:stylesheet> 

when applied to the same XML document, it gives the same correct result :

13.68

III. FXSL 2.x

This conversion is :

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:f="http://fxsl.sf.net/" xmlns:my="my:fun" exclude-result-prefixes="my f xs" > <xsl:import href="../f/func-transform-and-sum.xsl"/> <!-- --> <xsl:output method="text"/> <!-- --> <xsl:template match="foo"> <xsl:sequence select= "sum( f:transform-and-sum(my:makeNum(), bar/@val ) )" /> </xsl:template> <!-- --> <xsl:function name="my:makeNum" as="xs:double"> <xsl:param name="psNum" as="xs:string"/> <!-- --> <xsl:sequence select="number(translate($psNum, ',', '.'))"/> </xsl:function> <!-- --> <xsl:function name="my:makeNum" as="element()"> <my:makeNum/> </xsl:function> <!-- --> <xsl:template match="my:makeNum" as="xs:double" mode="f:FXSL"> <xsl:param name="arg1" as="xs:string"/> <!-- --> <xsl:sequence select="my:makeNum($arg1)"/> </xsl:template> </xsl:stylesheet> 

when applied to the same XML document, it gives the same correct result :

13.68

The latter solution is more flexible and can be successfully used when a more complicated conversion of values ​​is required before summing.

+6
source

Assuming the same as Dimitre, you mean that the comma is used as a decimal separator, and not as a separator for a list of integers.

Pure XSLT 1.0 without the EXSLT node extension:

 <xsl:template match="foo"> <xsl:call-template name="sum"> <xsl:with-param name="node" select="bar[1]"/> </xsl:call-template> </xsl:template> <xsl:template name="sum"> <xsl:param name="node"/> <xsl:param name="sum" select="0"/> <xsl:choose> <xsl:when test="$node"> <xsl:call-template name="sum"> <xsl:with-param name="node" select="$node/following-sibling::bar[1]"/> <xsl:with-param name="sum" select="$sum + translate($node/@val, ',', '.')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$sum"/> </xsl:otherwise> </xsl:choose> </xsl:template> 
+3
source

It seems to me that I say this a lot, but he repeats: the whole point of XML is that it provides data in an easily parsed form. XML, which contains data that cannot be parsed as XML, makes no sense; if at all possible, you should either fix your XML or use a different format.

+2
source

All Articles