Java 格式化XML的十进制值

Java 格式化XML的十进制值,java,xml,xslt,xsd,xstream,Java,Xml,Xslt,Xsd,Xstream,我目前遇到一个问题,我们正在连接的系统希望接收XML,其中包含三个格式化为小数点后一位的双字段。就我个人而言,我觉得我们的系统应该能够以默认格式发送值,然后由其他系统按照自己的意愿格式化它们自己的表示,但遗憾的是,这似乎不是一个选项 我的基于Java的系统目前正在通过使用XStream将对象转换为XML。我们有一个伴随XML的XSD,它将各种元素定义为string、double、dateTime等 我有三个双字段,它们包含12.5、100.123、5.23445等值。现在它们被转换成XML。我需

我目前遇到一个问题,我们正在连接的系统希望接收XML,其中包含三个格式化为小数点后一位的双字段。就我个人而言,我觉得我们的系统应该能够以默认格式发送值,然后由其他系统按照自己的意愿格式化它们自己的表示,但遗憾的是,这似乎不是一个选项

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

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

我简要地想到了实现这一目标的各种方案:

  • 以某种方式让Java在将这些值转换为XML之前将其格式化为这种精度。也许NumberFormat可以做到这一点,尽管我认为它主要用于字符串输出
  • 希望XSD能为我做到这一点;我知道你可以在XSD中限制精度,但我不确定它是否真的处理舍入本身,或者只是说“123.123的这个值对于这个模式无效”
  • 使用XSLT以某种方式为我实现这一点
我想请大家集思广益,看看在这种情况下使用什么样的“公认”方式/最佳实践

谢谢,
Dave.

XStream有()。您必须注册自己的双转换器来处理此问题。在转换器中,用于限制小数位数。

这可以在单个XPath表达式中完成

使用

floor(.) + round(10*(. -floor(.))) div 10
<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>
<t>
 <n>12.5</n>
 <n>100.123</n>
 <n>5.26445</n>
</t>
floor(.) + round($vFactor*(. -floor(.))) div $vFactor
<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>
使用XSLT作为XPath主机进行验证

floor(.) + round(10*(. -floor(.))) div 10
<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>
<t>
 <n>12.5</n>
 <n>100.123</n>
 <n>5.26445</n>
</t>
floor(.) + round($vFactor*(. -floor(.))) div $vFactor
<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>
其中
$vFactor
10^N
,其中
N
是小数点后的位数

使用此表达式,修改后的XSLT转换如下所示:

floor(.) + round(10*(. -floor(.))) div 10
<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>
<t>
 <n>12.5</n>
 <n>100.123</n>
 <n>5.26445</n>
</t>
floor(.) + round($vFactor*(. -floor(.))) div $vFactor
<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>

展示一些代码,也许我们可以从上下文中得到一些帮助。XSLT2.0是否适合您?您将有
format-number()
xsl:decimal-format
供您使用。@Don-目前没有任何相关的代码。我正在仔细考虑上面提到的3个选择@empo—我需要研究XStream是否支持XSLT2.0;如果是这样的话,这些可能会有所帮助。好问题,+1。有关完整、简短且简单的XPath单行程序解决方案,请参见我的答案:)我还添加了一个通用表达式,该表达式可以执行任意精度的舍入操作。:)很好的建议-转换器可以锁定到一组特定的元素吗?我在XML中有很多双精度,但如果我只希望价格相关的双精度是。1例如…@Bozho:您可能有兴趣在我的答案中看到纯XPath解决方案:)@Bozho:为什么?你能提出一个简单的表达吗?不,这就是为什么我没有提出一个表达的原因: