0

我被递归困住了,想知道是否有人可以帮助我。

我有<Receipts><Deposits>元素,它们并不冗长,即<Receipts>元素没有属性来显示<Deposit>它的目标。我需要弄清楚<Deposits>“仍需支付的金额”以及最后一张收据何时支付(如果有的话)。

我正在尝试使用以下代码来做到这一点:

想法是收取第一笔存款,看看是否有收据。如果押金未全额支付并且有更多收据 - 使用所有相同的参数调用该 recorsive 函数,除了现在计入后续收据。

如果没有更多收据或已支付押金 - 正确处理(添加所需属性)。否则继续进行第二次存款。等等。

但是,XSLT 崩溃并显示错误消息“处理器堆栈已溢出 - 可能的原因是无限模板递归”

我真的很感激任何帮助/提示......我对递归不是很好,也无法理解为什么我的这里不起作用。

谢谢!:)

<!-- 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="$depositsAll">
        <!-- 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>
4

2 回答 2

4

您的命名模板classifyDeposits肯定是无限递归的。它没有基本情况。在该<xsl:choose>部分中,您有两个条件:<xsl:when>and <xsl:otherwise>,但是您同时调用classifyDeposits了这两个条件。

所以无论你传递给这个模板什么,它都会调用自己。您需要有一个基本情况:模板不调用自身的条件。

在伪代码中,您实际上是在这样做:

function recursive
  if (A>B) then
    call recursive
  else
    call recursive

您需要在某个地方添加另一个不会调用自身的分支。

function recursive
  if (C=0) then
    return
  else if (A>B) then
    call recursive
  else
    call recursive

当然,有条件是不够的。它必须是可达的。

于 2010-04-19T16:10:14.793 回答
0

关于递归,我学到的一件事是你需要确保你有一个条件,当你完成时会触发。

例子:

decrement_me_until_zero(int i)
{
     if(i ==0) return;  //we're done here, roll on back up!
     else
     {
         i = i-1;
         decrement_me_until_zero(i);
         return;
     }
}

我根本不知道 xlst,但这可能是递归可以进入无限循环的一个简单原因。改为考虑:

decrement_me_until_zero(int i)
{
     if(i ==0) return;  //we're done here, roll on back up!
     else
     {
         decrement_me_until_zero(i);
         i=i-1;                           //oops!  we decrement after we pass the variable down!
         return;
     }
}

我希望这会有所帮助

于 2010-04-19T16:15:52.643 回答