Подтвердить что ты не робот

XSL-проблема округления/номера формата

Я пытаюсь получить значение числа до 2 dec мест из моего 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 файлу. Неужели я чего-то не хватает?

4b9b3361

Ответ 1

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

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

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

Ответ 2

У меня была бесконечная проблема с десятичными знаками в 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"

Важно отметить, что функция добавляет '1', а не добавляет 0.001 или аналогичную.

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