When using an XQuery expression that uses external functions, declare the function signatures either in the XQuery prolog as external functions or using an XStaticContext instance. Supply (or bind) a Java implementation for each function using an XDynamicContext instance.
Functions declared in the XStaticContext are only visible to the main module. For an external function to be visible to a library module, it must be declared in the prolog of that library module.
The XStaticContext interface has two declareFunction methods that each have three parameters—one for the name, one for the return type of the function, and an array for the types of the arguments. The name is always provided as a QName object, but the types can be QNames or XSequenceTypes. The function name, return type, and argument types must uniquely identify the function.
Method Signature | Purpose |
---|---|
declareFunction(QName name, QName type, QName[] argTypes) | Use when the return value and arguments of the
function are all single atomic values The type QNames must refer to built-in types or global types declared in a schema that has been registered on the XFactory instance used to create the XStaticContext instance. If a QName refers to a non-atomic type, the processor will treat it as the type element(*, ns:type), where ns:type is the given QName. The XTypeConstants interface has convenient constants available that provide a QName object for each built-in type. |
declareFunction(QName name, XSequenceType type, XSequenceType[] argTypes) | Use when any of the arguments or the return value of the function is a node or a sequence of atomic values or nodes |
declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare namespace trig = "http://www.example.org/trigonometry";
declare function trig:arctan($ratio as xs:double) as xs:double external;
declare function trig:sin($angle as xs:double) as xs:double external;
<ramps>
{
for $ramp in ramps/ramp
let $angleRadians := trig:arctan($ramp/height div $ramp/base)
let $angle := trig:toDegrees($angleRadians)
let $length := $ramp/height div trig:sin($angleRadians)
return
element ramp
{
$ramp/height,
$ramp/base,
element angle { $angle },
element length { $length }
}
}
</ramps>
// Create the factory
XFactory factory = XFactory.newInstance();
// Create a new static context
XStaticContext staticContext = factory.newStaticContext();
// Declare a namespace for the functions
staticContext.declareNamespace("trig", "http://www.example.org/trigonometry");
// Create a QName for the trig:toDegrees function
QName toDegreesQName = new QName("http://www.example.org/trigonometry", "toDegrees");
// Declare the function on the static context
staticContext.declareFunction(toDegreesQName, XTypeConstants.DOUBLE_QNAME, new QName[]{XTypeConstants.DOUBLE_QNAME});
// Create an XQuery executable for the query
XQueryExecutable executable = factory.prepareXQuery(xquerySource, staticContext);
The bindings for external functions will be available to the main module and to any library modules that have an external function declaration in their prolog for that function.
Use Java reflection to obtain a java.lang.reflect.Method object for the function. If the method is an instance method, an instance object is required when binding this function.
An error is raised if you do not supply a Java method for a function that is used when executing the XQuery expression.
Method Name | Purpose |
---|---|
bindFunction(QName qname, Method method) | Use when binding a static method |
bindFunction(QName qname, Method method, Object instanceObject) | Use when binding an instance method |
// Create a new dynamic context
XDynamicContext dynamicContext = factory.newDynamicContext();
// Retrieve the java.lang.reflect.Method object for the trig:toDegrees function
Method toDegreesMethod = Math.class.getMethod("toDegrees", Double.TYPE);
// Bind the function to the dynamic context
dynamicContext.bindFunction(toDegreesQName, toDegreesMethod);
// Create QNames for the trig:arctan and trig:sin functions
QName arctanQName = new QName("http://www.example.org/trigonometry", "arctan");
QName sinQName = new QName("http://www.example.org/trigonometry", "sin");
// Retrieve the java.lang.reflect.Method objects for the trig:arctan and trig:sin functions
// then bind them to the dynamic context
Method arctanMethod = Math.class.getMethod("atan", Double.TYPE);
Method sinMethod = Math.class.getMethod("sin", Double.TYPE);
dynamicContext.bindFunction(arctanQName, arctanMethod);
dynamicContext.bindFunction(sinQName, sinMethod);
// Create an XML input document
String xml = "<ramps>" +
"<ramp><base>4</base><height>4</height></ramp>" +
"<ramp><base>4</base><height>3</height></ramp>" +
"<ramp><base>10</base><height>2</height></ramp>" +
"</ramps>";
StreamSource source = new StreamSource(new StringReader(xml));
// Execute the query
XSequenceCursor result = executable.execute(source, dynamicContext);
// Serialize the result to System.out
result.exportItem(new StreamResult(System.out));