How to check that the content of an element is numeric
<xsl:template match="a"> <xsl:value-of select="."/> <xsl:if test= "string(number(.))='NaN'"> is not a number</xsl:if> </xsl:template>
Format number example
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>
How to do numeric validations in DTD
> 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="translate(ssn, '0123456789', '')">
The former tolerates leading and trailing spaces and a decimal point, the latter does not.
Large and small numbers in xsl
> 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
Disable display of NaN
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:
Above I am displaying a dash instead of "NaN"
Converting non-numeric characters to numbers
> 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
because that means the same thing as
and would produce undesirable results (0, in this case).
Count the number of digits in a number
> 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:
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]/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.
Number or string
The following will be true if the value is a number:
test="@value <= 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.
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).
Remove non-digit characters from a string
<xsl:value-of select="translate(phoneNumber, translate(phoneNumber, '0123456789', ''), '')"/>
Finding odd and even
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.
'###,###,##0.00' (if you want zero to be '0.00')
'$###,###,##0.00' (if you want zero to be '$0.00')