格式化XML的十进制值

时间:2011-06-28 11:13:34

标签: java xml xslt xsd xstream

我现在遇到一个问题,我们连接的系统希望接收XML,其中包含三个格式化为一个小数位的双字段。就我个人而言,我觉得我们的系统应该能够以默认格式发送值,然后由其他系统根据需要格式化自己的表示形式,但是这似乎不是一种选择。

我的基于Java的系统目前正在通过使用XStream将对象转换为XML。我们有一个伴随XML的XSD,并将各种元素定义为string,double,dateTime等。

我有三个双字段,其中包含12.5,100.123,5.23445等值。现在它们几乎被转换为XML。我需要的是将这些值格式化为XML到一个小数位; 12.5,100.1,5.2等

我已经简要地想出了实现这个目标的选项:

  • 在转到XML之前,以某种方式将Java格式化为这种精度。也许NumberFormat可以做到这一点,虽然我认为这主要是用于使用String输出。
  • 希望XSD能为我做到这一点;我知道你可以限制XSD的精度,但是我不确定它是否实际处理了舍入本身,或者只是说“这个模式的123.123的值是无效的”?
  • 使用XSLT以某种方式为我完成此任务。

我会挑选你的集体大脑,了解在这种情况下使用的“接受”方式/最佳做法。

谢谢, 戴夫。

2 个答案:

答案 0 :(得分:4)

XStream有converterstutorial)。您必须注册自己的Double转换器来处理这个问题。在转换器中使用DecimalFormat来限制小数位数。

答案 1 :(得分:4)

这可以在单个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

其中$vFactor10^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的任何有意义的值生成所需的输出。在上面的示例中,它设置为{{ 1}}并且结果包含小数点后四位数的所有数字:

4