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

Subject: [xsl] RE: Is xsl:for-each "syntactic sugar"?
From: "Costello, Roger L." <costello@xxxxxxxxx>
Date: Fri, 7 May 2010 18:34:52 -0400
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>

Current Thread