This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Calculate balance
- From: Dimitre Novatchev <dnovatchev at yahoo dot com>
- To: xsl-list at lists dot mulberrytech dot com
- Date: Mon, 11 Mar 2002 11:33:06 -0800 (PST)
- Subject: [xsl] Re: Calculate balance
- Reply-to: xsl-list at lists dot mulberrytech dot com
Using the scanl1 function from the functional programming library FXSL,
the solution to the problem is quite easy:
The following stylesheet:
runningBalance.xsl:
------------------
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:funTypedSum="f:funTypedSum"
exclude-result-prefixes="xsl funTypedSum"
>
<xsl:import href="Fxsl\Msxsl\scanl.xsl"/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<funTypedSum:funTypedSum/>
<xsl:template match="/">
<xsl:variable name="vTypedSum"
select="document('')/*/funTypedSum:*[1]"/>
<xsl:variable name="vList"
select="/report/ledgerbook/table/row/amount"/>
<xsl:variable name="vOpeningBalance"
select="/report/ledgerbook/openingbalance"/>
<xsl:call-template name="scanl">
<xsl:with-param name="pFun" select="$vTypedSum"/>
<xsl:with-param name="pQ0" select="$vOpeningBalance"/>
<xsl:with-param name="pList" select="$vList"/>
<xsl:with-param name="pElName" select="'balance'"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="funTypedSum:*">
<xsl:param name="pArg1"/>
<xsl:param name="pArg2" select="/.."/>
<xsl:variable name="vThisAmount"
select="$pArg2 * ((($pArg2/@type = 'C') * 2) - 1)"/>
<xsl:value-of select="$pArg1 + $vThisAmount"/>
</xsl:template>
</xsl:stylesheet>
when applied on the original xml source document:
runningBalance.xml:
------------------
<report>
<date>
<currentdate>11-Mar-2002</currentdate>
<startdate>12-dec-02</startdate>
<enddate>12-dec-02</enddate>
</date>
<ledgerbook>
<openingbalance>-2000.0</openingbalance>
<table>
<row>
<ledgerdate>12-DEC-2002</ledgerdate>
<voucher>V1.1.3</voucher>
<costcenter>Head Office</costcenter>
<lccode />
<description />
<amount type="C">1000</amount>
</row>
<row>
<ledgerdate>12-DEC-2002</ledgerdate>
<voucher>V1.1.2</voucher>
<costcenter>Head Office</costcenter>
<lccode />
<description />
<amount type="C">1000</amount>
</row>
<row>
<ledgerdate>12-DEC-2002</ledgerdate>
<voucher>V1.2.1</voucher>
<costcenter />
<lccode />
<description />
<amount type="D">2000</amount>
</row>
<row>
<ledgerdate>12-DEC-2002</ledgerdate>
<voucher>V1.2.2</voucher>
<costcenter />
<lccode />
<description />
<amount type="D">2000</amount>
</row>
</table>
</ledgerbook>
</report>
Produces this result:
<balance>-2000.0</balance>
<balance>-1000</balance>
<balance>0</balance>
<balance>-2000</balance>
<balance>-4000</balance>
Hope this helped.
Cheers,
Dimitre Novatchev.
Jeni Tennison <jeni at jenitennison dot com> wrote:
> Hi Shabbir,
>
> >> Or if performance is really an issue, you could take a different
> >> approach in which you step through the rows one by one, with a
> >> template that applies templates to the next row and passes on the
> >> balance from each step. Let us know if you want to see an example
> >> of how that would work.
> >
> > Yes, I want to know that approch.
>
> OK. Currently, you tell the processor to iterate over all the rows at
> once, with an xsl:for-each:
>
> <xsl:for-each select="report/ledgerbook/table/row">
> <tr>
> <td><xsl:value-of select="ledgerdate"/></td>
> <td><xsl:value-of select="voucher"/></td>
> <td><xsl:value-of select="costcenter"/></td>
> <td><xsl:value-of select="lccode"/></td>
> <td><xsl:value-of select="description"/></td>
> <xsl:call-template name="amountplace"/>
> </tr>
> </xsl:for-each>
>
> Rather than do that, you can manually step through them one by one.
> This enables you to pass parameters, keeping track of the current
> balance, from one row to the next.
>
> Instead of the xsl:for-each, then, just apply templates to the first
> row in your table:
>
> <xsl:apply-templates select="report/ledgerbook/table/row[1]" />
>
> Then create a template that matches row elements and takes a
> parameter, $balance, which is originally set to the openingbalance:
>
> <xsl:template match="row">
> <xsl:param name="balance" select="../../openingbalance" />
> ...
> </xsl:template>
>
> Within the template, you can work out the difference between this
> balance and the previous one as I showed in the last email, and
> therefore work out a new balance based on the old one:
>
> <xsl:template match="row">
> <xsl:param name="balance" select="../../openingbalance" />
> <xsl:variable name="difference">
> <xsl:choose>
> <xsl:when test="amount/@type = 'D'">
> <xsl:value-of select="amount * -1" />
> </xsl:when>
> <xsl:otherwise>
> <xsl:value-of select="amount" />
> </xsl:otherwise>
> </xsl:choose>
> </xsl:variable>
> <xsl:variable name="newbalance" select="$balance + $difference" />
> ...
> </xsl:template>
>
> You can use this new balance within the tr element that you
> create:
>
> <xsl:template match="row">
> <xsl:param name="balance" select="../../openingbalance" />
> <xsl:variable name="difference">
> <xsl:choose>
> <xsl:when test="amount/@type = 'D'">
> <xsl:value-of select="amount * -1" />
> </xsl:when>
> <xsl:otherwise>
> <xsl:value-of select="amount" />
> </xsl:otherwise>
> </xsl:choose>
> </xsl:variable>
> <xsl:variable name="newbalance" select="$balance + $difference" />
> <tr>
> <td><xsl:value-of select="ledgerdate"/></td>
> <td><xsl:value-of select="voucher"/></td>
> <td><xsl:value-of select="costcenter"/></td>
> <td><xsl:value-of select="lccode"/></td>
> <td><xsl:value-of select="description"/></td>
> <xsl:call-template name="amountplace"/>
> <td><xsl:value-of select="$newbalance" /></td>
> </tr>
> ...
> </xsl:template>
>
> You can also use it as the value to be passed to the next row that
> you
> process. You need to apply templates to the immediately following row
> within the document, passing the value of the $newbalance variable as
> the value of the $balance parameter, as follows:
>
> <xsl:template match="row">
> <xsl:param name="balance" select="../../openingbalance" />
> <xsl:variable name="difference">
> <xsl:choose>
> <xsl:when test="amount/@type = 'D'">
> <xsl:value-of select="amount * -1" />
> </xsl:when>
> <xsl:otherwise>
> <xsl:value-of select="amount" />
> </xsl:otherwise>
> </xsl:choose>
> </xsl:variable>
> <xsl:variable name="newbalance" select="$balance + $difference" />
> <tr>
> <td><xsl:value-of select="ledgerdate"/></td>
> <td><xsl:value-of select="voucher"/></td>
> <td><xsl:value-of select="costcenter"/></td>
> <td><xsl:value-of select="lccode"/></td>
> <td><xsl:value-of select="description"/></td>
> <xsl:call-template name="amountplace"/>
> <td><xsl:value-of select="$newbalance" /></td>
> </tr>
> <xsl:apply-templates select="following-sibling::row[1]">
> <xsl:with-param name="balance" select="$newbalance" />
> </xsl:apply-templates>
> </xsl:template>
>
> Cheers,
>
> Jeni
>
>
>
>
> __________________________________________________
> Do You Yahoo!?
> Try FREE Yahoo! Mail - the world's greatest free email!
> http://mail.yahoo.com/
__________________________________________________
Do You Yahoo!?
Try FREE Yahoo! Mail - the world's greatest free email!
http://mail.yahoo.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list