Calling XQuery Functions from Java

Although the usual way to invoke XQuery from a Java application is to compile and execute a query as described above, it is also possible to invoke individual XQuery functions directly from Java if required. This is achieved as follows:

  1. First use the s9api interface to create an XQueryEvaluator in the usual way

  2. Use methods such as setContextItem() and setExternalVariable() to supply any information needed by the query

  3. Then instead of calling the run() method on the XQueryEvaluator to execute the query, call the method callFunction() to execute a specific function.

The third step can be repeated to call different functions or to call the same function with different parameters. Having called a function, the context item and external variable values should not be changed.

A function in a query is identified uniquely by a QName and arity. The QName is supplied explicitly in the call on callFunction(); the arity is inferred from the length of the argument array.

The arguments to the function are supplied as an array of XdmValue objects, and the result is returned as an XdmValue. The XdmValue class has subclasses such as XdmNode, XdmAtomicValue, and XdmMap allowing specific types of value to be constructed; it is also possible, of course, to use the result of one function call as an argument to another function call.

Saxon applies the standard function conversion rules to convert supplied arguments to the required type: for example, if the function expects a string, then you can supply an attribute node, and it will be atomized.

Here is an example:

Processor processor = new Processor(true); XQueryCompiler qc = processor.newXQueryCompiler(); XQueryExecutable exp1 = qc.compile( "declare function local:t1($v1 as xs:integer, $v2 as xs:double*) { " + " $v1 div sum($v2)" + "};" + "10"); final XQueryEvaluator ev = exp1.load(); XdmValue v1 = new XdmAtomicValue(14); XdmValue v2 = new XdmAtomicValue(5).append(new XdmAtomicValue(2)); XdmValue result = ev.callFunction(new QName("", "t1"), new XdmValue[]{v1, v2});

The value of result will be the atomic value 2, of type xs:double. The function conversion rules take care of the fact that a supplied sequence of integers is accepted where the required type is a sequence of xs:double values.