[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: RE: Is xsl:for-each "syntactic sugar"?
On Fri, May 7, 2010 at 3:34 PM, Costello, Roger L. <costello@xxxxxxxxx> wrote: > Hi Folks, > > Suppose that I want to write an XSLT transform that outputs a bank account balance after each debit/credit transaction. Here's an XML document that has the start balance followed by each transaction: > > <?xml version="1.0"?> > <BankTransactions> > B B <StartBalance>100.00</StartBalance> > B B <Transaction>-5.00</Transaction> > B B <Transaction>-2.50</Transaction> > B B <Transaction>10.00</Transaction> > B B <Transaction>-7.50</Transaction> > </BankTransactions> > > The output should be: > > 95 92.5 102.5 95 > > I do not believe that this task can be accomplished using xsl:for-each. Do you agree? Here is a solution using the f:scanl() function of FXSL. The complexity of the implemented algorithm is O(N) and I don't believe that this linear algorithm can be expressed with <xsl:for-each>. The function f:scanl() is very similar to f:foldl(), but at each application of the parameter-function, the intermediate result is also output. <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://fxsl.sf.net/" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs f" > <xsl:import href="../f/func-scanlDVC.xsl"/> <xsl:import href="../f/func-Operators.xsl"/> <!-- To be applied on testFunc-scanlDVC4.xml --> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/*"> <xsl:sequence select="f:scanl(f:add(), 0, *)"/> </xsl:template> </xsl:stylesheet> Result: 0 100 95 92.5 102.5 95 As can be seen from the code of the function in the CVS of FXSL (at: http://fxsl.cvs.sourceforge.net/viewvc/fxsl/fxsl-xslt2/f/func-scanl.xsl?revis ion=1.1&view=markup) the function is recursive: 1 <xsl:stylesheet version="2.0" 2 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 3 xmlns:f="http://fxsl.sf.net/" 4 exclude-result-prefixes="f" 5 > 6 <xsl:import href="func-apply.xsl"/> 7 8 <xsl:function name="f:scanl"> 9 <xsl:param name="pFunc" as="element()"/> 10 <xsl:param name="pA0"/> 11 <xsl:param name="pList" as="item()*"/> 12 13 <xsl:sequence select= 14 "$pA0, 15 (if (exists($pList)) 16 then 17 f:scanl($pFunc, 18 f:apply($pFunc, $pA0, $pList[1]), 19 $pList[position() > 1] 20 ) 21 else () 22 )" 23 /> 24 </xsl:function> 25 26 <xsl:function name="f:scanl1"> 27 <xsl:param name="pFun" as="element()"/> 28 <xsl:param name="pList" as="item()+"/> 29 30 <xsl:sequence select="f:scanl($pFun, $pList[1], $pList[position() > 1])"/> 31 </xsl:function> 32 </xsl:stylesheet> A DVC-recursive variant is also in the library, but its code is twice as long and not so easily readable. -- Cheers, Dimitre Novatchev --------------------------------------- Truly great madness cannot be achieved without significant intelligence. --------------------------------------- To invent, you need a good imagination and a pile of junk ------------------------------------- Never fight an inanimate object ------------------------------------- You've achieved success in your field when you don't know whether what you're doing is work or play > > Below are two implementations. The first implementation uses a recursive function. The second uses xsl:apply-templates to recursively fire a template. Which implementation is better? Why? Is there a better implementation than the two shown below? B /Roger > > ---------------------------------------------- > IMPLEMENTATION #1: Uses Recursive Function > ---------------------------------------------- > <?xml version="1.0" encoding="US-ASCII"?> > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > B B B B B B B B xmlns:ex="http://www.example.org" > B B B B B B B B version="2.0"> > > B B <xsl:output method="text" encoding="US-ASCII" /> > > > B B <xsl:function name="ex:Balance"> > B B B B <xsl:param name="starting-balance" /> > B B B B <xsl:param name="transactions" /> > > B B B B <xsl:choose> > B B B B B B <xsl:when test="empty($transactions)" /> > B B B B B B <xsl:otherwise> > B B B B B B B B <xsl:sequence select="$starting-balance + $transactions[1]" /> > B B B B B B B B <xsl:sequence select="ex:Balance($starting-balance + $transactions[1], $transactions[position() gt 1])" /> > B B B B B B </xsl:otherwise> > B B B B </xsl:choose> > B B </xsl:function> > > B B <xsl:template match="BankTransactions"> > B B B B <xsl:sequence select="ex:Balance(StartBalance, (Transaction))" /> > B B </xsl:template> > > </xsl:stylesheet> > > -------------------------------------------------------------------------- > IMPLEMENTATION #2: Uses xsl:apply-templates to Recursively Fire a Template > -------------------------------------------------------------------------- > <?xml version="1.0" encoding="US-ASCII"?> > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > B B B B B B B B version="2.0"> > > B B <xsl:output method="text" encoding="US-ASCII" /> > > > B B <xsl:template match="BankTransactions"> > B B B B <xsl:apply-templates select="Transaction[1]"> > B B B B B B <xsl:with-param name="starting-balance" select="data(StartBalance)" /> > B B B B </xsl:apply-templates> > B B </xsl:template> > > > B B <xsl:template match="Transaction"> > B B B B <xsl:param name="starting-balance" /> > > B B B B <xsl:sequence select="$starting-balance + data(.)" /> > > B B B B <xsl:if test="following-sibling::Transaction"> > B B B B B B <xsl:apply-templates select="following-sibling::Transaction[1]"> > B B B B B B B B <xsl:with-param name="starting-balance" select="$starting-balance + data(.)" /> > B B B B B B </xsl:apply-templates> > B B B B </xsl:if> > B B </xsl:template> > > </xsl:stylesheet>
|
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
|