check if a number, xslt

Numeric Content

1. How to check that the content of an element is numeric
2. Format number example
3. How to do numeric validations in DTD
4. Large and small numbers in xsl
5. Disable display of NaN
6. Converting non-numeric characters to numbers
7. Count the number of digits in a number
8. Number or string
9. Remove non-digit characters from a string
10. Finding odd and even
11. Format Number

1.

How to check that the content of an element is numeric

David Carlisle


<xsl:template match="a">
<xsl:value-of select="."/> 
<xsl:if 
test= "string(number(.))='NaN'"> 
is not a number</xsl:if>
</xsl:template>


            

2.

Format number example

Carl Soane



Here's a simple example:

XML file

<?xml version="1.0"?>
<Numbers>
<Num>
123456.7890
</Num>
</Numbers>


The XSL Stylesheet:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="http://www.w3.org/TR/REC-html40">

<xsl:output method="html"/>


<xsl:template match="/">
<HTML>
<BODY>
  <xsl:apply-templates select="Numbers"/>
</BODY>
</HTML>
</xsl:template>

<xsl:template match="Numbers">
<b><xsl:value-of 
 select="format-number
(Num, '#,###,###.###')"/></b>
 <br/>
</xsl:template>

</xsl:stylesheet>

 Output file
 
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <HTML>
 <BODY>
 <b>123,456.789</b>
 <br>
 </BODY>
</HTML>



            

3.

How to do numeric validations in DTD

Mike Kay


> How to do numeric validations in DTD?? 
> <personalinfo>
> <ssn>123456789</ssn>
> </personalinfo>

Can't be done in the DTD,

If you want to detect in a stylesheet that the <ssn> is non-numeric, try:

<xsl:if test="string(number(ssn))='NaN'">

or

<xsl:if 
test="translate(ssn, '0123456789', '')">

The former tolerates leading and trailing spaces and a decimal point, the latter does not.

4.

Large and small numbers in xsl

Mike Kay.

> Can XSL handle large and small numbers
Yes
> specified in 1e-157 or 1.1e+12 notation.
No

1.1e+12 is not a number in XSLT so if you do a numeric comparison it is treated as NaN; all less than and greater than comparisons with NaN yield false.

I found the description in the Java Language Spec reasonably penetrable, though as with SQL three-valued logic, some operations have results that defy one's previous expectations.

> I can't get my head round what this means in practice. 
>How would you represent 1e-157 for instance?

As 0.000(lots of zeroes)0001

P.S. Don't blame me, I didn't invent this language

5.

Disable display of NaN

West, Wilson Y

how do I disable the showing of NaN if I am doing a division by zero?

Define a format name, like so:

<xsl:decimal-format name="MyFormat" NaN=" - " zero-digit="0"/>

And use it with your format statement:

format-number(@totalAmt,'#,###','MyFormat')

Above I am displaying a dash instead of "NaN"

6.

Converting non-numeric characters to numbers

Michael Kay

> For example my XML would be as follows:
> <AAA>
>    <BBB>123</BBB>
>    <BBB>456</BBB>
>    <BBB>-</BBB>
>    <BBB>789</BBB>
> </AAA>
>
> <xsl:variable name="TotalSum" select="sum(AAA/BBB[not '-'])">
>
	

That should be rejected as a syntax error.

Try <xsl:variable name="TotalSum" select="sum(AAA/BBB[not(.='-')])">

or if you want to reject all the non-numeric ones

<xsl:variable name="TotalSum" select="sum(AAA/BBB[number(.)=number(.)])">

(That's weird, it relies on the fact that the only number that isn't equal to itself is NaN)

Here is some more explanation of why this method is preferable. It is true that this would work just as well...

<xsl:variable name="TotalSum" select="sum(AAA/BBB[boolean(number(.))])"/>

...but here the predicate is excluding BBB elements with numeric values of 0 from the node-set. While it is safe to omit these when using sum(), if the idea is to identify numeric nodes, then you'll want to use the [number(.)=number(.)] approach.

Also, you can't just use


sum(AAA/BBB[number(.)])

because that means the same thing as

sum(AAA/BBB[position()=number(.)])

and would produce undesirable results (0, in this case).

7.

Count the number of digits in a number

Dimitre Novatchev

> Is there any xsl function or trick to get the number of digits of a
> certain number ??

The solution depends on the number system used to represent the number and whether the number is a whole integer or not:

1. Decimal

string-length($x) - (contains($x, '.')) - (contains($x, '-')) 

2. Hexadecimal integer

<digits:node>
  <digit>0</digit>
  <digit>16</digit>
  <digit>256</digit>
  <digit>4096</digit>
  <digit>65536</digit>
  <digit>1048576</digit>
  <digit>16777216</digit>
  <digit>268435456</digit>
  <digit>4294967296</digit>
  <digit>68719476736</digit>
  <digit>1099511627776</digit>
  <digit>17592186044416</digit>
  <digit>281474976710656</digit>
  <digit>4503599627370496</digit>
  <digit>72057594037927936</digit>
  <digit>1152921504606846976</digit>
</digits:node>

"st" variable is defined as:

<xsl:variable name="st" select="document('')/*"/>
count($st/digits:node/digit[. > $x][1]/preceding-sibling::digit)

3. Integer in another numeric system

The same as the above, only the "digits:node/digit" nodes should contain consecutive powers of the base of the numeric system.

8.

Number or string

G Ken Holman and Jeni Tennison



>I want to see if the value of an attribute or element is a number or string.
>I tried using number(@value) != 'NaN', but it always returns false.  How can
>I find if a value is a string or number.

The following will be true if the value is a number:

   test="@value &lt;= 0 or @value > 0"

The use of < and > will coerce the argument to a number, and NaN does not pass either test. If the entire test results in false, then it must not have been a number, otherwise one of the two would have been true if it were a number.

Jeni offers

I think that you mean it always returns true? When you compare a number (e.g. number(@value)) with a string (e.g. 'NaN'), then the string gets converted to a number (so 'NaN' becomes NaN), and the comparison is made. So if @value has the value 25 then the comparison is between 25 and NaN, and 25 is not equal to NaN, so it returns true. However, NaN has a weird quality - NaN is not equal to *any* number, including NaN. So NaN != NaN also returns true.

There are two ways, therefore, that you can test whether the value attribute holds a number. First, you can compare the result of converting it to a number and then to a string with the string 'NaN':

  string(number(@value)) != 'NaN'

This will return true if @value is a number (because '25' is not equal to 'NaN') and false if @value is not a number (because the string 'NaN' is equal to the string 'NaN').

Alternatively, you can use:

  number(@value) = number(@value)

This will return true if @value is a number (because 25 is equal to 25) and false if @value is not a number (because the number NaN is not equal to the number NaN).

9.

Remove non-digit characters from a string

Michael Kay



# What is the equivalent of the following logic in XSLT
# PhoneNumber=(678)898-4274
# for (int i = 0; i < phoneNumber.length(); i++) {
#                 if (Character.isDigit(phoneNumber.charAt(i))) 
# out = out + phoneNumber.charAt(i);
#             }

<xsl:value-of select="translate(phoneNumber, translate(phoneNumber,
'0123456789', ''), '')"/>

10.

Finding odd and even

Wendell Piez

You check oddness or evenness generally the same way you do in the particular case of alternating colors. If $count is your count of nodes, then

test="$count mod 2 = 1"

returns true for odd counts (when count is divided by 2, the remainder is 1)

test="$count mod 2 = 0"

returns true for even counts (when it's divided by 2 the remainder is 0)

Because of the number->Boolean casting rules (1 = true, 0 = false), if you say

test="$count mod 2"

it will test true for odd counts, false for even counts.

The modulus operator (which returns remainders) can be used like this to determine any kind of regular cycling, not just odd-even.

11.

Format Number

Tony Graham



> In the XML file, I see that the value of 45.00, but when it displays it
> displays like this 45    .  I would like to display the full value of 45.00.
>
> This is the code that I have:
>   <xsl:value-of select="format-number(FinalTotal, '###,###,###.##',
> 'usdollar')"/>

'###,###,###.00'

or

'###,###,##0.00' (if you want zero to be '0.00')

or

'$###,###,##0.00' (if you want zero to be '$0.00')