xsl-list
[Top] [All Lists]

[xsl] RE: Is xsl:for-each "syntactic sugar"?

2010-05-07 17:35:15
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>
    <StartBalance>100.00</StartBalance>
    <Transaction>-5.00</Transaction>
    <Transaction>-2.50</Transaction>
    <Transaction>10.00</Transaction>
    <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?

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?  /Roger

----------------------------------------------
IMPLEMENTATION #1: Uses Recursive Function
----------------------------------------------
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                xmlns:ex="http://www.example.org";
                version="2.0">

    <xsl:output method="text" encoding="US-ASCII" />


    <xsl:function name="ex:Balance">
        <xsl:param name="starting-balance" />
        <xsl:param name="transactions" />

        <xsl:choose>
            <xsl:when test="empty($transactions)" />
            <xsl:otherwise> 
                <xsl:sequence select="$starting-balance + $transactions[1]" />
                <xsl:sequence select="ex:Balance($starting-balance + 
$transactions[1], $transactions[position() gt 1])" />   
            </xsl:otherwise>
        </xsl:choose>
    </xsl:function>

    <xsl:template match="BankTransactions">
        <xsl:sequence select="ex:Balance(StartBalance, (Transaction))" />
    </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";
                version="2.0">

    <xsl:output method="text" encoding="US-ASCII" />


    <xsl:template match="BankTransactions">
        <xsl:apply-templates select="Transaction[1]">
            <xsl:with-param name="starting-balance" select="data(StartBalance)" 
/>
        </xsl:apply-templates>
    </xsl:template>


    <xsl:template match="Transaction">
        <xsl:param name="starting-balance" />

        <xsl:sequence select="$starting-balance + data(.)" />

        <xsl:if test="following-sibling::Transaction">
            <xsl:apply-templates select="following-sibling::Transaction[1]">
                <xsl:with-param name="starting-balance" 
select="$starting-balance + data(.)" />
            </xsl:apply-templates>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--