XSLT 1.0 递归
我被递归困住了,想知道是否有人可以帮助我。
我有
和
元素,它们并不详细,即
元素没有有一个属性来显示它的目标
。我需要弄清楚
“尚欠金额”以及最后一张收据的支付时间(如果有)。
我尝试使用以下代码来完成此操作:
这个想法是收取第一笔存款并查看是否有收据。如果押金未全额支付并且有更多收据 - 使用所有相同的参数调用该 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() <= $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 > 0 and
$receiptCount < $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() > 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 <= 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 < ./@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>
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="$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() <= $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 > 0 and
$receiptCount < $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() > 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 <= 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 < ./@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>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的命名模板
classifyDeposits
肯定是无限递归的。它没有基本情况。但是,在
部分中,您有两个条件:
和
在这两种情况下,您都可以调用classifyDeposits
。因此,无论您传递给该模板什么,它都会调用自身。您需要有一个基本情况:模板不调用自身的条件。
在伪代码中,您实际上是在执行以下操作:
您需要在某个位置添加另一个分支,该分支不会调用自身。
当然,仅仅拥有条件还不够。它需要可达。
Your named template
classifyDeposits
is definitely recursing infinitely. It has no base case. In the<xsl:choose>
section you have two conditions:<xsl:when>
and<xsl:otherwise>
, however you callclassifyDeposits
in both conditions.So no matter what you pass to this template, it will call itself. You need to have a base case: a condition in which the template doesn't call itself.
In pseudocode, you're essentially doing this:
You need to add another branch, somewhere, that does not call itself.
Of course, just having the condition isn't good enough. It needs to be reachable.
我学到的关于递归的一件事是,您需要确保完成时会触发一个条件。
示例:
我根本不知道 xlst,但这可能是递归进入无限循环的一个简单原因。考虑一下:
我希望有帮助
One thing i've learned about concerning recursion is that you need to make sure that you have a condition that will trigger when you are done.
example:
I don't know xlst at all, but this can be a simple reason why recursion can go into an infinite loop. Consider instead:
I hope that helps