Network Deployment (Distributed operating systems), v8.0 > Develop and deploying 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.


Procedure

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

declare option xltxe:java-extension "prefix = className";

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:

prefix:methodName(Params*)


Example

Invoke 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();

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

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

The example query provided assumes that 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;
    }
}

Invoke Instance Methods

Invoke instance methods from a class is slightly different from invoking static methods because of the requirement for an instance object. In order to obtain an instance object from a Java class within a query, invoke its new constructor:

prefix:new(Params*)

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();

// 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 that 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, you 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.
Use external functions with XQuery

+

Search Tips   |   Advanced Search