【问题标题】:Formatting scientific number representation in xsl在 xsl 中格式化科学数字表示
【发布时间】:2010-12-06 15:07:13
【问题描述】:

我的 XML -1.8959581529998104E-4 中有以下值。我想将其格式化为它应该使用 XSL 给我的确切数字 -0.000189595815299981。

format-number(-1.8959581529998104E-4,'0.000000;-0.000000') 给我 NaN。

有什么想法吗?

干杯

安德斯

【问题讨论】:

    标签: xslt numbers format


    【解决方案1】:

    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 版吗?即 w3.org/1999/XSL/Transform"> ?
    • 刚在 MSDN 论坛上看过,VS2008 不支持 2.0 版。 :-(
    • @Andez:看起来您可以使用 XSLT 2.0 实现,但不能将它们与 VS 集成。链接:stackoverflow.com/questions/4099051/…
    • 是的,很好的答案@Alejandro。这对我很有用。再次感谢
    • 当正指数前面没有“+”符号(例如 2E4)时,此答案中发布的模板无法正确处理正指数,请参阅下面的修改版本:stackoverflow.com/a/56671831/2047725
    【解决方案2】:

    这是基于 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)时,此答案中发布的模板无法正确处理正指数,请参阅下面的修改版本:stackoverflow.com/a/56671831/2047725
    【解决方案3】:

    没有模板的另一种可能的解决方法:

    <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 实现。 :)
    【解决方案4】:

    在一种特定情况下确定vFactor 时,Moopuser357812 的上述答案中的逻辑似乎无法正常工作。

    如果vExponent 是一位正数(前面没有“+”号),则vFactor 设置为空字符串。这是因为假设vExponent 的第一个字符将是一个加号/减号,因此第二个字符以后是有意义的。然后将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, '-', ''), '+', ''",它将修复错误。我会进行编辑,但这似乎很粗鲁。
    【解决方案5】:

    刚刚在 Linux 下使用 1.1.24 版中的 libxslt1.1 与 xsltproc 进行了尝试:

    即使没有任何专用模板,XSLT 1.1 现在也能够以指数/科学格式读取,它似乎很简单:-))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多