Solved

"NaN" in the XSLT

Posted on 2009-05-12
15
643 Views
Last Modified: 2013-11-18
Hi all,
           I see  NaN in my XSLT page, but it should have some value in it, when I checked the xml of it , I found E in the number, I guess this is creating an issue.  Could you please help me to fix it

<company_winloss pos="3" company_name="POS">
                  <wins>11657</wins>
                  <winPct>62.9</winPct>
                  <average_premium>1053.0</average_premium>
                  <pa_average_premium>1351.6127648623144</pa_average_premium>
                  <pa_prem>1.575575E7</pa_prem>
                  <prem>1.2269629E7</prem>
                  <company_key>3</company_key>
            </company_winloss>
0
Comment
Question by:balatrue
  • 6
  • 4
  • 3
  • +1
15 Comments
 
LVL 59

Expert Comment

by:Kevin Cross
ID: 24364017
0
 
LVL 59

Expert Comment

by:Kevin Cross
ID: 24364037
0
 
LVL 39

Expert Comment

by:abel
ID: 24364039
What version of XSLT are you using? Do you use it client side (browser), which is always XSLT 1.0, or do you use it server side? What XSLT processor do you use? (the brand name, actually: Saxon, Xalan, libxslt, Microsoft MSXML etc).
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 24364044
cast to number first

    <xsl:template match="pa_prem">
    <xsl:value-of select="format-number(number(.), '#0.#############')"/>
</xsl:template>
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 24364213
sorry, just remebered that this only works in an XSLT2 aware processor
... so, if this is XSLT2, simply go this way, otherwise, use the recursive approach shown before
0
 

Author Comment

by:balatrue
ID: 24365748
Hi Gertone & abel,
                          Thanks for a prompt response.   I am using Xalan here . So this

<xsl:template match="pa_prem">
    <xsl:value-of select="format-number(number(.), '#0.#############')"/>
</xsl:template>

will work i guess. I wil let you know if it fails.
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 24366037
it will not work in Xalan, sorry
0
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 

Author Comment

by:balatrue
ID: 24366424
I guess I have to change the number format even before that. right ? As per to my application we query the database and write a xml as a string. I have to handle it some where here .
0
 
LVL 39

Expert Comment

by:abel
ID: 24367310
That would be a viable solution, but you can very well do this in XSLT 1.0. The problem with 1.0 is that you get quite verbose code. This afternoon I played around a bit with the idea of having input of exponential notation and having numeric output (i.e., without the exp. notation).

So, 1.23E5 becomes 12300 and 1.23e-4 becomes 0.000123. Using the code below will do what you want. In the following post I will post the input / output in the code section.

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet

    xmlns:common="http://exslt.org/common"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"

    exclude-result-prefixes="common">

    

    <xsl:output indent="yes"/>

    

    <xsl:variable name="dot" select="'.'" />

    

    <xsl:template match="/">

        <output>

            <xsl:apply-templates select="*/pa_prem" />

        </output>

    </xsl:template>

    

    <xsl:template match="pa_prem">

        <outcome>

            <xsl:call-template name="calculate-exponent">

                <xsl:with-param name="number" select="text()" />

            </xsl:call-template>

        </outcome>

    </xsl:template>

    

    <xsl:template name="calculate-exponent">

        <xsl:param name="number" />

        <xsl:variable name="number-elem">

            <xsl:call-template name="numeric-elem">

                <xsl:with-param name="number" select="$number" />

            </xsl:call-template>

        </xsl:variable>

        <xsl:variable name="numeric-part">

            <xsl:value-of select="common:node-set($number-elem)/numeric-part"/>    

        </xsl:variable>

        <xsl:variable name="exponent">

            <xsl:value-of select="common:node-set($number-elem)/exponent"/>    

        </xsl:variable>

        

        <xsl:value-of select="concat($number, ' : ')"/>

        <xsl:if test="$exponent &gt;= 0">

            <xsl:value-of select="$numeric-part"/>

            <xsl:call-template name="repeat">

                <xsl:with-param name="repeat-count" select="$exponent" />

                <xsl:with-param name="string" select="'0'" />

            </xsl:call-template>

        </xsl:if>

        <xsl:if test="$exponent &lt; 0">

            <xsl:variable name="reverse-exp" select="-1 * $exponent" />

            <xsl:variable name="num-length" select="string-length($numeric-part)" />

            <xsl:choose>

                <xsl:when test="$reverse-exp &lt; $num-length">

                    <xsl:value-of select="substring($numeric-part, 1, $num-length - $reverse-exp)"/>

                    <xsl:value-of select="$dot" />

                    <xsl:value-of select="substring($numeric-part, $num-length - $reverse-exp + 1)"/>

                </xsl:when>

                <xsl:otherwise>

                    <xsl:value-of select="concat('0', $dot)"/>

                    <xsl:call-template name="repeat">

                        <xsl:with-param name="repeat-count" select="$reverse-exp - $num-length" />

                        <xsl:with-param name="string" select="'0'" />

                    </xsl:call-template>

                    <xsl:value-of select="$numeric-part"/>            

                </xsl:otherwise>

            </xsl:choose>            

        </xsl:if>

    </xsl:template>

    

    <xsl:template name="numeric-elem">

        <xsl:param name="number" />

        <!-- normalized means: no spaces and uppercase E -->

        <xsl:variable name="normalized-number" select="translate($number, 'e ', 'E')" />

        

        <!-- dot position is subtracted from the exponent -->

        <xsl:variable name="dot-position">

            <xsl:variable name="pos" select="string-length(substring-before($normalized-number, $dot))" />

            <xsl:if test="starts-with($normalized-number, concat('0', $dot))">

                <xsl:value-of select="1"/>

            </xsl:if>

            <xsl:if test="not (starts-with($normalized-number, concat('0', $dot)))">

                <xsl:value-of select="$pos"/>

            </xsl:if>

            <xsl:if test="not(contains($number, $dot))">

                <xsl:value-of select="0"/>

            </xsl:if>

        </xsl:variable>

        

        <!-- removes dot and exp part, if it is there -->

        <xsl:variable name="numeric-part">

            <xsl:variable name="before-e">

                <xsl:if test="contains($normalized-number, 'E')">

                    <xsl:value-of select="substring-before($normalized-number, 'E')"/>

                </xsl:if>

                <xsl:if test="not(contains($normalized-number, 'E'))">

                    <xsl:value-of select="$normalized-number"/>

                </xsl:if>

            </xsl:variable>

            <xsl:value-of select="translate($before-e, $dot, '')"/>

        </xsl:variable>

        

        <xsl:variable name="exponent">

            <xsl:choose>

                <xsl:when test="contains($normalized-number, 'E')">

                    <xsl:value-of select="substring-after($normalized-number, 'E')" />        

                </xsl:when>

                <xsl:otherwise>0</xsl:otherwise>

            </xsl:choose>

        </xsl:variable>

        

        <original><xsl:value-of select="$number"/></original>

        <numeric-part>

            <!-- this will remove any leading zeros -->

            <xsl:choose>

                <xsl:when test="contains($number, $dot) and starts-with($normalized-number, concat('0', $dot))">

                    <xsl:value-of select="substring($numeric-part, 2)" />

                </xsl:when>

                <xsl:otherwise>

                    <xsl:value-of select="number($numeric-part)" />        

                </xsl:otherwise>

            </xsl:choose>

            

        </numeric-part>

        <exponent>

            <xsl:choose>

                <xsl:when test="$dot-position = 0">

                    <xsl:value-of select="number($exponent)" />                    

                </xsl:when>

                <xsl:when test="$exponent &gt; 0">

                    <xsl:value-of select="$exponent + $dot-position - string-length($numeric-part)" />                    

                </xsl:when>

                <xsl:otherwise>

                    <xsl:value-of select="$exponent + $dot-position - string-length($numeric-part)" />                    

                </xsl:otherwise>

            </xsl:choose>            

        </exponent>

    </xsl:template>

    

    

    <xsl:template name="repeat">

        <xsl:param name="string" />

        <xsl:param name="repeat-count" />

        <xsl:if test="$repeat-count &gt; 0">

            <xsl:call-template name="repeat">

                <xsl:with-param name="repeat-count" select="$repeat-count - 1" />

                <xsl:with-param name="string" select="$string" />

            </xsl:call-template>

            <xsl:value-of select="$string" />

        </xsl:if>

    </xsl:template>

    

</xsl:stylesheet>

Open in new window

0
 
LVL 39

Expert Comment

by:abel
ID: 24367353
Using the following input it creates the following output.

The code was written quite quickly and although I did some checks, it may contain some errors. And, for the same reason, it may be optimized a bit.

I used an extension method that is available in Xalan (and most other processor): exslt:node-set (common:node-set in this code).

<!-- input -->

<company_winloss>

    <pa_prem>1.575575E7  </pa_prem>

    <pa_prem>1.57        </pa_prem>

    <pa_prem>0.57E0      </pa_prem>

    <pa_prem>1.57E-5     </pa_prem>

    <pa_prem>1.57E-4     </pa_prem>

    <pa_prem>1.57E-3     </pa_prem>

    <pa_prem>1.57E-2     </pa_prem>

    <pa_prem>0.57E-20    </pa_prem>

    <pa_prem>0.0000057E7 </pa_prem>

    <pa_prem>123456E7    </pa_prem>

    <pa_prem>123.456E7   </pa_prem>

    <pa_prem>123.456E12  </pa_prem>

    <pa_prem>0.123456E7  </pa_prem>

    <pa_prem>001234.56E12</pa_prem>

    <pa_prem>1234.56E12  </pa_prem>

    <pa_prem>1.2269629E7 </pa_prem>

    <company_key>3</company_key>

</company_winloss>
 

<!-- output -->

<output>

   <outcome>1.575575E7   : 15755750</outcome>

   <outcome>1.57         : 1.57</outcome>

   <outcome>0.57E0       : 0.57</outcome>

   <outcome>1.57E-5      : 0.0000157</outcome>

   <outcome>1.57E-4      : 0.000157</outcome>

   <outcome>1.57E-3      : 0.00157</outcome>

   <outcome>1.57E-2      : 0.0157</outcome>

   <outcome>0.57E-20     : 0.0000000000000000000057</outcome>

   <outcome>0.0000057E7  : 0000057</outcome>

   <outcome>123456E7     : 1234560000000</outcome>

   <outcome>123.456E7    : 1234560000</outcome>

   <outcome>123.456E12   : 123456000000000</outcome>

   <outcome>0.123456E7   : 1234560</outcome>

   <outcome>001234.56E12 : 1234560000000000</outcome>

   <outcome>1234.56E12   : 1234560000000000</outcome>

   <outcome>1.2269629E7  : 12269629</outcome>

</output>

Open in new window

0
 
LVL 60

Accepted Solution

by:
Geert Bormans earned 500 total points
ID: 24367534
There are various solutions to this problem,
abel just posted one
mwvisa1 also posted one in the first answer to this post.

But honestly, allthough it "can be done" using XSLT, you are kind of stretching,
basically you are developing your own scientific notation parser
if you really get the XML from querying a database, I strongly recommend that you change the serialisation there.
It is likely only a small effort to format the number in the database export.
I am quiet convinced that if it were my project, and I had the option, I would solve this in teh  database and not in XSLT1
0
 
LVL 39

Expert Comment

by:abel
ID: 24372802
you can put a number() around the outcome, to prevent something like 0.0000057E7  to become 0000057. The reason that the number() isn't used earlier in the chain is trivial: these digits are considered significant digits because they appear after the dot.
0
 
LVL 39

Expert Comment

by:abel
ID: 24372833
> It is likely only a small effort to format the number in the database export.

totally agree, Gertone :)
Though I just liked the exercise, checking out my XSLT 1.0 skills after doing all this easy XSLT 2.0 stuff (all the above being a one-liner in 2.0, as you pointed out).

On a side note to the OP: you are using Xalan, which probably means you are using Java. It is easy to switch to XSLT 2.0 by changing to Saxon (http://www.saxonica.com), the free open source version supports all of XSLT 2.0, apart from schema awareness. And then you can just use number(value) with scientific notationed numbers.

-- Abel --
0
 
LVL 59

Expert Comment

by:Kevin Cross
ID: 24374511
I also agree with Gertone.  My original post was in response to the question strictly being on XML / XSLT.  If you are in control up front of how the XML is generated, then changing in that code is your best bet as pointed out.
0
 
LVL 39

Expert Comment

by:abel
ID: 24535028
So you get some excellent answers from three experts, including a fully worked out solution to your original question and a link to something similar and you grade one tip. You've been around long enough on this site to know how to split points to show the appreciation to several experts at the same time.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Test ddwrt:UserLookup 1 53
nextBoolean(double p) for Random class 3 35
configure dependency in POM for new database 3 17
use lov values 2 33
Preface This is the third article about the EE Collaborative Login Project. A Better Website Login System (http://www.experts-exchange.com/A_2902.html) introduces the Login System and shows how to implement a login page. The EE Collaborative Logi…
Java functions are among the best things for programmers to work with as Java sites can be very easy to read and prepare. Java especially simplifies many processes in the coding industry as it helps integrate many forms of technology and different d…
HTML5 has deprecated a few of the older ways of showing media as well as offering up a new way to create games and animations. Audio, video, and canvas are just a few of the adjustments made between XHTML and HTML5. As we learned in our last micr…
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)

920 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now