Nux 1.0a5

nux.xom.xquery
Class XQuery

java.lang.Object
  extended bynux.xom.xquery.XQuery

public class XQuery
extends Object

Compiled representation of a W3C XQuery (thread-safe). Since XQuery is a superset of XPath 2.0 this class can also be used with plain XPath expressions as queries. Also note that XPath 2.0 supports regular expressions via the fn:matches, fn:replace, and fn:tokenize functions.

Instances are considered immutable and thread-safe; The same compiled query may be executed (evaluated) many times in series or in parallel, just like XSLTransform objects.

Requires saxon-8.1.1 or higher; Does not care whether it is an open-source or commercial Saxon version. To get started, simply add saxon8.jar to your classpath. Thanks to Michael Kay for that amazing piece of software! In case of problems, first check the saxon documentation and search the saxon mailing list as well as the XOM mailing list.

Example usage:

     // find the links of all images in a XHTML-like document
     XQuery xquery = new XQuery("//*:img/@src", null);
 
     // find the links of all JPG images in a XHTML-like document via regular expression
     // XQuery xquery = new XQuery("//*:img/@src[matches(., '.jpg')]", null);
 
     Document doc = BuilderPool.GLOBAL_POOL.getBuilder(false).build(new File("/tmp/test.xml"));
     Nodes results = xquery.execute(doc).toNodes();
     for (int i=0; i < results.size(); i++) {
         System.out.println("node "+i+": "+results.get(i).toXML());
         //System.out.println("node "+i+": "+ XOMUtil.toPrettyXML(results.get(i)));
     }
 
Here is another typical relational join XQuery that, for all bicycles, lists the item number, description, and highest bid (if any), ordered by item number:
     for $i in doc("items.xml")//item_tuple
     let $b := doc("bids.xml")//bid_tuple[itemno = $i/itemno]
     where contains($i/description, "Bicycle")
     order by $i/itemno
     return
        <item_tuple>
           { $i/itemno }
           { $i/description }
           <high_bid>{ max($b/bid) }</high_bid>
        </item_tuple>
 
Here is a query (using namespaces) that selects all records that have a remark in German:
     declare namespace music = "http://www.example.org/music/records";
     declare namespace xsd = "http://www.w3.org/2001/XMLSchema";
     declare base-uri "http://example.org";
 
     <Q5 xmlns:music="http://www.example.org/music/records">
     {
        doc("tests/2003-11/usecases/ns/action.xml")//music:record[music:remark/@xml:lang = "de"]
     }
     </Q5>
 
A query can declare external global variables, for example:
     declare variable $foo     as xs:string external (:: pragma saxon:default "hello" ::); 
     declare variable $size    as xs:integer external (:: pragma saxon:default 100 ::); 
     declare variable $myuri   as xs:anyURI external;
     declare variable $mynode  as node() external;
     declare variable $myelem  as element() external;
     declare variable $mynodes as node()* external;
 
Such external global variable values can be passed to the query as follows:
     Map vars = new HashMap();
     vars.put("foo", "hello world");
     vars.put("size", new Integer(99));
     vars.put("myuri", "http://www.w3.org/2001/XMLSchema");
     vars.put("mynode", new Document(new Element("xyz")));
     vars.put("myelem", new Element("abc"));
     vars.put("mynodes", new ParentNode[] {new Document(new Element("elem1")), new Element("elem2"))});
     xquery.execute(doc, null, vars);
 
The Standard XQuery functions can be used directly. Custom extension functions written in Java can be defined and used as explained in the Saxon Extensibility Functions documentation.

Custom URI resolvers can be defined as explained in the Saxon URI Resolver documentation. These are made available to the query by calling setURIResolver() on a DynamicQueryContext (per execution), or on the configuration object of a StaticQueryContext (per query).

Performance note: For simple XPath expressions you can get a throughput of several thousand executions/sec for 10KB XHTML-like input documents, served from memory (commodity PC 2004, JDK 1.4.2). Be aware that this is an example ballpark figure at best, because use cases, documents and the complexity of queries vary wildly in practise.

Author:
whoschek.AT.lbl.DOT.gov, $Author: hoschek3 $

Constructor Summary
XQuery(String query, URI baseURI)
          Constructs a new compiled XQuery from the given query.
XQuery(String query, URI baseURI, StaticQueryContext staticContext, DocumentURIResolver resolver)
          Constructs a new compiled XQuery from the given query, base URI, static context and resolver.
 
Method Summary
 ResultSequence execute(ParentNode contextNode)
          Executes (evaluates) the query against the given node (subtree).
 ResultSequence execute(ParentNode contextNode, DynamicQueryContext dynamicContext, Map variables)
          Executes (evaluates) the query against the given node (subtree), using the given dynamic context and external variables.
protected  ResultSequence newResultSequence(XQueryExpression expression, DynamicQueryContext dynamicContext)
          Callback that returns a result sequence for the current query execution.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

XQuery

public XQuery(String query,
              URI baseURI)
       throws XQueryException
Constructs a new compiled XQuery from the given query.

Parameters:
query - the query to compile
baseURI - the base URI of the query. Used for resolving any relative URI's found in the query, and used by the XQuery doc function. (May be null in which case it defaults to the current working directory).
Throws:
XQueryException - if the syntax of the query is wrong, or if it references namespaces, variables, or functions that have not been declared, or contains other static errors.

XQuery

public XQuery(String query,
              URI baseURI,
              StaticQueryContext staticContext,
              DocumentURIResolver resolver)
       throws XQueryException
Constructs a new compiled XQuery from the given query, base URI, static context and resolver.

Parameters:
query - the query to compile
baseURI - the base URI of the query. Used for resolving any relative URI's found in the query, and used by the XQuery doc() function, and hence the resolver. May be null in which case it defaults to the current working directory.
staticContext - the context and configuration to use; per query (may be null).
resolver - an object that is called by the XQuery processor to turn a URI passed to the XQuery doc() function into a XOM Document. May be null in which case Saxon's default resolution is used.
Throws:
XQueryException - if the syntax of the query is wrong, or if it references namespaces, variables, or functions that have not been declared, or contains other static errors.
Method Detail

execute

public ResultSequence execute(ParentNode contextNode)
                       throws XQueryException
Executes (evaluates) the query against the given node (subtree).

Parameters:
contextNode - the context node to execute the query against. The context node is available to the query as the value of the query expression ".". If this parameter is null, the context node will be undefined.
Returns:
an iterator producing execution output results on demand
Throws:
XQueryException - if an error occurs during execution

execute

public ResultSequence execute(ParentNode contextNode,
                              DynamicQueryContext dynamicContext,
                              Map variables)
                       throws XQueryException
Executes (evaluates) the query against the given node (subtree), using the given dynamic context and external variables.

Argument variables specifies external global variables in the form of zero or more variableName --> variableValue map associations. Each map entry's key and value are interpreted as follows:

Parameters:
contextNode - the context node to execute the query against. The context node is available to the query as the value of the query expression ".". If this parameter is null, the context node will be undefined.
dynamicContext - optional dynamic context of this execution (may be null). If not null, the Configuration object of the dynamic context must be be the same as the Configuration object that was used when creating the StaticQueryContext.
variables - optional external global variables on the dynamic context; per execution (may be null).
Returns:
an iterator producing execution output results on demand
Throws:
XQueryException - if an error occurs during execution

newResultSequence

protected ResultSequence newResultSequence(XQueryExpression expression,
                                           DynamicQueryContext dynamicContext)
                                    throws XQueryException
Callback that returns a result sequence for the current query execution.

An XQuery result sequence may, apart from "normal" nodes, also contain top-level values of atomic types such as Long, Float, Boolean, etc, all of which are not XML nodes.

This method's result sequence implementation converts each top-level atomic value to an Element named "atomic" with a child Text node holding the value's string representation. "Normal" nodes and anything not at top-level is returned "as is", without conversion.

Overrride this default implementation if you need custom conversions in result sequence implementations. Note however, that conversions of atomic values should rarely be used. It is often more desirable to avoid such atomic conversions altogether. This can almost always easily be achieved by formulating the xquery string such that it wraps atomic values via standard XQuery constructors (rather than via Java methods) into an element or attribute or document. That way, the query always produces a "normal" XML node sequence as output, and never produces a sequence of atomic values as output, and thus custom conversion by this class are never needed and invoked.

For example, by default the following query

     for $i in (1, 2, 3) return $i
 
yields this (perhaps somewhat unexpected) output:
     <atomic type="java.lang.Long">1</atomic>
     <atomic type="java.lang.Long">2</atomic>
     <atomic type="java.lang.Long">3</atomic>
 

Hence, most likely you will want to rewrite the query along the following lines:

     for $i in (1, 2, 3) return <item> {$i} </item>
 
now yielding as output:
     <item>1</item> 
     <item>2</item>
     <item>3</item>
 
Observe that the rewritten query converts top-level atomic values precisely as desired by the user, without needing any Java-level conversion.

Parameters:
expression - the compiled query expression
dynamicContext - the dynamic context of this execution
Returns:
a result sequence implementation
Throws:
XQueryException - if an error occurs during execution

Nux 1.0a5