XSLT 1.0 recursion

Posted by DashaLuna on Stack Overflow See other posts from Stack Overflow or by DashaLuna
Published on 2010-04-19T15:58:04Z Indexed on 2010/04/19 16:13 UTC
Read the original article Hit count: 449

Filed under:
|
|
|

I'm stuck with recursion, was wondering if anyone can help me out with it.

I have <Receipts> and <Deposits> elements, that are not verbose, i.e. that a <Receipts> element doesn't have an attribute to show what <Deposit> it is towards. I need to figure out <Deposits> "still amount due" and when a last receipt towards it was paid if any.

I'm trying to do it with the following code:

The idea was to take 1st deposit and see if there are receipts. If the deposit isn't fully paid and there are more receipts - call that recorsive function with all the same params except now count in following receipt.

If there aren't any more receipts or deposit is payed - process it correctly (add required attributes). Otherwise proceed with 2nd deposit. And so on.

However, the XSLT crashes with error message that "a processor stack has overflowed - possible cause is infinite template recursion"

I would really appreciate any help/teps... I'm not that great with recursion and can't understand why mine here doesn't work.

Thanks! :)

<!-- Accumulate all the deposits with @DueAmount attribute -->
<xsl:variable name="depositsClassified">
    <xsl:call-template name="classifyDeposits">
        <!-- a node-list of all Deposits elements ordered by DueDate Acs -->
        <xsl:with-param name="depositsAll" select="$deposits"/> 
        <xsl:with-param name="depositPrevAmount" select="'0'"/>
        <!-- a node-list of all Receipts elements ordered by ReceivedDate Acs -->
        <xsl:with-param name="receiptsAll" select="$receiptsAsc"/>
        <xsl:with-param name="receiptCount" select="'1'"/>
    </xsl:call-template>
</xsl:variable>


<xsl:template name="classifyDeposits">
    <xsl:param name="depositsAll"/>
    <xsl:param name="depositPrevAmount" select="'0'"/>
    <xsl:param name="receiptsAll"/>
    <xsl:param name="receiptCount"/>


    <xsl:if test="$deposits">
        <!-- Do required operations for the 1st deposit -->
        <xsl:variable name="depositFirst" select="$depositsAll[1]"/>
        <xsl:variable name="receiptSum">
            <xsl:choose>
                <xsl:when test="$receiptsAll">
                    <xsl:value-of select="sum($receiptsAll[position() &lt;= $receiptCount]/@ActionAmount)"/>
                </xsl:when>
                <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
        </xsl:variable> 
        <xsl:variable name="diff" select="$depositPrevAmount + $depositFirst/@DepositTotalAmount - $receiptSum"/>

        <xsl:choose>
            <xsl:when test="$diff &gt; 0 and
                $receiptCount &lt; $receiptsQuantityOf">
                <xsl:call-template name="classifyDeposits">
                    <xsl:with-param name="depositsAll" select="$depositsAll"/>
                    <xsl:with-param name="depositPrevAmount" select="$depositPrevAmount"/>
                    <xsl:with-param name="receiptsAll" select="$receiptsAll"/>
                    <xsl:with-param name="receiptCount" select="$receiptCount + 1"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <!-- Record changes to the deposit (@DueAmount and receipt ReceivedDate) -->
                <xsl:apply-templates select="$depositFirst" mode="defineDeposit">
                    <xsl:with-param name="diff" select="$diff"/>
                    <xsl:with-param name="latestReceiptForDeposit" select="$receiptsAll[position() = $receiptCount]"/>
                </xsl:apply-templates>


                <!-- Recursive call to the next deposit -->
                <xsl:call-template name="classifyDeposits">
                    <xsl:with-param name="depositsAll" select="$depositsAll[position() &gt; 1]"/>
                    <xsl:with-param name="depositPrevAmount" select="$depositPrevAmount + $depositFirst/@DepositTotalAmount"/>
                    <xsl:with-param name="receiptsAll" select="$receiptsAll"/>
                    <xsl:with-param name="receiptCount" select="'1'"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:if>
</xsl:template>

<!-- Determine deposit's status, due amount and payment received date if any -->
<xsl:template match="Deposits" mode="defineDeposit">
    <xsl:param name="diff"/>
    <xsl:param name="latestReceiptForDeposit"/>

    <xsl:choose>
        <xsl:when test="$diff &lt;= 0">
            <xsl:apply-templates select="." mode="addAttrs">
                <xsl:with-param name="status" select="'paid'"/>
                <xsl:with-param name="dueAmount" select="'0'"/>
                <xsl:with-param name="receipt" select="$latestReceiptForDeposit"/>
            </xsl:apply-templates>
        </xsl:when>
        <xsl:when test="$diff = ./@DepositTotalAmount">
            <xsl:apply-templates select="." mode="addAttrs">
                <xsl:with-param name="status" select="'due'"/>
                <xsl:with-param name="dueAmount" select="$diff"/>
            </xsl:apply-templates>
        </xsl:when>
        <xsl:when test="$diff &lt; ./@DepositTotalAmount">
            <xsl:apply-templates select="." mode="addAttrs">
                <xsl:with-param name="status" select="'outstanding'"/>
                <xsl:with-param name="dueAmount" select="$diff"/>
                <xsl:with-param name="receipt" select="$latestReceiptForDeposit"/>
            </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise/>
    </xsl:choose>
</xsl:template>

<xsl:template match="Deposits" mode="addAttrs">
    <xsl:param name="status"/>
    <xsl:param name="dueAmount"/>
    <xsl:param name="receipt" select="''"/>

    <!-- Constract a new MultiDeposits element with required info -->
    <xsl:copy>
        <xsl:copy-of select="./@*"/>
        <xsl:attribute name="Status"><xsl:value-of select="$status"/></xsl:attribute>
        <xsl:attribute name="DueAmount"><xsl:value-of select="$dueAmount"/></xsl:attribute>
        <xsl:if test="$receipt">
            <xsl:attribute name="latestReceiptDate">
                <xsl:value-of select="$receipt/@ActionDate"/>
            </xsl:attribute>
        </xsl:if>
        <xsl:copy-of select="./*"/>
    </xsl:copy>
</xsl:template>

© Stack Overflow or respective owner

Related posts about xslt

Related posts about xslt-1.0