XPath Kick Start: Navigating XML with XPath 1.0 and 2.0
XPath 2.0 also has a number of numeric functions, designed to work with these numeric types:
These functions also apply to types derived by restriction from these types. The XQuery 1.0 and XPath 2.0 Functions and Operators document lists a large number of op functions that specify how various numeric operators work on different data types. Here are some of the op functions describedyou can tell what operator each function is describing by its name :
These functions are not callable from XPath 2.0 expressions; they underpin the operators in the language. However, you can work with a set of numeric functions in the fn namespace. Each of the fn functions returns a value of the same type as the type of its argument. If the argument is the empty sequence, the empty sequence is returned, and if the argument is xdt:untypedAtomic , it is converted to xs:double . Here's an overview of the callable numeric functions:
We'll take a look at them here. The fn:floor Function
The fn:floor function returns the largest numberthat is, the closest to positive infinitythat has no fractional part, such that the returned number is not greater than the value you pass to this function. Here's the signature of this function:
fn:floor( $srcval as numeric?) as numeric? Here are some examples:
fn:floor(2.3) returns 2 fn:floor(1.5) returns 1 fn:floor(-9.5) returns -10 And here's an example putting this function to work in an XSLT 2.0 stylesheet. In this example, we'll determine whether a number is an integer, and we start by assigning that number to a variable named $number :
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="number" select="1.5" /> . . . If floor($number) = $number , the number is indeed an integer, and we can insert the message "That number is an integer." in the result document like this:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="number" select="1.5" /> . . . <xsl:template match="/"> <xsl:value-of select="if (floor($number) = $number) then 'That number is an integer.' . . . </xsl:template> On the other hand, if floor($number) != $number , we can insert the message "That number is not an integer." in the result document, as you see in ch09_11.xsl (Listing 9.11). Listing 9.11 Using the fn:floor Function ( ch09_11.xsl )
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="number" select="1.5" /> <xsl:template match="/"> <xsl:value-of select="if (floor($number) = $number) then 'That number is an integer.' else 'That number is not an integer.'"/> </xsl:template> </xsl:stylesheet> And here's the result when you use Saxon on this stylesheetas you can see, this code knows that 1.5 is not an integer:
<?xml version="1.0" encoding="UTF-8"?> That number is not an integer. The fn:ceiling Function
The fn:ceiling function returns the smallestthat is, closest to negative infinitynumber with no fractional part, such that the returned number is not less than the value you pass this function. Here's what this function's signature looks like:
fn:ceiling( $srcval as numeric?) as numeric? Here are some examples:
fn:ceiling(9.3) returns 10. fn:ceiling(1.5) returns 2. fn:ceiling(-4.5) returns -4. Here's an example using fn:ceiling . In this case, say you have one and a half truckloads of iron ore to move and want to know how many trucks you'll need. We start by setting up a variable, $numberofTruckLoads :
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="numberofTruckLoads" select="1.5" /> . . . And passing this variable to the fn:ceiling function tells us how many trucks we'll need to transport the load; you can see the XPath code in ch09_12.xsl (Listing 9.12). Listing 9.12 Using the fn:ceiling Function ( ch09_12.xsl )
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="numberofTruckLoads" select="1.5" /> <xsl:template match="/"> <xsl:value-of select="concat('You will need ', string(ceiling($numberofTruckLoads)), ' trucks.')"/> </xsl:template> </xsl:stylesheet> Here's the result:
<?xml version="1.0" encoding="UTF-8"?> You will need 2 trucks. The fn:round Function
The fn:round function is XPath 2.0's main rounding function. The fn:round function returns the number with no fractional part that is closest to the value you pass. If there are two such numbers , this function returns the one closest to positive infinity. Here's what the signature of this function looks like:
fn:round( $srcval as numeric?) as numeric? Here are some examplesnote in particular that fn:round(-9.5) returns 9, not 10:
fn:round(1.2) returns 1. fn:round(6.5) returns 7. fn:round(6.4999999) returns 6. fn:round(-9.5) returns -9.
USING fn:round AND fn:floor fn:round( $srcval ) returns the same value as fn:floor( $srcval + 0.5) .
Here's an example using this function in XSLT 2.0; say you're in charge of the movie reviews of a newspaper and have to multiply the average number of stars awarded to a movie, like 3.73, by your reviewers and come up with a whole number. You can use the fn:round function to do that, as you see in ch09_13.xsl (Listing 9.13). Listing 9.13 Using the fn:round Function ( ch09_13.xsl )
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="movieName" select="Casablanca" /> <xsl:variable name="numberOfStars" select="3.73" /> <xsl:template match="/"> <xsl:value-of select="concat('Casablanca got ', string(round($numberOfStars)), ' stars.')"/> </xsl:template> </xsl:stylesheet> And here's the result:
<?xml version="1.0" encoding="UTF-8"?> Casablanca got 4 stars. The fn:round-half-to-even Function
The fn:round-half-to-even function gives you a chance to specify the rounding precision yourself. There are two ways to use itpassing it a value, and passing a value and precision:
fn:round-half-to-even( $srcval as numeric?) as numeric? fn:round-half-to-even( $srcval as numeric?, $precision as integer) as numeric? The first version of this function returns the nearest value to the value you pass that has no fractional part. If two values are equally closethat is, the fractional part of the value you pass is exactly .5the value returned is the one whose least significant digit is even. If you pass a $precision value to this function, you can set the precision yourself. In this case, the value returned is the nearest value to $srcval that is a multiple of 1/10 to the power of $pr e cision . As with the other form of this function, if two values are equally closethat is, the fractional part of the value you pass is exactly .5the value returned is the one whose least significant digit is even. Here is an example:
fn:round-half-to-even(3.5) returns 4. On the other hand, the next example also returns 4:
fn:round-half-to-even(4.5) returns 4. Here's an example that uses a precision of 2 (here we're using the standard exponentiation syntax you use in XPath 2.0; note that 1E+3 = 1000, 1E-1 = 1/10, and so on):
fn:round-half-to-even(9.477512E+3, 2) returns 9477.51E0. You can also round to positive powers of 10 if you pass a negative value as the precision you want. For example, here's how you can round to the nearest 100:
fn:round-half-to-even(12312.63, -2) returns 12300.
AGGREGATE FUNCTIONS There are also some numeric functions that are specifically designed to work on sequences, called aggregate functions, such as max , min , count , avg , and sum , that are coming up in Chapter 12, "XPath 2.0 Node and Sequence Functions."
|