You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中XSLT转换XML节点值异常:科学计数法问题求助

解决XSLT转换中数值输出为科学计数法的问题

问题背景

你的Java XSLT转换程序已经稳定运行10年,近期突然出现异常:处理源XML中的<Sold>1064623.94</Sold>节点时,Java程序输出的结果是<Sold amountCurrencyID="EUR">1.06462394E6</Sold>(科学计数法格式),但在线XSLT转换工具能输出正确的<Sold amountCurrencyID="EUR">1064623.94</Sold>。这种格式问题影响了后续Java方法的执行,你怀疑问题出在javax.xml.Transformer或xml-apis-1.3.04.jar库,当前使用的是Saxon的TransformerFactoryImpl。

相关代码片段

XSLT节点代码

<Sold> 
<xsl:attribute name="amountCurrencyID" namespace="">EUR</xsl:attribute> 
<xsl:value-of select="string(number(string($var4_resultof_first/*[local-name()='Sold' ])))"/> 
</Sold>

Java转换核心代码

public void convert() throws ClassNotFoundException, InstantiationException, IllegalAccessException, TransformerException { 
    TransformerFactory transformerFactory = new net.sf.saxon.TransformerFactoryImpl(); 
    Source xsltSource = new StreamSource(new ByteArrayInputStream(this.getUserInfo().getXslt())); 
    Templates templates = transformerFactory.newTemplates(xsltSource); 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    Source xmlSource = new StreamSource(getBais()); 
    Result result = new StreamResult(getBaos()); 
    Transformer transformer = templates.newTransformer(); 
    transformer.setErrorListener(new XsltErrorListener()); 
    if(this.getParametros()!=null && this.getParametros().size()>0){ 
        String nombre=""; 
        for (Enumeration enumer = this.getParametros().keys();enumer.hasMoreElements();){ 
            nombre=(String)enumer.nextElement(); 
            transformer.setParameter(nombre, this.getParametros().get(nombre)); 
        } 
    } 
    transformer.transform(xmlSource, result); 
}

问题根源

问题出在XSLT中多余的嵌套转换逻辑:string(number(string(...)))。

  1. 源节点<Sold>的值本身已经是字符串类型的数值,你先转成字符串(冗余操作)、再转成数值、最后又转回字符串。
  2. 当把较大的浮点数转回字符串时,Saxon(受版本或配置影响)会采用科学计数法格式化,而在线工具使用的处理器可能默认保留标准十进制格式。
  3. 这层多余的数值转换完全是画蛇添足,反而引入了数值格式化的不确定性。

解决方案

方案1:移除冗余转换(最优解)

直接使用源节点的原始字符串值,彻底避免数值转换带来的格式化问题:

<Sold> 
<xsl:attribute name="amountCurrencyID" namespace="">EUR</xsl:attribute> 
<xsl:value-of select="$var4_resultof_first/*[local-name()='Sold']"/> 
</Sold>

这个方法既能完全保留原始格式,又减少了不必要的计算开销,是最可靠的解决方式。

方案2:用format-number()显式控制格式

如果必须确保值是合法数值后再输出,可以用format-number()强制指定非科学计数法的格式:

<Sold> 
<xsl:attribute name="amountCurrencyID" namespace="">EUR</xsl:attribute> 
<xsl:value-of select="format-number(number($var4_resultof_first/*[local-name()='Sold']), '#.00')"/> 
</Sold>

其中#.00表示保留两位小数,你可以根据实际需求调整格式:比如#.##表示最多保留两位小数,0.00则强制显示两位小数(即使末尾是0)。

方案3:检查Saxon版本与配置

如果近期更新过依赖库(比如Saxon或xml-apis),版本变更可能导致数值格式化行为改变:

  • 对比当前使用的Saxon版本和之前稳定运行的版本,查看版本差异文档;
  • 可以尝试为Transformer设置Saxon特有的参数,控制数值输出格式(具体参数参考对应版本的官方文档)。临时解决的话,回退到之前稳定的库版本也是可行的,但长期来看优化XSLT逻辑更稳妥。

验证建议

修改XSLT后,先通过在线工具测试确认输出符合预期,再部署到Java程序中验证结果。如果是版本问题,回退库版本时要确保不会影响其他依赖功能。

内容的提问来源于stack exchange,提问作者javalderas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:21:13