Форматирование десятичных значений для XML - PullRequest
3 голосов
/ 28 июня 2011

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

Моя система на основе Java в настоящее время преобразует объекты в XML с помощью XStream. У нас есть XSD, который сопровождает XML и определяет различные элементы как string, double, dateTime и т. Д.

У меня есть три двойных поля, которые содержат значения, такие как 12.5, 100.123, 5.23445 и т. Д. В настоящее время они в значительной степени преобразованы в XML. Мне нужно, чтобы эти значения были отформатированы в XML до одного десятичного знака; 12,5, 100,1, 5,2 и т. Д.

Я кратко обдумал варианты для достижения этой цели:

  • Каким-то образом Java форматирует эти значения с такой точностью, прежде чем перейти к XML. Возможно, NumberFormat может сделать это, хотя я думал, что это в основном для использования с выходом String.
  • Надеюсь, что XSD может сделать это для меня; Я знаю, что вы можете наложить ограничения на точность в XSD, но я не уверен, действительно ли он обрабатывает само округление или просто скажет «это значение 123.123 недопустимо для этой схемы»?
  • Используйте XSLT, чтобы как-то выполнить это для меня.

Я бы выбрал ваши коллективные мозги относительно того, что было бы «приемлемым» способом / наилучшей практикой для использования в такой ситуации.

Спасибо, Дэйв.

Ответы [ 2 ]

4 голосов
/ 28 июня 2011

Это можно сделать в одном выражении XPath.

Использовать :

floor(.) + round(10*(. -floor(.))) div 10

Проверка с использованием XSLT в качестве хоста XPath :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="text()[contains(.,'.')]">
    <xsl:value-of select=
     "floor(.) + round(10*(. -floor(.))) div 10"/>
 </xsl:template>
</xsl:stylesheet>

, когда это преобразование применяется к следующему документу XML :

<t>
 <n>12.5</n>
 <n>100.123</n>
 <n>5.26445</n>
</t>

желаемый, правильный результат:

<t>
   <n>12.5</n>
   <n>100.1</n>
   <n>5.3</n>
</t>

Пояснение : Использование стандартных функций XPath floor(), round() и оператор XPath div и ваша логика.

Обобщенное выражение :

floor(.) + round($vFactor*(. -floor(.))) div $vFactor

где $vFactor равно 10^N, где N - количество цифр после запятой, которое мы хотим.

Используя это выражение, модифицированное XSLT-преобразование будет таким :

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>

     <xsl:param name="pPrecision" select="4"/>

     <xsl:variable name="vFactor" select=
     "substring('10000000000000000000000',
                 1, $pPrecision+1
                )
     "/>

     <xsl:template match="node()|@*">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>

     <xsl:template match="text()[contains(.,'.')]">
        <xsl:value-of select=
         "floor(.) + round($vFactor*(. -floor(.))) div $vFactor"/>
     </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к тому же XML-документу (см. Выше), мы создаем требуемый вывод для любого значащего значения $pPrecision. В приведенном выше примере оно установлено на4 ирезультат содержит все числа, округленные до четырех цифр после десятичной точки:

<t>
   <n>12.5</n>
   <n>100.123</n>
   <n>5.2645</n>
</t>
4 голосов
/ 28 июня 2011

XStream имеет преобразователей ( учебник ).Вы должны будете зарегистрировать свой собственный конвертер Double, который справится с этим.В конвертере используйте DecimalFormat для ограничения количества десятичных знаков.

...