Subject: [xsl] Re: Calculate balance From: Dimitre Novatchev <dnovatchev@xxxxxxxxx> Date: Mon, 11 Mar 2002 11:33:06 -0800 (PST) |
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
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] multilple row/col xsl->fo, Mathy V Arumugam | Thread | [xsl] (re-)calculating attribute va, Christian Timmerer |
RE: [xsl] [xml]characters not compa, Michael Kay | Date | RE: [xsl] [xml]characters not compa, Joshua Allen |
Month |