Subject: [xsl] Transform and Sum (Was Re: sum function) From: Dimitre Novatchev <dnovatchev@xxxxxxxxx> Date: Fri, 16 Nov 2001 14:08:52 -0800 (PST) |
> How do I use the sum function on xml such as: > > <Amount>12,345.12</Amount> > <Amount>132,345.12</Amount> > <Amount>2,345.12</Amount> > > If I use Total Price = <xsl:value-of select="sum(//Amount)"/> I get the > result NaN. However, if the data does not contain ',' the sum works > correctly. The functional solution to this problem is: transform-and-sum funTrans ls = foldl (add.funTrans) 0 ls In case we already have the XSLT implementation of the above function, we can simply call it, providing as a parameter our own funTrans function: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:func-transform="f:func-transform" exclude-result-prefixes="xsl func-transform" > <xsl:import href="transform-and-sum.xsl"/> <xsl:output method="text"/> <func-transform:func-transform/> <xsl:template match="/"> <xsl:call-template name="transform-and-sum"> <xsl:with-param name="pFuncTransform" select="document('')/*/func-transform:*[1]"/> <xsl:with-param name="pList" select="/*/*"/> </xsl:call-template> </xsl:template> <xsl:template match="func-transform:*"> <xsl:param name="arg" select="0"/> <xsl:value-of select="translate($arg, ',', '')"/> </xsl:template> </xsl:stylesheet> And in case the source xml doc is the following: <t> <Amount>12,345.12</Amount> <Amount>132,345.12</Amount> <Amount>2,345.12</Amount> </t> we get the result: 147035.36 We can even implement our own eliminateCommas function, although this would be much less efficient than using translate() directly. Why would we implement transform-and-sum for such seemingly very simple case? The answer is: because once implemented, it can be re-used to solve many other problems, some of them quite complex, for which direct XSLT support (like translate()) is not available. Here's an example: find the sum of hexadecimal numbers. We're using the same function transform-and-sum, passing to it this time another function as parameter -- this one converts the hexadecimal representation of a number into its decimal representation. here's how the code looks like in this case: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:func-transform2="f:func-transform2" exclude-result-prefixes="xsl func-transform2" > <xsl:import href="transform-and-sum.xsl"/> <xsl:import href="hex-to-decimal.xsl"/> <xsl:output method="text"/> <func-transform2:func-transform2/> <xsl:template match="/"> <xsl:call-template name="transform-and-sum"> <xsl:with-param name="pFuncTransform" select="document('')/*/func-transform2:*[1]"/> <xsl:with-param name="pList" select="/*/*"/> </xsl:call-template> </xsl:template> <xsl:template match="func-transform2:*"> <xsl:param name="arg" select="0"/> <xsl:call-template name="hex-to-decimal"> <xsl:with-param name="pxNumber" select="$arg"/> </xsl:call-template> </xsl:template> </xsl:stylesheet> This, when applied to the following xml source doc: <t> <Amount>4000</Amount> <Amount>1000</Amount> </t> Gives the following result: 20480 Now, here's the code of the more interesting functions "transform-and-sum" and "hex-to-decimal": transform-and-sum.xsl: --------------------- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:sum-fold-func="f:sum-fold-func" exclude-result-prefixes="xsl sum-fold-func" > <xsl:import href="foldl.xsl"/> <sum-fold-func:sum-fold-func/> <xsl:template name="transform-and-sum"> <xsl:param name="pFuncTransform" select="/.."/> <xsl:param name="pList" select="/.."/> <xsl:variable name="vrtfFoldFun"> <sum-fold-func:sum-fold-func/> <xsl:copy-of select="$pFuncTransform"/> </xsl:variable> <xsl:call-template name="foldl"> <xsl:with-param name="pFunc" select="msxsl:node-set($vrtfFoldFun)/*"/> <xsl:with-param name="pList" select="$pList"/> <xsl:with-param name="pA0" select="0"/> </xsl:call-template> </xsl:template> <xsl:template name="add" match="sum-fold-func:*"> <xsl:param name="arg0" select="/.."/> <xsl:param name="arg1" select="0"/> <xsl:param name="arg2" select="0"/> <xsl:variable name="vPartialCompose"> <xsl:apply-templates select="$arg0"> <xsl:with-param name="arg" select="$arg2"/> </xsl:apply-templates> </xsl:variable> <xsl:value-of select="$arg1 + $vPartialCompose"/> </xsl:template> </xsl:stylesheet> hex-to-decimal.xsl: ------------------ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:hex-converter="f:hex-converter" > <xsl:import href="str-foldl.xsl"/> <hex-converter:hex-converter/> <xsl:variable name="hexDigits" select="'0123456789ABCDEF'"/> <xsl:template name="hex-to-decimal"> <xsl:param name="pxNumber"/> <xsl:variable name="vFunXConvert" select="document('')/*/hex-converter:*[1]"/> <xsl:call-template name="str-foldl"> <xsl:with-param name="pFunc" select="$vFunXConvert"/> <xsl:with-param name="pA0" select="0"/> <xsl:with-param name="pStr" select="$pxNumber"/> </xsl:call-template> </xsl:template> <xsl:template match="hex-converter:*"> <xsl:param name="arg1"/> <!-- $pA0 --> <xsl:param name="arg2"/> <!-- a char (digit) --> <xsl:value-of select="16 * $arg1 + string-length(substring-before($hexDigits, $arg2))"/> </xsl:template> </xsl:stylesheet> As usual, these functions use either "foldl" or "str-foldl" to perform any necessary generic list-folding operations (respectively on a list of nodes, or on a string (list of characters)). The XSLT implementations of "foldl" and "str-foldl" have been already provided at: http://sources.redhat.com/ml/xsl-list/2001-11/msg00214.html and http://sources.redhat.com/ml/xsl-list/2001-11/msg00488.html Cheers, Dimitre Novatchev. __________________________________________________ Do You Yahoo!? Find the one for you at Yahoo! Personals http://personals.yahoo.com XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] the last substring, Jeff Beadle | Thread | [xsl] particular parameter , g.carlone@xxxxxxxxx |
Re: [xsl] the last substring, Jörg Heinicke | Date | Re: [xsl] the last substring, yan bai |
Month |