我有这样的 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。
为什么会发生这种情况以及如何解决这个问题?
为什么会发生这种情况
您的期望值是错误的,甚至没有意义。
20 div 160
为 12.5,100 div 160
为 62.5。 12.5 向上舍入为 13,62.5 向上舍入为 63,这些是您看到的值。
四舍五入本身会产生一个不精确的值,因此您不能指望四个四舍五入的百分比总和为 100。
我该如何解决这个问题
我认为您需要决定如何解决这种差异。
round()
功能完全按照预期工作。
我该如何解决这个问题?
正如其他人已经解释的那样,您无法“修复”此问题。
但是,您可以通过使用
round-half-to-even()
而不是 round()
来稍微缓解该问题。事实上,在给定的示例中,它只会将问题转移到另一边 - 即结果将是 12, 12, 12, 62,总共 98。但平均而言,舍入误差会更小。
有关以总和为 100 的方式对一组百分比进行舍入的算法的一些讨论(但不是专门在 XSLT 上下文中),请参阅
这就是
round
函数的工作原理:它返回一个最接近参数值的整数,这意味着 round(62.5) = 63
您可以从 100 中提取 precentage1、precentage2 和 precentage3 并得到 precentage4,因为所有这三个百分比值总共应为 100%,即:
<xsl:variable name="precentage4" select="100 - $precentage1 - $precentage2 - $precentage3" as="xs:double"/>
所有百分比均以
.5
结尾,因此向上舍入,从而获得 4 x .5 = 2
额外百分点。
百分比主要用于给出相对于整体的金额的粗略概念,因此要使它们准确,就需要而不是对它们进行四舍五入,如果总数是大于 2 的质数(导致无穷大),则这是有问题的小数位)。
这就是为什么在包含百分比的表格后面添加像
The percentages will not total to 100 due to rounding.
这样的注释。