Shr
Shr

Reputation: 1

Adding two scientific numbers in XSLT

I have to add two variables with scientific number values in XSLT. I am getting NAN, when I used something like this xsl:with-param name="inputVal" select="($price1+$price2)". where Price1 = 1.0E7 and Price2 = 1.0E8. I have issue with Sum() as well.

Here is an example of what I am looking for My XML :

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
  <cd>
    <title>CD1</title>
    <price>1.0E7</price>
  </cd>
  <cd>
    <title>CD2</title>
    <price>1.1E7</price>
  </cd>
  <cd>
    <title>CD3</title>
    <price>1.2E7</price>
  </cd>
</catalog>

My XSLT :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Price</th>
      </tr>
      <xsl:for-each select="catalog/cd">
      <tr>
      <td>
       
      <xsl:value-of select="title"/></td>
        <td><xsl:call-template name="convertSciToNumString">
                                                    <xsl:with-param name="inputVal" select="price"/>
                                                </xsl:call-template></td>
      </tr>
     </xsl:for-each>
      <tr>
        <th>Total</th>
        <th><xsl:value-of select="sum(catalog/cd/price)"/></th>
      </tr>
    </table>
  </body>
  </html>
</xsl:template>
    <xsl:template name="convertSciToNumString" >
        <xsl:param name="inputVal" select="0"/>
        <xsl:variable name="vMantissa" select="substring-before($inputVal, 'E')"/>
        <xsl:variable name="vExponent" select="substring-after($inputVal, '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="$inputVal = ''">       
            </xsl:when>
            <xsl:when test="number($inputVal)=$inputVal">
                <xsl:value-of disable-output-escaping="no" select="format-number($inputVal, '##,###,###,###,###,###,##0.00')"/>
            </xsl:when>
            <xsl:when test="starts-with($vExponent,'-')">
                <xsl:value-of disable-output-escaping="no" select="format-number($vMantissa div $vFactor, '##,###,###,###,###,###,##0.00')"/>
            </xsl:when>
            <xsl:otherwise>         
                <xsl:value-of disable-output-escaping="no" select="format-number($vMantissa * $vFactor, '##,###,###,###,###,###,##0.00')"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

I am using version 1.0 and by following the suggestion to create a template to convert data from scientific format to number format, I am able to individually, but as I have to use sum() or variable1 + variable2 in some cases, I am not sure how to handle this.

Upvotes: 0

Views: 252

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 117140

The main problem with your attempt is that your template returns a formatted string, not a number.

The other thing is that you need to do this in two passes: first, convert the scientific-notation values to numbers; then sum the resulting numbers and - if necessary - format them for output.

If you are using the Apache Xalan processor, you can make this much easier by utilizing the EXSLT math:power() extension function:

XSLT 1.0 (+ EXSLT)

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:math="http://exslt.org/math"
extension-element-prefixes="exsl math">

<xsl:template match="/catalog">
    <!-- FIRST PASS -->
    <xsl:variable name="cds-rtf">
        <xsl:for-each select="cd">
            <xsl:copy>
                <xsl:copy-of select="title"/>
                <price>
                    <xsl:variable name="significand" select="substring-before(price,'E')"/>
                    <xsl:variable name="magnitude" select="substring-after(price,'E')"/>
                    <xsl:value-of select="$significand * math:power(10, $magnitude)"/>
                </price>
            </xsl:copy>
        </xsl:for-each>
    </xsl:variable>
    <xsl:variable name="cds" select="exsl:node-set($cds-rtf)/cd"/>
    <!-- OUTPUT -->
    <html>
        <body>
            <h2>My CD Collection</h2>
            <table border="1">
                <tr>
                    <th>Title</th>
                    <th>Price</th>
                </tr>
                <xsl:for-each select="$cds">
                    <tr>
                        <td>
                            <xsl:value-of select="title"/>
                        </td>
                        <td>
                            <xsl:value-of select="format-number(price, '#,###')"/>
                        </td>
                    </tr>
                </xsl:for-each>
                <tr>
                    <th>Total</th>
                    <th>
                        <xsl:value-of select="format-number(sum($cds/price), '#,###')"/>
                    </th>
                </tr>
            </table>
        </body>
    </html>
</xsl:template>

</xsl:stylesheet>

Applied to your input example, this will produce:

Result (rendered)

enter image description here

Upvotes: 0

Related Questions