0

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.

Shr
  • 1
  • 1
  • 1
    See if these help: https://stackoverflow.com/questions/4367737/formatting-scientific-number-representation-in-xsl, https://stackoverflow.com/questions/23960064/convert-string-in-scientific-notation-to-number-format-in-xpath – michael.hor257k Jun 08 '20 at 17:17
  • I don't find helpful information in those links, as they have solution for display rather than arithmetic operation on variables with scientific values. – Shr Jun 29 '20 at 13:18
  • What you call "display" is actually a number. You need to start by translating both values given in scientific notation to numbers. Then you can apply numeric operation to the results. – michael.hor257k Jun 29 '20 at 13:47
  • I was able to call the template and get the result for individual value but I am not able to do that for sum() – Shr Jul 06 '20 at 19:41
  • Please edit your question and show a [mcve] including input, your current XSLT and the expected result. Also state which XS:T 1.0 processor you are using, so that we know which extensions you can use. – michael.hor257k Jul 06 '20 at 19:51
  • I have updated the question with sample code I am using, please look into it – Shr Jul 14 '20 at 15:14
  • You didn't answer my question about your processor. – michael.hor257k Jul 14 '20 at 16:27
  • Processor is Apache and version 1.0 – Shr Jul 14 '20 at 17:45

1 Answers1

0

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

michael.hor257k
  • 113,275
  • 6
  • 33
  • 51