the atom named 'Zinc' in the periodic table: Node result = XQueryUtil.xquery(doc, "/PERIODIC_TABLE/ATOM[NAME = 'Zinc']").get(0); System.out.println("result=" + result.toXML()); // equivalent via the more powerful underlying API: XQuery xquery = new XQuery("/PERIODIC_TABLE/ATOM[NAME = 'Zinc']", null); Node result = xquery.execute(doc).next(); // count the numer of elements in a document tree: int count = XQueryUtil.xquery(doc, "//*").size(); System.out.println("count=" + count); // equivalent via the XPath count() function: int count = Integer.parseInt(XQueryUtil.xquery(doc, "count(//*)").get(0).getValue()); System.out.println("count=" + count); A query to find the links of all images (or all JPG images) in a XHTML-like document:
Document doc = new Builder().build(new File("/tmp/test.xml")); Nodes results = XQueryUtil.xquery(doc, "//*:img/@src"); // Nodes results = XQueryUtil.xquery(doc, "//*:img/@src[matches(., '.jpg')]"); 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))); }
Namespaces
A query can use namespaces. Here is an example that lists the titles of Tim Bray's blog articles via the Atom feed:
declare namespace atom = "http://www.w3.org/2005/Atom"; declare namespace xsd = "http://www.w3.org/2001/XMLSchema"; doc("http://www.tbray.org/ongoing/ongoing.atom")/atom:feed/atom:entry/atom:title
Namespace declarations can be defined inline within the query prolog via
declare namespace
, and
declare default element namespace
directives, as described above. They can also be defined via the
declareNamespace()
methods and
setDefaultElementNamespace()
method of a {@link StaticQueryContext}.
Passing variables to a query
A query can declare
local variables, for example:
declare variable $i := 7; declare variable $j as xs:integer := 7; declare variable $math:pi as xs:double := 3.14159E0; declare variable $bookName := 'War and Peace';
A query can access variable values via the standard
$varName
syntax, as in
return ($x, $math:pi)
or
/books/book[@name = $bookName]/author[@name = $authorName]
.
A query can declare external global variables, for example:
declare variable $foo as xs:string external; declare variable $size as xs:integer external; declare variable $myuri as xs:anyURI external; declare variable $mydoc as document-node() external; declare variable $myelem as element() external; declare variable $mynodes as node()* external;
External global variables can be bound and 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("mydoc", new Document(new Element("xyz"))); vars.put("myelem", new Element("abc")); vars.put("mynodes", new Node[] {new Document(new Element("elem1")), new Element("elem2"))}); vars.put("mydocs", new Node[] { new Builder().build(new File("samples/data/articles.xml")), new Builder().build(new File("samples/data/p2pio.xml")) }); String query = "for $d in $mydocs return $size * count($d)"; Nodes results = new XQuery(query, null).execute(doc, null, vars).toNodes(); new ResultSequenceSerializer().write(results, System.out);
Standard functions, user defined functions and extension functions
The
Standard XQuery functions can be used directly. Also note that XPath 2.0 supports regular expressions via the standard
fn:matches
,
fn:replace
, and
fn:tokenize
functions. For example:
string-length('hello world');
A query can employ user defined functions, for example:
declare namespace ipo = "http://www.example.com/IPO"; declare function local:total-price( $i as element(item)* ) as xs:double { let $subtotals := for $s in $i return $s/quantity * $s/USPrice return sum($subtotals) }; for $p in doc("ipo.xml")/ipo:purchaseOrder where $p/shipTo/name="Helen Zoe" and $p/@orderDate = xs:date("1999-12-01") return local:total-price($p//item)
Custom extension functions written in Java can be defined and used as explained in the
Saxon Extensibility Functions documentation. For example, here is query that outputs the square root of a number via a method in java.lang.Math, as well as calls static methods and constructors of java.lang.String, java.util.Date as well as other extension functions.
declare namespace exslt-math = "http://exslt.org/math"; declare namespace math = "java:java.lang.Math"; declare namespace date = "java:java.util.Date"; declare namespace string = "java:java.lang.String"; declare namespace saxon = "http://saxon.sf.net/"; declare variable $query := string(doc("query.xml")/queries/query[1]); ( exslt-math:sin(3.14) math:sqrt(16), math:pow(2,16), string:toUpperCase("hello"), date:new(), (: print current date :) date:getTime(date:new()) (: print current date in milliseconds :) saxon:eval(saxon:expression($query)) (: run a dynamically constructed query :) )
Modules
An XQuery module is a file containing a set of variable and function declarations. For decomposition and reuse of functionality a module can import declarations from other modules. Here are two example modules generating the factorial of a number:
(: file modules/factorial.xq :) module namespace factorial = "http://example.com/factorial"; declare function factorial:fact($i as xs:integer) as xs:integer { if ($i <= 1) then 1 else $i * factorial:fact($i - 1) }; (: file main.xq :) import module namespace factorial = "http://example.com/factorial" at "modules/factorial.xq"; factorial:fact(4) [hoschek /Users/hoschek/unix/devel/nux] fire-xquery main.xq <atomic-value xsi:type="xs:integer" xmlns="http://dsd.lbl.gov/nux" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">24</atomic-value>
Customizing the doc() function
A custom document URI resolver for the XQuery/XPath
doc()
function can be defined in the constructor of this class. Other miscellaneous options can be made available to the query by calling configuration methods on a {@link DynamicQueryContext} (per execution),or on the configuration object of a {@link StaticQueryContext} (per query).
Performance
For simple XPath expressions you can get a throughput of up to 1000-20000 (100000) executions/sec over 200 (0.5) KB input documents, served from memory (commodity PC 2004, JDK 1.5, server VM). Be aware that this is an example ballpark figure at best, because use cases, documents and the complexity of queries vary wildly in practise. In any case, it is safe to assume that this XQuery/XPath implementation is one of the fastest available. For details, see {@link nux.xom.sandbox.XQueryBenchmark}.
@author whoschek.AT.lbl.DOT.gov
@author $Author: hoschek3 $
@version $Revision: 1.125 $, $Date: 2006/06/18 20:42:25 $