2010-04-19 189 views
0

我被困在遞歸中,想知道是否有人能幫助我。XSLT 1.0遞歸

我有<Receipts><Deposits>元件中,不是冗長,即,一個元件<Receipts>不具有屬性,以顯示它是什麼<Deposit>朝向。我需要計算出<Deposits>「還款到期」,並且最後一張收據是否已付款(如果有的話)。

我想用下面的代碼來做到這一點:

的想法就是把第一個存款,看看是否有收據。如果存款沒有全額支付並且有更多的收據 - 將所有相同的參數稱爲recorsive功能,除了現在計入以下收據。

如果沒有更多的收據或存款支付 - 正確處理(添加必需的屬性)。否則,繼續第二次存款。等等。

然而,隨着錯誤消息的XSLT崩潰,「一個處理器堆棧溢出 - 可能的原因是無窮的遞歸模板」

我真的很感激任何幫助/ TEPS ......我不是遞歸這個偉大並不明白爲什麼我的這裏不起作用。

謝謝! :)

<!-- 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

您的命名模板classifyDeposits肯定是遞歸無限。它沒有基礎案例。在<xsl:choose>部分中,您有兩個條件:<xsl:when><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 

當然,只是條件不夠好。它需要可達。

+0

@Welbog謝謝你,看到它在僞使得它更清晰這是怎麼回事。我認爲包含聲明的if語句可用作基本情況?分行會繼續撥打同一套存款或不包括第一張存款。但是選擇聲明只有在有存款需要處理時纔會執行。 對不起,如果這是一個愚蠢的問題,只是試圖讓我的頭。 – DashaLuna 2010-04-19 16:24:24

+0

''部件不在您傳遞給模板的參數上運行。我假設它是某種全局變量。這絕對不是參與函數的基本情況,因爲一旦模板被第一次調用,'$ deposits'的值不會改變。如果它匹配第一個呼叫,它將匹配每個後續呼叫。 – Welbog 2010-04-19 16:26:52

+0

哦,是的,抱歉,這是一個錯字。它應該是。它不會無限循環。儘管如此,它並沒有正確計算DueAmount,我完全搞不懂爲什麼.. :(我應該編輯原始消息,尋求邏輯幫助或添加評論嗎? – DashaLuna 2010-04-19 16:30:39

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; 
    } 
} 

我希望幫助

+0

@Joshua哦,我明白了你的觀點,我會再次看看我的意見。謝謝 – DashaLuna 2010-04-19 16:26:43

+0

downvote?任何人都在關心澄清?不客氣大傻 – Joshua 2010-04-19 16:32:42