在XSL中格式化科学数字表示法

3
我在我的XML中有以下数值-1.8959581529998104E-4。我想使用XSL将其格式化为应有的确切数字-0.000189595815299981
format-number(-1.8959581529998104E-4,'0.000000;-0.000000') gives me NaN.

有什么想法吗?
5个回答

16

XSLT 1.0不支持科学计数法。

这个: number('-1.8959581529998104E-4') 结果:NaN

这个: number('-0.000189595815299981') 结果:-0.000189595815299981

XSLT 2.0支持科学计数法

这个: number('-1.8959581529998104E-4') 结果:-0.000189595815299981

编辑:一个非常简单的XSLT 1.0解决方法:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="number[substring-after(.,'E')]">
        <xsl:variable name="vExponent" select="substring-after(.,'E')"/>
        <xsl:variable name="vMantissa" select="substring-before(.,'E')"/>
        <xsl:variable name="vFactor"
             select="substring('100000000000000000000000000000000000000000000',
                               1, substring($vExponent,2) + 1)"/>
        <xsl:choose>
            <xsl:when test="starts-with($vExponent,'-')">
                <xsl:value-of select="$vMantissa div $vFactor"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$vMantissa * $vFactor"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>
使用这个输入:
<number>-1.8959581529998104E-4</number>

输出:

-0.00018959581529998104

@Alejandro,再次感谢!!!我正在尝试在IDE中使用VS2008使我的转换工作。我需要做些什么来强制它使用xsl的2.0版本吗?即 <xsl:stylesheet version="2.0" xmlns:xsl="?" rel = "nofollow noreferrer">http://www.w3.org/1999/XSL/Transform">? - Andez
刚在 MSDN 论坛上看到,VS2008 不支持版本 2.0。 :-( - Andez
@Andez:看起来你可以使用XSLT 2.0实现,但是你无法将它们与VS集成。链接:http://stackoverflow.com/questions/4099051/saxon-with-visual-studio-2010-is-there-a-way-to-use-the-debugger - user357812
此答案中发布的模板在处理未以“+”符号(例如2E4)开头的正指数时存在问题,请参见我下面修改后的版本:https://dev59.com/ylLTa4cB1Zd3GeqPaXDC#56671831 - w5m

4

这是基于user357812的回答。但我将其改编成函数形式,并处理了非科学计数法。

<xsl:template name="convertSciToNumString" >
    <xsl:param name="inputVal" select="0"/>
    <xsl:variable name="vExponent" select="substring-after($inputVal,'E')"/>
    <xsl:variable name="vMantissa" select="substring-before($inputVal,'E')"/>
    <xsl:variable name="vFactor"
         select="substring('100000000000000000000000000000000000000000000',
                           1, substring($vExponent,2) + 1)"/>
    <xsl:choose>
        <xsl:when test="number($inputVal)=$inputVal">
            <xsl:value-of select="$inputVal"/>
        </xsl:when>
        <xsl:when test="starts-with($vExponent,'-')">
            <xsl:value-of select="format-number($vMantissa div $vFactor, '#0.#############')"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="format-number($vMantissa * $vFactor, '#0.#############')"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

使用方法:

<xsl:template match="X">
    <X>
        <xsl:call-template name="convertSciToNumString">
            <xsl:with-param name="inputVal" select="text()"/>
        </xsl:call-template>
    </X>    
</xsl:template>

这应该处理科学计数法和小数值的混合使用。


此答案中发布的模板无法正确处理正指数,当它们不以 "+" 符号(例如 2E4)开头时,请参见我下面修改过的版本:https://dev59.com/ylLTa4cB1Zd3GeqPaXDC#56671831 - w5m

1
在确定一个特定场景中的vFactor时,Moopuser357812所提供的答案中似乎逻辑不正确。
如果vExponent是一个个位正数(没有前面的“+”符号),那么vFactor被设置为空字符串。这是因为假设第一个字符是加号/减号符号,因此从第二个字符开始才是有用的。然后vMantissa变量与空字符串相乘,导致模板输出NaN。
如果vExponent是一个多位数的正数(没有前面的“+”符号),那么vFactor被设置为一个错误的值。由于上述假设,第一个数字被忽略,然后vMantissa乘以一个错误的vFactor。
因此,我稍微修改了之前发布的代码,使其能够处理科学计数法形式的数字:2E-4、2E+4和2E4。
<xsl:template name="convertSciToNumString" >
    <xsl:param name="inputVal" select="0"/>
    <xsl:variable name="vMantissa" select="substring-before(., 'E')"/>
    <xsl:variable name="vExponent" select="substring-after(., 'E')"/>
    <xsl:variable name="vExponentAbs" select="translate($vExponent, '-', '')"/>
    <xsl:variable name="vFactor" select="substring('100000000000000000000000000000000000000000000', 1, substring($vExponentAbs, 1) + 1)"/>
    <xsl:choose>
        <xsl:when test="number($inputVal)=$inputVal">
            <xsl:value-of select="$inputVal"/>
        </xsl:when>
        <xsl:when test="starts-with($vExponent,'-')">
            <xsl:value-of select="format-number($vMantissa div $vFactor, '#0.#############')"/>
        </xsl:when>
        <xsl:otherwise>         
            <xsl:value-of select="format-number($vMantissa * $vFactor, '#0.#############')"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

但是这会破坏指数中带有“+”符号的部分(至少在Mono的XSLT处理器中是如此)。如果您将该行更改为select="translate(translate($vExponent, '-', ''), '+', ''",则可以修复该错误。我想进行编辑,但那似乎很粗鲁。 - tekHedd

1
另一个可能的解决办法,不需要模板:

<xsl:stylesheet version="1.0" ... xmlns:java="http://xml.apache.org/xslt/java">
...
<xsl:value-of select="format-number(java:java.lang.Double.parseDouble('1E-6'), '0.000')"/>

只适用于Java,不适用于其他XSLT实现。 :) - Macke

0

我刚刚在 Linux 下使用版本为 1.1.24 的 libxslt1.1 尝试了一下 xsltproc:

XSLT 1.1 现在即使没有任何专用模板,也能读取指数/科学格式的内容,看起来很顺利 :-))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接