【问题标题】:Running Total of Calculated And Rounded Variable in XSLT在 XSLT 中运行计算和舍入变量的总和
【发布时间】:2019-07-04 12:05:12
【问题描述】:

我试图在我的 XSLT 1.0 样式表中保留一个计算值的运行总计(收入的 10%,四舍五入到最接近的 10 美分),但是舍入错误导致我的结果不准确。我知道我当前的代码是错误的,但我不知道如何更正它。

我试过用这个来求和:

<xsl:value-of select="format-number(ceiling(sum(./bsk:Date/@income) div 10), '$#.00')" />

这引入了我提到的舍入误差。

我已经尝试过使用这些总和:

<xsl:value-of select="format-number(sum(ceiling(./bsk:Date/@income div 10)), '$#.00')" />

<xsl:value-of select="format-number(sum(ceiling(./bsk:Date/@income div 10)), '$#.00')" /></td>

我收到错误:“XSLT 转换期间出错:XPath 表达式应返回 NodeSet。”

下面是我正在使用的代码。

<!--   The XML:  -->

<Month name="June">
    <Date num="28" day="Friday">
        <Expense amount="62.50" for="Business License" />
    </Date>
    <Date num="29" day="Saturday" income="61.30"  tithe="paid" />
    <Date num="30" day="Sunday" income="108.45" />
</Month>

<!--  The XSLT -->

<xsl:for-each select="./bsk:Month"><table>
    <tbody>
        <xsl:for-each select="./bsk:Date">
            <xsl:variable name="income"><xsl:choose>
                    <xsl:when test="@income"><xsl:value-of select="@income" /></xsl:when>
                    <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose></xsl:variable>
            <xsl:variable name="tithe" select="ceiling($income) div 10" />
            <xsl:variable name="expenses"><xsl:choose>
                    <xsl:when test="./bsk:Expense"><xsl:value-of select="sum(./bsk:Expense/@amount)" /></xsl:when>
                    <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose></xsl:variable>
            <xsl:variable name="rowspan"><xsl:choose>
                    <xsl:when test="count(./bsk:Expense) &gt; 1"><xsl:value-of select="count(./bsk:Expense)" /></xsl:when>
                    <xsl:otherwise><xsl:value-of select="1" /></xsl:otherwise>
            </xsl:choose></xsl:variable>
            <tr>
                <td>
                    <xsl:attribute name="rowspan"><xsl:value-of select="$rowspan" /></xsl:attribute>
                    <xsl:choose>
                        <xsl:when test="@income">
                            <xsl:text>$</xsl:text>
                            <xsl:value-of select="$income" />
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:attribute name="class">null</xsl:attribute>
                            <xsl:text> - </xsl:text>
                        </xsl:otherwise>
                    </xsl:choose>
                </td>
                <td>
                    <xsl:attribute name="rowspan"><xsl:value-of select="$rowspan" /></xsl:attribute>
                    <xsl:choose>
                        <xsl:when test="@income">
                            <xsl:if test="@tithe='paid'"><xsl:attribute name="class">tithe_paid</xsl:attribute></xsl:if>
                            <xsl:value-of select="format-number($tithe, '$#.00')" />
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:attribute name="class">null</xsl:attribute>
                            <xsl:text> - </xsl:text>
                        </xsl:otherwise>
                    </xsl:choose>
                </td>
                <xsl:choose>
                    <xsl:when test="./bsk:Expense">
                        <td><xsl:value-of select="./bsk:Expense/@for" /></td>
                        <td><xsl:value-of select="format-number(./bsk:Expense[1]/@amount, '$#.00')" /></td>
                    </xsl:when>
                    <xsl:otherwise><td colspan="2" class="null"> - </td></xsl:otherwise>
                </xsl:choose>
                <td>
                    <xsl:attribute name="rowspan"><xsl:value-of select="$rowspan" /></xsl:attribute>
                    <xsl:if test="($income - $expenses) &lt; 0"><xsl:attribute name="class">hole</xsl:attribute></xsl:if>
                    <xsl:value-of select="format-number($income - $expenses - $tithe, '$#.00')" />
                </td>
            </tr>
            <xsl:for-each select="./bsk:Expense[position() &gt; 1]">
                <tr>
                    <td><xsl:value-of select="@for" /></td>
                    <td><xsl:value-of select="format-number(@amount, '$#.00')" /></td>
                </tr>
            </xsl:for-each>
        </xsl:for-each>
    </tbody>
        <tfoot><tr>
        <th>Totals</th>
        <td headers="Income"><xsl:value-of select="format-number(sum(./bsk:Date/@income), '$#.00')" /></td>
        <td headers="Tithe"><xsl:value-of select="format-number(ceiling(sum(./bsk:Date/@income) div 10), '$#.00')" /></td>
        <td colspan="2" headers="Exp_Amount"><xsl:value-of select="format-number(sum(./bsk:Date/bsk:Expense/@amount), '$#.00')" /></td>
        <td headers="Exp_Net">
            <xsl:if test="(sum(./bsk:Date/@income) - sum(./bsk:Date/bsk:Expense/@amount)) &lt; 0"><xsl:attribute name="class">hole</xsl:attribute></xsl:if>
            <xsl:value-of select="format-number(sum(./bsk:Date/@income) - sum(./bsk:Date/bsk:Expense/@amount), '$#.00')" />
        </td>
    </tr></tfoot>    
</table></xsl:for-each>

6 月份的什一奉献是 6.20 美元和 10.90 美元,加起来应该是 17.10 美元。但由于我那个月的总收入是 169.75 美元,它被四舍五入到只有 17.00 美元。因此,我的净值应该是 90.15 美元,现在显示为 90.25 美元,太高了 10 美分。

【问题讨论】:

  • XSLT 1.0 无法对计算值求和。如果您想要四舍五入值的总和,则需要分两遍执行此操作:首先,计算四舍五入的数量并将它们存储在一个变量中,然后将存储在变量中的数量相加。或者使用递归模板来累积四舍五入的金额(这将是您真正想要一个运行总计的方法 - 我不确定我是否在您的代码中看到了这一点)。
  • 根据您的建议,我计算四舍五入的金额并将它们存储在一个变量中:我确实有以下内容: 然后我将如何对这个变量中的金额求和?此外,也许运行总计在这里是错误的术语。每月总计会更好。我很抱歉。

标签: xml variables xslt-1.0 cumulative-sum


【解决方案1】:

考虑以下简化示例:

XML

<input>
    <entry date="2019-07-01" amount="61.30"/>
    <entry date="2019-07-02" amount="108.45"/>
</input>

XSLT 1.0 (+ EXSLT node-set())

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- first pass -->
<xsl:template match="/input" >
    <!-- first pass -->
    <xsl:variable name="pre-process-entries">
        <xsl:for-each select="entry">
            <entry date="{@date}" amount="{@amount}" tithe="{ceiling(@amount) div 10}"/>
        </xsl:for-each>
    </xsl:variable>
    <xsl:variable name="entries" select="exsl:node-set($pre-process-entries)/entry"/>
    <!-- output -->
    <table border="1">
        <tr>
            <th>Date</th>
            <th>Amount</th>
            <th>Tithe</th>
        </tr>
        <xsl:for-each select="$entries">
            <tr>
                <td>
                    <xsl:value-of select="@date"/>
                </td>
                <td>
                    <xsl:value-of select="format-number(@amount, '$#.00')"/>
                </td>
                <td>
                    <xsl:value-of select="format-number(@tithe, '$#.00')"/>
                </td>
            </tr>
        </xsl:for-each>
        <tr>
            <th>TOTAL</th>
            <th>
                <xsl:value-of select="format-number(sum($entries/@amount), '$#.00')"/>
            </th>
            <th>
                <xsl:value-of select="format-number(sum($entries/@tithe), '$#.00')"/>
            </th>
        </tr>
    </table>
</xsl:template>

</xsl:stylesheet>

结果

<?xml version="1.0" encoding="utf-8"?>
<table border="1">
  <tr>
    <th>Date</th>
    <th>Amount</th>
    <th>Tithe</th>
  </tr>
  <tr>
    <td>2019-07-01</td>
    <td>$61.30</td>
    <td>$6.20</td>
  </tr>
  <tr>
    <td>2019-07-02</td>
    <td>$108.45</td>
    <td>$10.90</td>
  </tr>
  <tr>
    <th>TOTAL</th>
    <th>$169.75</th>
    <th>$17.10</th>
  </tr>
</table>

渲染

【讨论】:

  • 到目前为止,谢谢。 :) 这很好用——但只是在一定程度上。我有一个约会,我有开支,但没有卖弄。我没有“收入”属性,所以我必须添加一个值为 0 的属性。当属性可能不存在时,有没有办法处理?其次,您会注意到我的 Date 元素有 子元素。我不得不将 XML 文件放入一个变量中并引用它来列出费用。有没有办法将那些 节点克隆到 $pre-process-entries 变量中,还是我做的唯一方法?
  • 输入没有收入的问题有几种处理方式。例如,您可以使用xsl:if 有条件地添加值为0 的属性。恐怕我不明白另一个问题,听起来应该单独提出一个问题。
  • 我使用选择/何时/其他设置来解决没有收入的问题,将收入和什一税都设置为 0。此外,我发现对费用元素的测试和嵌套的 for-each 循环有效将 Expense 元素添加到节点集就好了。非常感谢您的帮助。
猜你喜欢
  • 2018-09-20
  • 1970-01-01
  • 2018-01-12
  • 2012-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-13
  • 1970-01-01
相关资源
最近更新 更多