XSLT - 使用 round() 函数

问题描述 投票:0回答:5

我有这样的 XML 内容,

<doc>
    <p>20</p>
    <p>20</p>
    <p>20</p>
    <p>100</p>
    <t>160</t>
</doc>

有四个

<p>
元素包含数字,
<t>
代表以上四个
<p>
元素的总和。

我的目标是计算这些

<p>
元素的百分比并显示结果。

这是我为其编写的 XSL 代码,

    <xsl:variable name="val1" select="abc:get-int-value(doc/p[1]/text())" as="xs:double"/>
    <xsl:variable name="val2" select="abc:get-int-value(doc/p[2]/text())" as="xs:double"/>
    <xsl:variable name="val3" select="abc:get-int-value(doc/p[3]/text())" as="xs:double"/>
    <xsl:variable name="val4" select="abc:get-int-value(doc/p[4]/text())" as="xs:double"/>
    <xsl:variable name="valTotal" select="abc:get-int-value(doc/t/text())" as="xs:double"/>

    <xsl:variable name="precentage1" select="round(($val1 div $valTotal)*100)" as="xs:double"/>
    <xsl:variable name="precentage2" select="round(($val2 div $valTotal)*100)" as="xs:double"/>
    <xsl:variable name="precentage3" select="round(($val3 div $valTotal)*100)" as="xs:double"/>
    <xsl:variable name="precentage4" select="round(($val4 div $valTotal)*100)" as="xs:double"/>

    <xsl:template match="doc">
        <xsl:value-of select="$precentage1"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="$precentage2"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="$precentage3"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="$precentage4"/>
    </xsl:template>

    <xsl:function name="abc:get-int-value" as="xs:double">
        <xsl:param name="text" as="xs:string"/>

        <xsl:analyze-string select='$text' regex='\d+'>
            <xsl:matching-substring>
                <xsl:sequence select="number(.)"/>
            </xsl:matching-substring>
        </xsl:analyze-string>
    </xsl:function>

但是,它给出的百分比值为 13、13、13 和 63。所以这些数字的总数是 102(字面上应该是 100、99 或 101)。看来 p[4] 的百分比值已四舍五入为 63,而不是 62。

为什么会发生这种情况以及如何解决这个问题?

xml xslt xslt-2.0
5个回答
1
投票

为什么会发生这种情况

您的期望值是错误的,甚至没有意义。

20 div 160
为 12.5,
100 div 160
为 62.5。 12.5 向上舍入为 13,62.5 向上舍入为 63,这些是您看到的值。

四舍五入本身会产生一个不精确的值,因此您不能指望四个四舍五入的百分比总和为 100。

我该如何解决这个问题

我认为您需要决定如何解决这种差异。

round()
功能完全按照预期工作。


1
投票

我该如何解决这个问题?

正如其他人已经解释的那样,您无法“修复”此问题。

但是,您可以通过使用

round-half-to-even()
而不是
round()
来稍微缓解该问题。事实上,在给定的示例中,它只会将问题转移到另一边 - 即结果将是 12, 12, 12, 62,总共 98。但平均而言,舍入误差会更小。


1
投票

有关以总和为 100 的方式对一组百分比进行舍入的算法的一些讨论(但不是专门在 XSLT 上下文中),请参阅

如何使四舍五入的百分比加起来为100%


0
投票

这就是

round
函数的工作原理:它返回一个最接近参数值的整数,这意味着
round(62.5) = 63

您可以从 100 中提取 precentage1、precentage2 和 precentage3 并得到 precentage4,因为所有这三个百分比值总共应为 100%,即:

<xsl:variable name="precentage4" select="100 - $precentage1 - $precentage2 - $precentage3" as="xs:double"/>

0
投票

所有百分比均以

.5
结尾,因此向上舍入,从而获得
4 x .5 = 2
额外百分点。

百分比主要用于给出相对于整体的金额的粗略概念,因此要使它们准确,就需要而不是对它们进行四舍五入,如果总数是大于 2 的质数(导致无穷大),则这是有问题的小数位)。

这就是为什么在包含百分比的表格后面添加像

The percentages will not total to 100 due to rounding.
这样的注释。

© www.soinside.com 2019 - 2024. All rights reserved.