XSLT 1.0 帮助递归逻辑

发布于 2024-08-29 04:58:38 字数 10248 浏览 2 评论 0原文

我在逻辑上遇到了麻烦,希望得到任何帮助/提示。

我有 元素和 元素。然而,没有任何证据表明哪些收据支付了哪些存款。

我正在尝试使用以下属性更新 元素:

  • @DueAmont - 仍需支付的金额
  • @Status - 是否已付款、未付款(部分付款)或due
  • @ReceiptDate - 支付这笔存款的最新收据日期

每笔存款都可以用一张或多张收据支付。也可能发生这样的情况:一张收据可以支付一笔或多笔存款。例如。如果有 3 笔存款:

  1. 500
  2. 100
  3. 450

使用以下收据支付:

  1. 200
  2. 100
  3. 250

我想获得以下信息:
存款 1 已全额支付(status=paid、 dueAmount=0、receiptNum=3。
存款 2 已支付部分(status=outstanding、 dueAmount=50、receiptNum=3。
存款 3 未支付(status=due、dueAmount=450、receiptNum=NAN。



实际 XML:

 <Deposits DepositDate="2010-04-07T00:00:00" DepositTotalAmount="500.0000" NoOfPeople="10.0000" PerPerson="50.00"/>
 <Deposits DepositDate="2010-04-12T00:00:00" DepositTotalAmount="100.0000" NoOfPeople="10.0000" PerPerson="10.00"/>
 <Deposits DepositDate="2010-04-26T00:00:00" DepositTotalAmount="450.0000" NoOfPeople="10.0000" PerPerson="45.00"/>



<Receipts Amount="200.00" PaymentType="Cheque" Comment="" ReceiptAmount="200.00" ActionDate="2010-04-07T11:01:47" PayingInSlipNumber="" IsCard="No" IsRefund="No"/>
<Receipts Amount="100.00" PaymentType="Cheque" Comment="" ReceiptAmount="100.00" ActionDate="2010-04-11T11:01:47" PayingInSlipNumber="" IsCard="No" IsRefund="No"/>
<Receipts Amount="250.00" PaymentType="Cheque" Comment="" ReceiptAmount="250.00" ActionDate="2010-04-20T11:01:47" PayingInSlipNumber="" IsCard="No" IsRefund="No"/>

我在代码中添加了注释来解释我想要做什么。我已经连续第三天盯着这段代码了——看不出我做错了什么。请问有人可以帮我吗? :)

谢谢!

设置:
$deposits - 所有可用存款
排序的所有可用收据

$receiptsAsc - 按@ActionDate 代码:

<!-- Accumulate all the deposits with @Status, @DueAmount and @ReceiptDate attributes Provide all deposits, receipts and start with 1st receipt -->
<xsl:variable name="depositsClassified">
    <xsl:call-template name="classifyDeposits">
        <xsl:with-param name="depositsAll" select="$deposits"/>
        <xsl:with-param name="receiptsAll" select="$receiptsAsc"/>
        <xsl:with-param name="receiptCount" select="'1'"/>
    </xsl:call-template>
</xsl:variable>

<!-- Recursive function to associate deposits' total amounts with overall receipts paid
    to determine whether a deposit is due, outstanding or paid. Also determine what's the due amount and latest receipt towards the deposit for each deposit -->
<xsl:template name="classifyDeposits">
    <xsl:param name="depositsAll"/>
    <xsl:param name="receiptsAll"/>
    <xsl:param name="receiptCount"/>

    <!-- If there are deposits to proceed -->
    <xsl:if test="$depositsAll">
        <!-- Get the 1st deposit -->
        <xsl:variable name="deposit" select="$depositsAll[1]"/>
        <!-- Calculate the sum of all receipts up to and including currenly considered -->
        <xsl:variable name="receiptSum">
            <xsl:choose>
                <xsl:when test="$receiptsAll">
                    <xsl:value-of select="sum($receiptsAll[position() &lt;= $receiptCount]/@ReceiptAmount)"/>
                </xsl:when>
                <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <!-- Difference between deposit amount and sum of the receipts calculated
        above -->
        <xsl:variable name="diff" select="$deposit/@DepositTotalAmount - $receiptSum"/>

        <xsl:choose>
            <!-- Deposit isn't paid fully and there are more receipts/payments exist.
            So consider the same deposit, but take next receipt into calculation as
            well -->
            <xsl:when test="($diff &gt; 0) and ($receiptCount &lt; count($receiptsAll))">
                <xsl:call-template name="classifyDeposits">
                    <xsl:with-param name="depositsAll" select="$depositsAll"/>
                    <xsl:with-param name="receiptsAll" select="$receiptsAll"/>
                    <xsl:with-param name="receiptCount" select="$receiptCount + 1"/>
                </xsl:call-template>
            </xsl:when>
            <!-- Deposit is paid or we ran out of receipts -->
            <xsl:otherwise>
                <!-- process the deposit. Determine its status and then update
                corresponding attributes -->
                <xsl:apply-templates select="$deposit" mode="defineDeposit">
                    <xsl:with-param name="diff" select="$diff"/>
                    <xsl:with-param name="receiptNum" select="$receiptCount"/>
                </xsl:apply-templates>

                <!-- Recursively call the template with the rest of deposits excluding the first. Before hand update the @ReceiptsAmount. For the receipts before current it is now 0, for the current is what left in the $diff, and simply copy over receipts after current one. -->
                <xsl:variable name="receiptsUpdatedRTF">
                    <xsl:for-each select="$receiptsAll">
                        <xsl:choose>
                            <!-- these receipts was fully accounted for the current deposit. Make them 0 -->
                            <xsl:when test="position() &lt; $receiptCount">
                                <xsl:copy>
                                    <xsl:copy-of select="./@*"/>
                                    <xsl:attribute name="ReceiptAmount">0</xsl:attribute>
                                </xsl:copy>
                            </xsl:when>
                            <!-- this receipt was partly/fully(in case $diff=0) accounted for the current deposit. Make it whatever is in $diff -->
                            <xsl:when test="position() = $receiptCount">
                                <xsl:copy>
                                    <xsl:copy-of select="./@*"/>
                                    <xsl:attribute name="ReceiptAmount">
                                        <xsl:value-of select="format-number($diff, '#.00;#.00')"/>
                                    </xsl:attribute>
                                </xsl:copy>
                            </xsl:when>
                            <!-- these receipts weren't yet considered - copy them over -->
                            <xsl:otherwise>
                                <xsl:copy-of select="."/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </xsl:variable>
                <xsl:variable name="receiptsUpdated" select="msxsl:node-set($receiptsUpdatedRTF)/Receipts"/>

                <!-- Recursive call for the next deposit. Starting counting receipts from the current one. -->
                <xsl:call-template name="classifyDeposits">
                    <xsl:with-param name="depositsAll" select="$deposits[position() != 1]"/>
                    <xsl:with-param name="receiptsAll" select="$receiptsUpdated"/>
                    <xsl:with-param name="receiptCount" select="$receiptCount"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:if>
</xsl:template>

<!-- Determine deposit's status and due amount -->
<xsl:template match="MultiDeposits" mode="defineDeposit">
    <xsl:param name="diff"/>
    <xsl:param name="receiptNum"/>

    <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="receiptNum" select="$receiptNum"/>
            </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="receiptNum" select="$receiptNum"/>
            </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise/>
    </xsl:choose>
</xsl:template>

<!-- Add new attributes (@Status, @DueAmount and @ReceiptDate) to the 
    deposit element -->
<xsl:template match="MultiDeposits" mode="addAttrs">
    <xsl:param name="status"/>
    <xsl:param name="dueAmount"/>
    <xsl:param name="receiptNum" select="''"/>

    <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="$receiptNum != ''">
            <xsl:attribute name="ReceiptDate">
                <xsl:value-of select="$receiptsAsc[position() = $receiptNum]/@ActionDate"/>
            </xsl:attribute>
        </xsl:if>
        <xsl:copy-of select="./*"/>
    </xsl:copy>
</xsl:template>

I'm having troubles with the logic and would apprecite any help/tips.

I have <Deposits> elements and <Receipts> elements. However there isn't any identification what receipt was paid toward what deposit.

I am trying to update the <Deposits> elements with the following attributes:

  • @DueAmont - the amount that is still due to pay
  • @Status - whether it's paid, outstanding (partly paid) or due
  • @ReceiptDate - the latest receipt's date that was paid towards this deposit

Every deposit could be paid with one or more receipts. It also could happen, that 1 receipt could cover one or more deposits. For example. If there are 3 deposits:

  1. 500
  2. 100
  3. 450

That are paid with the following receipts:

  1. 200
  2. 100
  3. 250

I want to get the following info:
Deposit 1 is fully paid (status=paid, dueAmount=0, receiptNum=3.
Deposit 2 is partly paid (status=outstanding, dueAmount=50, receiptNum=3.
Deposit 3 is not paid (status=due, dueAmount=450, receiptNum=NAN.

Actual XML:

 <Deposits DepositDate="2010-04-07T00:00:00" DepositTotalAmount="500.0000" NoOfPeople="10.0000" PerPerson="50.00"/>
 <Deposits DepositDate="2010-04-12T00:00:00" DepositTotalAmount="100.0000" NoOfPeople="10.0000" PerPerson="10.00"/>
 <Deposits DepositDate="2010-04-26T00:00:00" DepositTotalAmount="450.0000" NoOfPeople="10.0000" PerPerson="45.00"/>

<Receipts Amount="200.00" PaymentType="Cheque" Comment="" ReceiptAmount="200.00" ActionDate="2010-04-07T11:01:47" PayingInSlipNumber="" IsCard="No" IsRefund="No"/>
<Receipts Amount="100.00" PaymentType="Cheque" Comment="" ReceiptAmount="100.00" ActionDate="2010-04-11T11:01:47" PayingInSlipNumber="" IsCard="No" IsRefund="No"/>
<Receipts Amount="250.00" PaymentType="Cheque" Comment="" ReceiptAmount="250.00" ActionDate="2010-04-20T11:01:47" PayingInSlipNumber="" IsCard="No" IsRefund="No"/>

I've added comments in the code explaining what I'm trying to do. I am staring at this code for the 3rd day now non stop - can't see what I'm doing wrong. Please could anyone help me with it? :)

Thanks!

Set up:
$deposits - All the available deposits
$receiptsAsc - All the available receipts sorted by their @ActionDate

Code:

<!-- Accumulate all the deposits with @Status, @DueAmount and @ReceiptDate attributes Provide all deposits, receipts and start with 1st receipt -->
<xsl:variable name="depositsClassified">
    <xsl:call-template name="classifyDeposits">
        <xsl:with-param name="depositsAll" select="$deposits"/>
        <xsl:with-param name="receiptsAll" select="$receiptsAsc"/>
        <xsl:with-param name="receiptCount" select="'1'"/>
    </xsl:call-template>
</xsl:variable>

<!-- Recursive function to associate deposits' total amounts with overall receipts paid
    to determine whether a deposit is due, outstanding or paid. Also determine what's the due amount and latest receipt towards the deposit for each deposit -->
<xsl:template name="classifyDeposits">
    <xsl:param name="depositsAll"/>
    <xsl:param name="receiptsAll"/>
    <xsl:param name="receiptCount"/>

    <!-- If there are deposits to proceed -->
    <xsl:if test="$depositsAll">
        <!-- Get the 1st deposit -->
        <xsl:variable name="deposit" select="$depositsAll[1]"/>
        <!-- Calculate the sum of all receipts up to and including currenly considered -->
        <xsl:variable name="receiptSum">
            <xsl:choose>
                <xsl:when test="$receiptsAll">
                    <xsl:value-of select="sum($receiptsAll[position() <= $receiptCount]/@ReceiptAmount)"/>
                </xsl:when>
                <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <!-- Difference between deposit amount and sum of the receipts calculated
        above -->
        <xsl:variable name="diff" select="$deposit/@DepositTotalAmount - $receiptSum"/>

        <xsl:choose>
            <!-- Deposit isn't paid fully and there are more receipts/payments exist.
            So consider the same deposit, but take next receipt into calculation as
            well -->
            <xsl:when test="($diff > 0) and ($receiptCount < count($receiptsAll))">
                <xsl:call-template name="classifyDeposits">
                    <xsl:with-param name="depositsAll" select="$depositsAll"/>
                    <xsl:with-param name="receiptsAll" select="$receiptsAll"/>
                    <xsl:with-param name="receiptCount" select="$receiptCount + 1"/>
                </xsl:call-template>
            </xsl:when>
            <!-- Deposit is paid or we ran out of receipts -->
            <xsl:otherwise>
                <!-- process the deposit. Determine its status and then update
                corresponding attributes -->
                <xsl:apply-templates select="$deposit" mode="defineDeposit">
                    <xsl:with-param name="diff" select="$diff"/>
                    <xsl:with-param name="receiptNum" select="$receiptCount"/>
                </xsl:apply-templates>

                <!-- Recursively call the template with the rest of deposits excluding the first. Before hand update the @ReceiptsAmount. For the receipts before current it is now 0, for the current is what left in the $diff, and simply copy over receipts after current one. -->
                <xsl:variable name="receiptsUpdatedRTF">
                    <xsl:for-each select="$receiptsAll">
                        <xsl:choose>
                            <!-- these receipts was fully accounted for the current deposit. Make them 0 -->
                            <xsl:when test="position() < $receiptCount">
                                <xsl:copy>
                                    <xsl:copy-of select="./@*"/>
                                    <xsl:attribute name="ReceiptAmount">0</xsl:attribute>
                                </xsl:copy>
                            </xsl:when>
                            <!-- this receipt was partly/fully(in case $diff=0) accounted for the current deposit. Make it whatever is in $diff -->
                            <xsl:when test="position() = $receiptCount">
                                <xsl:copy>
                                    <xsl:copy-of select="./@*"/>
                                    <xsl:attribute name="ReceiptAmount">
                                        <xsl:value-of select="format-number($diff, '#.00;#.00')"/>
                                    </xsl:attribute>
                                </xsl:copy>
                            </xsl:when>
                            <!-- these receipts weren't yet considered - copy them over -->
                            <xsl:otherwise>
                                <xsl:copy-of select="."/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </xsl:variable>
                <xsl:variable name="receiptsUpdated" select="msxsl:node-set($receiptsUpdatedRTF)/Receipts"/>

                <!-- Recursive call for the next deposit. Starting counting receipts from the current one. -->
                <xsl:call-template name="classifyDeposits">
                    <xsl:with-param name="depositsAll" select="$deposits[position() != 1]"/>
                    <xsl:with-param name="receiptsAll" select="$receiptsUpdated"/>
                    <xsl:with-param name="receiptCount" select="$receiptCount"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:if>
</xsl:template>

<!-- Determine deposit's status and due amount -->
<xsl:template match="MultiDeposits" mode="defineDeposit">
    <xsl:param name="diff"/>
    <xsl:param name="receiptNum"/>

    <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="receiptNum" select="$receiptNum"/>
            </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="receiptNum" select="$receiptNum"/>
            </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise/>
    </xsl:choose>
</xsl:template>

<!-- Add new attributes (@Status, @DueAmount and @ReceiptDate) to the 
    deposit element -->
<xsl:template match="MultiDeposits" mode="addAttrs">
    <xsl:param name="status"/>
    <xsl:param name="dueAmount"/>
    <xsl:param name="receiptNum" select="''"/>

    <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="$receiptNum != ''">
            <xsl:attribute name="ReceiptDate">
                <xsl:value-of select="$receiptsAsc[position() = $receiptNum]/@ActionDate"/>
            </xsl:attribute>
        </xsl:if>
        <xsl:copy-of select="./*"/>
    </xsl:copy>
</xsl:template>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

风尘浪孓 2024-09-05 04:58:38

有趣的问题。我认为更好的方法是添加一个参数来累积余额,这样您就不需要更新收据结构。我的版本如下。我已经根据您提供的示例输入进行了测试,并收到了预期的结果。

请注意,我将存款的模板模式从 MultiDeposits 更改为 Deposits,因为您在示例输入中使用了后一个元素名称。

<!-- Accumulate all the deposits with @Status, @DueAmount and @ReceiptDate 
     attributes. Provide all deposits and receipts. --> 
<xsl:variable name="depositsClassified"> 
    <xsl:call-template name="classifyDeposits"> 
        <xsl:with-param name="depositsAll" select="$deposits"/> 
        <xsl:with-param name="receiptsAll" select="$receiptsAsc"/> 
    </xsl:call-template> 
</xsl:variable> 

<!-- Recursive function to associate deposits' total amounts with overall 
     receipts paid to determine whether a deposit is due, outstanding or paid. 
     Also determine what's the due amount and latest receipt towards the 
     deposit for each deposit --> 
<xsl:template name="classifyDeposits"> 
    <xsl:param name="depositsAll"/> 
    <xsl:param name="receiptsAll"/> 
    <xsl:param name="balance" select="0"/>

    <!-- If there are deposits to proceed --> 
    <xsl:if test="$depositsAll"> 
        <!-- Get the 1st deposit --> 
        <xsl:variable name="deposit" select="$depositsAll[1]"/> 
        <!-- Get the 1st receipt. -->
        <xsl:variable name="receipt" select="$receiptsAll[1]"/> 
        <!-- Calculate difference. --> 
        <xsl:variable 
            name="diff" 
            select="$balance + $deposit/@DepositTotalAmount
                             - $receipt/@ReceiptAmount"/> 

        <xsl:choose> 
            <!-- Deposit isn't paid fully and there are more receipts. 
                 Move on to the next receipt, with updated balance. --> 
            <xsl:when test="($diff > 0) and $receiptsAll[2]"> 
                <xsl:call-template name="classifyDeposits"> 
                    <xsl:with-param name="depositsAll" select="$depositsAll"/> 
                    <xsl:with-param 
                        name="receiptsAll" 
                        select="$receiptsAll[position() != 1]"/> 
                    <xsl:with-param 
                        name="balance" 
                        select="$balance - $receipt/@ReceiptAmount"/>
                </xsl:call-template> 
            </xsl:when> 
            <!-- Deposit is paid or we ran out of receipts --> 
            <xsl:otherwise> 
                <!-- Process the deposit. Determine its status and then update 
                corresponding attributes --> 
                <xsl:apply-templates select="$deposit" mode="defineDeposit"> 
                    <xsl:with-param name="diff" select="$diff"/> 
                    <xsl:with-param name="receipt" select="$receipt"/> 
                </xsl:apply-templates> 

                <!-- Recursive call for the next deposit. --> 
                <xsl:call-template name="classifyDeposits"> 
                    <xsl:with-param
                        name="depositsAll" 
                        select="$depositsAll[position() != 1]"/> 
                    <xsl:with-param name="receiptsAll" select="$receiptsAll"/> 
                    <xsl:with-param 
                        name="balance" 
                        select="$balance + $deposit/@DepositTotalAmount"/>
                </xsl:call-template> 
            </xsl:otherwise> 
        </xsl:choose> 
    </xsl:if> 
</xsl:template> 

<!-- Output deposit's status and due amount --> 
<xsl:template match="Deposits" mode="defineDeposit"> 
    <xsl:param name="diff"/> 
    <xsl:param name="receipt"/> 
    <xsl:copy>
        <xsl:copy-of select="@*"/> 
        <xsl:choose>
            <xsl:when test="$diff >= @DepositTotalAmount">
                <xsl:attribute name="Status">due</xsl:attribute>
                <xsl:attribute name="DueAmount">
                    <xsl:value-of select="@DepositTotalAmount"/>
                </xsl:attribute>
            </xsl:when>
            <xsl:when test="$diff > 0">
                <xsl:attribute name="Status">outstanding</xsl:attribute>
                <xsl:attribute name="DueAmount">
                    <xsl:value-of select="$diff"/>
                </xsl:attribute>
            </xsl:when>
            <xsl:otherwise>
                <xsl:attribute name="Status">paid</xsl:attribute>
                <xsl:attribute name="DueAmount">0</xsl:attribute>
                <xsl:attribute name="ReceiptDate">
                    <xsl:value-of select="$receipt/@ActionDate"/>
                </xsl:attribute>
            </xsl:otherwise>
        </xsl:choose>
        <xsl:copy-of select="node()"/> 
    </xsl:copy>
</xsl:template> 

作为示例,以下是如何针对输入进行递归:

存款 1 = 2200,存款 2 = 1100
收据 1 = 200,收据 2 = 2000,收据 3 = 800

    1Run) bal = 0; 
          diff = 0(bal) + 2200(dep1) - 200(recp1) = 2000
          (diff > 0 & more receipts)

    2Run) bal = 0-200(recp1) = -200; 
          diff = -200(bal) + 2200(dep1) - 2000(recp2) = 0
          (output first deposit: status = "paid", proceed to next deposit)

    3Run) bal= -200 + 2200(dep1) = 2000;
          diff = 2000(bal) + 1100(dep2) -2000(recp2) = 1100
          (diff > 0 & more receipts) 

    4Run) bal= 2000 - 2000(recp2) = 0;
          diff = 0(bal) + 1100(dep2) - 800(recp3) = 300
          (no more receipts, output second deposit: status = "outstanding")

Interesting question. I believe a better approach is to add a parameter to accumulate the balance, so that you will not need to update the receipts structure. My version follows. I have tested it on the sample input you provided, and received the expected result.

Please note that I changed the template pattern for deposits from MultiDeposits to Deposits, since you used the latter element name in your sample input.

<!-- Accumulate all the deposits with @Status, @DueAmount and @ReceiptDate 
     attributes. Provide all deposits and receipts. --> 
<xsl:variable name="depositsClassified"> 
    <xsl:call-template name="classifyDeposits"> 
        <xsl:with-param name="depositsAll" select="$deposits"/> 
        <xsl:with-param name="receiptsAll" select="$receiptsAsc"/> 
    </xsl:call-template> 
</xsl:variable> 

<!-- Recursive function to associate deposits' total amounts with overall 
     receipts paid to determine whether a deposit is due, outstanding or paid. 
     Also determine what's the due amount and latest receipt towards the 
     deposit for each deposit --> 
<xsl:template name="classifyDeposits"> 
    <xsl:param name="depositsAll"/> 
    <xsl:param name="receiptsAll"/> 
    <xsl:param name="balance" select="0"/>

    <!-- If there are deposits to proceed --> 
    <xsl:if test="$depositsAll"> 
        <!-- Get the 1st deposit --> 
        <xsl:variable name="deposit" select="$depositsAll[1]"/> 
        <!-- Get the 1st receipt. -->
        <xsl:variable name="receipt" select="$receiptsAll[1]"/> 
        <!-- Calculate difference. --> 
        <xsl:variable 
            name="diff" 
            select="$balance + $deposit/@DepositTotalAmount
                             - $receipt/@ReceiptAmount"/> 

        <xsl:choose> 
            <!-- Deposit isn't paid fully and there are more receipts. 
                 Move on to the next receipt, with updated balance. --> 
            <xsl:when test="($diff > 0) and $receiptsAll[2]"> 
                <xsl:call-template name="classifyDeposits"> 
                    <xsl:with-param name="depositsAll" select="$depositsAll"/> 
                    <xsl:with-param 
                        name="receiptsAll" 
                        select="$receiptsAll[position() != 1]"/> 
                    <xsl:with-param 
                        name="balance" 
                        select="$balance - $receipt/@ReceiptAmount"/>
                </xsl:call-template> 
            </xsl:when> 
            <!-- Deposit is paid or we ran out of receipts --> 
            <xsl:otherwise> 
                <!-- Process the deposit. Determine its status and then update 
                corresponding attributes --> 
                <xsl:apply-templates select="$deposit" mode="defineDeposit"> 
                    <xsl:with-param name="diff" select="$diff"/> 
                    <xsl:with-param name="receipt" select="$receipt"/> 
                </xsl:apply-templates> 

                <!-- Recursive call for the next deposit. --> 
                <xsl:call-template name="classifyDeposits"> 
                    <xsl:with-param
                        name="depositsAll" 
                        select="$depositsAll[position() != 1]"/> 
                    <xsl:with-param name="receiptsAll" select="$receiptsAll"/> 
                    <xsl:with-param 
                        name="balance" 
                        select="$balance + $deposit/@DepositTotalAmount"/>
                </xsl:call-template> 
            </xsl:otherwise> 
        </xsl:choose> 
    </xsl:if> 
</xsl:template> 

<!-- Output deposit's status and due amount --> 
<xsl:template match="Deposits" mode="defineDeposit"> 
    <xsl:param name="diff"/> 
    <xsl:param name="receipt"/> 
    <xsl:copy>
        <xsl:copy-of select="@*"/> 
        <xsl:choose>
            <xsl:when test="$diff >= @DepositTotalAmount">
                <xsl:attribute name="Status">due</xsl:attribute>
                <xsl:attribute name="DueAmount">
                    <xsl:value-of select="@DepositTotalAmount"/>
                </xsl:attribute>
            </xsl:when>
            <xsl:when test="$diff > 0">
                <xsl:attribute name="Status">outstanding</xsl:attribute>
                <xsl:attribute name="DueAmount">
                    <xsl:value-of select="$diff"/>
                </xsl:attribute>
            </xsl:when>
            <xsl:otherwise>
                <xsl:attribute name="Status">paid</xsl:attribute>
                <xsl:attribute name="DueAmount">0</xsl:attribute>
                <xsl:attribute name="ReceiptDate">
                    <xsl:value-of select="$receipt/@ActionDate"/>
                </xsl:attribute>
            </xsl:otherwise>
        </xsl:choose>
        <xsl:copy-of select="node()"/> 
    </xsl:copy>
</xsl:template> 

As an example, here's how a recursion develops for the input:

Deposit 1 = 2200, Deposit 2 = 1100
Receipt 1 = 200, Receipt 2 = 2000, Receipt 3 = 800

    1Run) bal = 0; 
          diff = 0(bal) + 2200(dep1) - 200(recp1) = 2000
          (diff > 0 & more receipts)

    2Run) bal = 0-200(recp1) = -200; 
          diff = -200(bal) + 2200(dep1) - 2000(recp2) = 0
          (output first deposit: status = "paid", proceed to next deposit)

    3Run) bal= -200 + 2200(dep1) = 2000;
          diff = 2000(bal) + 1100(dep2) -2000(recp2) = 1100
          (diff > 0 & more receipts) 

    4Run) bal= 2000 - 2000(recp2) = 0;
          diff = 0(bal) + 1100(dep2) - 800(recp3) = 300
          (no more receipts, output second deposit: status = "outstanding")
兰花执着 2024-09-05 04:58:38

但是没有任何证据表明哪些收据支付了哪些存款。

这是你问题的关键。您必须有一种方法将收据与存款预先关联起来。想象一下,如果您使用纸质收据,您会如何处理?你必须询问给你收据的人哪笔存款的金额是多少,然后一旦你发现了,你就把它记录在收据上。一旦您知道这一点并以表示收据的方式反映它,您就可以构建 xslt 来抓取这些位。不幸的是,我无法帮助您使用 xslt,但想象一下每个收据都有每个分区的子元素。就像:

<RECEIPTS total=500 blah blah blah>
      <subtotal deposit=1 amount=100>
      <subtotal deposit=2 amount=300>
</RECEIPTS>

然后在循环时,抓住收据的子项,循环每个小计并将其添加到相应的存款金额计数器中。

另外,我注意到,从您期望的输出来看,如果将不止一张收据应用于存款,会发生什么情况?你如何表示这一点?目前,

Deposit 2 is partly paid (status=outstanding, dueAmount=50, receiptNum=3

如果存款 2 已部分支付并有 2 张收据,那么属性receiptNum 对您仍然有意义吗?您可能必须扩展此功能,也许可以按照与我之前提供的收据模型相同的方式添加小计子元素。

我想说的是,如果你想解决这个问题,就假装你是在纸上做这一切的。这将阐明您需要如何在代码中执行此操作。

在查看了您的其他一些帖子后,我意识到您可能无法控制所获得的数据集。然而,在某些时候,您需要能够回答以下问题:“这些收据的哪些金额用于哪些存款?”之后,我不得不说,您尝试使用递归来解决这个问题可能只会让您感到困惑。任何递归方法都可以用循环代替。我期待看到您的最终解决方案是什么样的。

However there isn't any identification what receipt was paid toward what deposit.

This is the key to your problem. You have to have a way to associate the receipts with the deposits UP FRONT. Imagine if you were working with paper receipts, how would you handle this? You'd have to ask the person who gave you the receipt how much was intended for which deposit, and then once you found that out you record it on the receipt. Once you know this and reflect it in the way you represent receipts, you can build the xslt to grab those bits out. Unfortunately I can't help you with the xslt for that, but imagine that each receipt has child element for each partition. like:

<RECEIPTS total=500 blah blah blah>
      <subtotal deposit=1 amount=100>
      <subtotal deposit=2 amount=300>
</RECEIPTS>

then as you loop through, grab the children of the receipt, loop through each subtotal and add it to the appropriate counter for the deposit sum.

Also, I noticed, from your desired output, what happens if more than one receipt is applied towards a deposit? how do you represent that? currently you have

Deposit 2 is partly paid (status=outstanding, dueAmount=50, receiptNum=3

what if deposit 2 was partially paid with 2 receipts, is the attribute receiptNum still going to have meaning for you? you might have to extend this, maybe by adding subtotal children elements in the same manner as the receipts model I offered earlier.

Id say if you want to get a handle on this, pretend you were doing this all with/on paper. That would shed light on how you need to do it in code.

After looking at some of your other posts, I realize that you may not be in control of the dataset you get. At some point however, you need to be able to answer the question, "Which amounts of these receipts go to which deposits?" After that, I have to say, your attempts at using recursion to solve this problem might be serving only to confuse you. Any recursion method can be replaced with a loop instead. I look forward to seeing what your final solution looks like.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文