3

I have the following value in my XML -1.8959581529998104E-4. I want to format this to the exact number it should be using XSL to give me -0.000189595815299981.

format-number(-1.8959581529998104E-4,'0.000000;-0.000000') gives me NaN.

Any ideas?

zx485
  • 28,498
  • 28
  • 50
  • 59
Andez
  • 5,588
  • 20
  • 75
  • 116

5 Answers5

16

XSLT 1.0 does not have support for scientific notation.

This: number('-1.8959581529998104E-4') Result: NaN

This: number('-0.000189595815299981') Result: -0.000189595815299981

XSLT 2.0 has support for scientific notation

This: number('-1.8959581529998104E-4') Result: -0.000189595815299981

EDIT: A very simple XSLT 1.0 workaround:

<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>

With this input:

<number>-1.8959581529998104E-4</number>

Output:

-0.00018959581529998104
W. Churchill
  • 346
  • 1
  • 7
  • 28
  • @Alejandro, thanks again!!! I'm trying to get my transform to work using VS2008 in the IDE. Do I need to do something to force it to use version 2.0 for xsl? I.e ? – Andez Dec 06 '10 at 15:25
  • Just looked on MSDN Forums and version 2.0 is not supported in VS2008. :-( – Andez Dec 06 '10 at 15:36
  • @Andez: It looks like you can use a XSLT 2.0 implementation, but you can't integrate them with VS. Link: http://stackoverflow.com/questions/4099051/saxon-with-visual-studio-2010-is-there-a-way-to-use-the-debugger –  Dec 06 '10 at 15:37
  • The template posted in this answer doesn't correctly handle positive exponents when they are not preceded by a '+' symbol (e.g. 2E4), see my modified version below: https://stackoverflow.com/a/56671831/2047725 – w5m Jun 19 '19 at 19:34
4

This is based on user357812 answer. But I made it act like a function and handle non-scientific notation

<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>

Usage:

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

This should handle a mix of scientific notation and decimal values.

Moop
  • 3,414
  • 2
  • 23
  • 37
  • The template posted in this answer doesn't correctly handle positive exponents when they are not preceded by a '+' symbol (e.g. 2E4), see my modified version below: https://stackoverflow.com/a/56671831/2047725 – w5m Jun 19 '19 at 19:36
1

Another possible workaround without a template:

<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')"/>
Grugh
  • 11
  • 1
1

The logic doesn't appear to work correctly in the above answers by Moop and user357812 when determining vFactor in one particular scenario.

If vExponent is a single-digit positive number (without a preceding '+' sign), then vFactor is set to an empty string. This is because an assumption was made that the 1st character of vExponent would be a plus/minus sign and therefore the 2nd character onwards were of interest. The vMantissa variable is then multiplied by an empty string which results in the template outputting NaN.

If vExponent is a multi-digit positive number (without a preceding '+' sign), then vFactor is set to an incorrect value. Because of the aforementioned assumption, the 1st digit is ignored and the vMantissa is then multiplied by an incorrect vFactor.

Therefore, I've modified the previously posted code a little so that it can handle scientific numbers of the forms: 2E-4, 2E+4 and 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>
w5m
  • 2,286
  • 3
  • 34
  • 46
  • But this broke exponents that _do_ have a '+' sign (at least in mono's XSLT processor). If you change the line to select="translate(translate($vExponent, '-', ''), '+', ''", it fixes the bug. I would do an edit but that seems rude. – tekHedd Dec 10 '19 at 18:10
0

Just tried this with xsltproc using libxslt1.1 in version 1.1.24 under Linux:

XSLT 1.1 is able to read in exponential/scientific format now even without any dedicated template, it seems to simply work :-))

Achim
  • 442
  • 1
  • 3
  • 13