XSL - проблема округления / формата числа - PullRequest
26 голосов
/ 27 сентября 2010

Я пытаюсь получить значение числа с точностью до 2 разрядов из моего xml.

XML: <Quantity>0.0050</Quantity>

XSL: <xsl:value-of select="format-number($quantity, '####0.00')" />

Однако XSL, похоже, имеет проблему с этим значением и выводит 0.00 в одной области страницы и 0.01 в другой. Конечно, в этой ситуации выгодно иметь 0.01 выход во всех областях.

Другая область имеет значение 4.221, но XSL выводит 4.23.

Я понимаю, что format-number как метод преобразует число в строку.

Не уверен, как это исправить.


EDIT:

Ладно, после небольшого осмотра я обнаружил, что это работает:

<xsl:value-of select='format-number( round(100*$quantity) div 100 ,"##0.00" )' />

Через этот веб-сайт

Поскольку этот парень упоминает, что XSL использует «округление банкиров» для округления до четных чисел вместо больших.

Решение вряд ли кажется изящным и означает добавление тонны дополнительных функций в и без того громоздкий и сложный файл XSL. Конечно, я что-то упустил?

Ответы [ 4 ]

20 голосов
/ 27 сентября 2010

Не уверен, почему формат будет таким противоречивым, но из памяти спецификация для него ... сложна.

Тем временем вы можете использовать функцию round ( ref ).Что менее чем идеально, но функционально.Если вам нужно определенное количество фиговых фиг, вы можете использовать СИЛА МАТОВ! и делать что-то вроде:

<xsl:value-of select="round(yournum*100) div 100"/>

15 голосов
/ 13 февраля 2013

У меня были бесконечные проблемы с десятичными знаками в XSLT / XPath 1.0, часто в комбинации, представляющей десятичные числа в виде чисел с плавающей запятой, и с использованием округления до половины (округление банкира).К сожалению, подход round(yournum*100) div 100 не работал для меня из-за неточности с плавающей запятой.Например, умножение 1.255 на 100 дает 125.49999999999999 (это не должно зависеть от реализации, поскольку предполагается, что это IEEE 754, но я не знаю, все ли реализации придерживаются этого).Когда округлено, это дает 125, а не желаемое значение 126.

Я выбрал следующий подход, который, я думаю, работает (хотя это всегда сложная область, поэтому я не буду заявлять слишком много уверенности!).Однако это зависит от вашего движка XSLT, поддерживающего расширения EXSLT.Предполагается, что вы хотите округлить до двух десятичных знаков.

<func:function name="local:RoundHalfUp">
    <xsl:param name="number"/>

    <xsl:choose>
        <xsl:when test="contains($number, '.')">
            <xsl:variable name="decimal" select="estr:split($number, '.')[2]"/>
            <xsl:choose>
                <xsl:when test="string-length($decimal) &gt; 2">
                    <func:result select="format-number(concat($number, '1'), '0.00')"/>
                </xsl:when>
                <xsl:otherwise>
                    <func:result select="format-number($number, '0.00')"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
            <func:result select="format-number($number, '0.00')"/>
        </xsl:otherwise>
    </xsl:choose>

</func:function>

, которые можно назвать так:

<xsl:value-of select="local:RoundHalfUp(1.255)"/>

Пространства имен:

xmlns:func="http://exslt.org/functions"
xmlns:estr="http://exslt.org/strings"
xmlns:local="http://www.acme.org/local_function"

Это важноотметить, что функция добавляет a '1', а не добавляет 0,001 или аналогичный.

Определенно лучше использовать XSLT 2.0, если это опция (поскольку она имеет правильный десятичный тип), ноЯ знаю, что это часто не вариант (из мучительного опыта!).

0 голосов
/ 02 августа 2018

Я также столкнулся с проблемой, из-за которой, если вы сделали округление ($ number * 100) div 100, вы получили представление с плавающей запятой .4999999 и округление не работает должным образом.это, это, кажется, работает: round ($ число * 1000 div 10) div 100

0 голосов
/ 17 мая 2018

По сравнению со всеми приведенными выше ответами

<xsl:value-of select="format-number(xs:decimal($quantity), '####0.00')" />

полезно, оно не усекает значения десятичной точки.усечение точно указанных чисел.если число в экспоненциальном формате, мы можем использовать его следующим образом:

<xsl:value-of select="format-number(xs:decimal(number($quantity)), '####0.00')" />

Спасибо

...