XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition (309 page)

BOOK: XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition
3.9Mb size Format: txt, pdf, ePub

It is not possible to write functions in XPath itself. For this, you need XSLT 2.0, XQuery 1.0, or potentially some other language that supports the capability. XPath only provides the ability to call such functions, not to define them.

A number of useful third-party function libraries have become available for XSLT 1.0 processors (see for example
http://www.exslt.org
and
http://fxsl.sf.net/
), and the same is starting to happen for XSLT 2.0 and XQuery 1.0. An example is Priscilla Walmsley's library at
http://www.functx.com
, which is available in both XSLT and XQuery versions.

Functions, at least in theory, are uniquely identified by their expanded QName (that is, namespace URI and local name) and their
arity
—that is, the number of arguments. The idea is that the static context contains a list of functions that are available to be called, and it cannot contain two functions with the same name and the same arity. There is no overloading of functions, so you can't have two functions with the same name and the same number of arguments, distinguished only by the types of the arguments.

Products that allow you to call Java methods are quite likely to provide some kind of overloading in practice, if one can extrapolate from what XSLT 1.0 processors do. The specification leaves enough latitude to allow this: all aspects of external calls are essentially implementation-defined. Conceptually, a product can satisfy the letter of the law by claiming that for each possible Java method name and number of arguments, there is a single function in the static context, and it is this notional function that decides which of several Java methods to call, based on the types of the arguments supplied.

Converting the Arguments and the Result

At compile time, every function in the static context has a known signature defining the types of the arguments and the type of the result. For example, consider a function that calculates the total sales of a product (the actual logic isn't important).

Here is the XSLT 2.0 implementation:


  

  


And here is the equivalent in XQuery 1.0:

declare function mf:product-sales ($product as schema-element(mf:product))

        as xs:decimal {

    sum($product//sale[@product-code eq $product/code])

};

In both cases, we have defined the function name as
mf:product-sales
(we'll assume that the namespaces have been declared properly), and we have defined it to take a single argument, which is an element conforming to the schema-defined element declaration
mf:product
. This means the element will be either a valid
mf:product
or a member of its substitution group; the detailed meaning of the syntax
schema-element(mf:product)
is given in Chapter 11. The return type of the function is declared to be an
xs:decimal
.

There's no formal link between the namespaces used for functions and the namespaces used for elements, attributes, and schema-defined types. But with functions which, like this one, are very specific to a particular element type, I think it's a useful convention to put the function in the same namespace as the element type.

An XPath expression that invokes this function might look like this:

//mf:product[mf:product-sales(.) gt 100000]

This expression returns a sequence containing all the

elements that have total sales in excess of 100,000.

In this example, the required type of the argument was a single node, and the result type of the function was a single atomic value. It is also possible, of course, for functions to take sequences as their arguments, or to return sequences as their result. In general, the required type of an argument has two parts: the required cardinality and the required item type. The required cardinality is shown by an occurrence indicator after the type and may be one of:

Occurrence Indicator
Meaning
(none)
Exactly one item
*
Any number of items
+
One or more items
?
Either one item, or none

The required item type defines a type that each item in the supplied value must conform to. This may be a very generic type, such as
node()
, or a very specific type, such as
element(mf:product)
or
xs:unsignedByte
. If no required type is specified for an argument, the implicit default is
item()*
. This allows any sequence of items, in other words any value at all.

Other books

A Change of Heart by Philip Gulley
Are We Live? by Marion Appleby
Love Inspired Suspense September 2015 #1 by Margaret Daley, Alison Stone, Lisa Phillips
Master of Shadows by Mark Lamster
Bloodforged by Nathan Long
Dream Keeper by Gail McFarland