WAS v8.5 > Develop applications > XML applications > Use the XML API to perform operations > Use external variables and functions > Use external functions > Use external functions with XQuery

Use query-declared external functions with XQuery

As an alternative to binding Java methods to functions in a query using the API, Java external functions can be declared directly within a query. The only additional configuration required is for bound Java classes to exist on the classpath during query execution.

Using the java-extension XQuery option declaration, we can bind a prefix to a Java class.

Any prefix name can be used for the java-extension element as long as it is bound to the http://www.ibm.com/xmlns/prod/xltxe-j namespace.

After binding a prefix to a Java class, methods within the bound class can be invoked by specifying the prefix and method name separated by a colon:


Example

Invoking Static Methods

When preparing an XQuery source that uses query-declared external functions, declare the prefix to Java class binding:

declare namespace calc="http://com.example/myApp/Calculator";
declare namespace sf="http://com.example/myApp/standardFormat";

declare namespace xltxe="http://www.ibm.com/xmlns/prod/xltxe-j";
declare option xltxe:java-extension "calc = org.company.Calculator";
declare option xltxe:java-extension "sf = org.standards.Formatter";

sf:format(calc:sqrt(64), "ISO-42.7")

Assuming that this query is available through the xquerySource Source object, the following code prepares the query:

// Create the factory
XFactory factory = XFactory.newInstance();

// Create an XQuery executable for the query XQueryExecutable executable = factory.prepareXQuery(xquerySource);

The following code executes the query that was prepared in the example:

// Create a result object to store the transformation result Result result = new StreamResult(System.out);

// Execute the XSLT executable
XSequenceCursor xsc = executable.execute();

// Output the result xsc.exportSequence(res);

The example query provided assumes the org.company.Calculator class contains a static method sqrt() that takes one parameter and the org.standards.Formatter class contains a static method format() that takes two parameters. At prepare time, the classes are not required on the classpath; but they are required during execution of the query.

The following are example implementations of the org.company.Calculator and org.standards.Formatter classes:

package org.company;

public class Calculator {
    public static int sqrt(int val) {
        return (int)Math.sqrt(val);
    }
package org.standards;

public class Formatter {
    public static String format(int val, String pattern) {
        return "Formatting " + val + " using pattern " + pattern;
    }}

Invoking Instance Methods

Invoking instance methods from a class is slightly different from invoking static methods because of the requirement for an instance object. To obtain an instance object from a Java class within a query, you must invoke its new constructor:

We can then store the result in an XQuery variable declaration as demonstrated by the following query:

declare namespace car="http://com.example/myApp/car";
declare namespace xltxe="http://www.ibm.com/xmlns/prod/xltxe-j";
declare option xltxe:java-extension "car = org.automobile.Car";
declare variable $var := car:new(3);

car:getDoors($var)

Assuming that this query is available through the xquerySource Source object, the following code prepares the query.

// Create the factory
XFactory factory = XFactory.newInstance();

// Create an XQuery executable for the query XQueryExecutable executable = factory.prepareXQuery(xquerySource);

The following code executes the query prepared in the example:

// Create a result object to store the transformation result Result result = new StreamResult(System.out);

// Execute the XSLT executable
XSequenceCursor xsc = executable.execute();

// Output the result xsc.exportSequence(res);

The example query assumes that org.automobile.Car class contains a constructor that takes an argument of type int. In addition, the org.automobile.Car class also contains an instance method getDoors() that takes no arguments. The syntax for invoking instance methods from query-declared external functions require the created instance object be passed in as the first argument.

The following is an example implementation of the org.automobile.Car class:

package org.automobile;

public class Car {
    private int doors;
 
    public Car (int doors) {
        this.doors = doors;
    }
 
    public int getDoors() {
        return doors;
    }}

Inheritance with instance methods is also supported. If the org.automobile.Car class has a subclass org.automobile.Sedan, we can create an instance of the org.automobile.Sedan class and use it to call methods in org.automobile.Car. This is demonstrated by the following query:

declare namespace car="http://com.example/myApp/car";
declare namespace sedan="http://com.example/myApp/sedan";
declare namespace xltxe="http://www.ibm.com/xmlns/prod/xltxe-j";
declare option xltxe:java-extension "car = org.automobile.Car";
declare option xltxe:java-extension "sedan = org.automobile.Sedan";

declare variable $var := sedan:new(5);

car:getDoors($var)

The following is an example implementation for org.automobile.Sedan:

package org.automobile;

public class Sedan extends Car {
    public Sedan (int doors) {
        super(doors);
    }}

Limitation: The mechanism used for resolving methods in a Java class requires that only one method exists, matching in name and arity. If multiple methods exist with the same name and different arity, an error is thrown.


Related


Use external functions with XQuery


+

Search Tips   |   Advanced Search