|
[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Transform and Sum (Was Re: sum function)
> 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
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|

Cart








