xsltlife
xsltlife

Reputation: 163

Round values if more than two digits in XSLT

I want to Round values if more than two digits in XSLT.

Input

<table>
    <tr>
        <td>3.310</td>
        <td>3.245</td>
        <td>3.882</td>
        <td>1.091</td>
    </tr>
</table>

The output should be:

<ans>
  <rt>6.5</rt
</ans>

Tried code:

<xsl:template match="table/tr">
  <xsl:variable name="change" select="td[1]-td[2]"/>
  <xsl:variable name="xxx" select="format-number($change * 100,'0.0')"/>
  <xsl:choose>
      <xsl:when test="$change mod 1 eq 0">
          <xsl:value-of select="format-number($xxx,0)"/>                      
      </xsl:when>
      <xsl:otherwise>
          <xsl:value-of select="format-number($xxx,0.0)"/>
      </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Logic:

If there are two decimals, round up to a single decimal. For example:

The error I am getting:

Arithmetic operator is not defined for arguments of types (xs:string, xs:integer)

I am using XSLT 2.0

Upvotes: 1

Views: 368

Answers (3)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243599

Logic:

If there are two decimals, round up to a single decimal. For example:

(3.310 - 3.245) * 100 = 6.5

(0.320 - 0.350) * 100 = 2.95 => rounded up = 3

(0.51 - 0.495) * 100 = 1.5

. . . .

I am using XSLT 2.0

Here is one correct solution:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

  <xsl:template match="num/text()">
    <xsl:value-of select="my:round-two-digits(xs:decimal(.)), '&#xA;'"/>
  </xsl:template>

  <xsl:function name="my:round-two-digits" as="xs:decimal">
    <xsl:param name="pNum" as="xs:decimal"/>

    <xsl:sequence select=
      "if(floor($pNum * 10) eq ($pNum * 10))
         then $pNum
         else round($pNum)"/>
  </xsl:function>
</xsl:stylesheet>

To test this, apply the above transformation on the following XML document:

<nums>
  <num>6.5</num>
  <num>2.95</num>
  <num>1.5</num>
</nums>

The wanted, correct result is produced:

6.5 
3 
1.5 

Note:

I personally prefer to use more compact XPath expressions, so the above can be re-written as:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

  <xsl:template match="num/text()">
    <xsl:value-of select="my:round-two-digits(xs:decimal(.)), '&#xA;'"/>
  </xsl:template>

  <xsl:function name="my:round-two-digits" as="xs:decimal">
    <xsl:param name="pNum" as="xs:decimal"/>

    <xsl:sequence select=
      "($pNum[floor($pNum * 10) eq ($pNum * 10)],
        round($pNum))
                    [1]"/>
  </xsl:function>
</xsl:stylesheet>

Upvotes: 0

Ansari
Ansari

Reputation: 58

Please check below code:

<xsl:template match="table/tr">
    <xsl:variable name="change" select="td[1]-td[2]"/>
    <xsl:variable name="xxx" select="number(format-number($change * 100,'0.0'))"/>
    <ans>
        <rt>
            <xsl:choose>
                <xsl:when test="$change mod 1 eq 0">
                    <xsl:value-of select="round($xxx)"/>                      
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="round($xxx)"/>
                </xsl:otherwise>
            </xsl:choose>
        </rt>
    </ans>
</xsl:template>

Upvotes: 2

michael.hor257k
michael.hor257k

Reputation: 117165

You are getting the error because you are trying to format a number that is already formatted. The result of formatting a number is a string.

I don't see why you need to format the number twice. Moreover, if you want to round a number, you should be using the round() function. Formatting a number is not the same thing. For example,

round(0.5)

returns 1, but

format-number(0.5, '0')

returns 0.

Upvotes: 1

Related Questions