This chapter explains how to use the Oracle XML Developer's Kit (XDK) XQuery processor for Java.
XDK provides a standalone XQuery 1.0 processor for use by Java applications. XQuery is the World Wide Web Consortium (W3C) standard query language for Extensible Markup Language (XML). Using XQuery to process XML within a Java application can improve developer productivity and application performance. Applications written with XQuery often require less code, run faster, and use less memory than applications written fully in Java.
JSR 225: XQuery API for Java (XQJ) defines how queries can be executed from a Java application. To use XQJ, your application must run with Java version 1.6. In addition, these JAR files are required:
jlib/oxquery.jar
jlib/xqjapi.jar
jlib/orai18n-mapping.jar
lib/xmlparserv2.jar
xdk/jlib/apache-xmlbeans.jar
xdk/jlib/antlr-runtime.jar
The directory paths for these Java Archive (JAR) files are relative to the ORACLE_HOME
directory of your Oracle Database installation. The supported versions of the third-party libraries ANother Tool for Language Recognition (ANTLR) (antlr-runtime.jar
) and XMLBeans (apache-xmlbeans.jar
) are available in xdk/jlib/version.txt
.
Example 7-1 shows how to execute a simple "Hello World" query using XQuery API for Java (XQJ). Because the XQuery processor runs directly in the Java Virtual Machine (JVM), you need no database or server to run this example.
Example 7-1 Simple Query Using XQJ
import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import oracle.xml.xquery.OXQDataSource; public class HelloWorld { public static void main(String[] args) throws XQException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); String query = "<hello-world>{1 + 1}</hello-world>"; XQPreparedExpression expr = con.prepareExpression(query); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
Example 7-1 generates this output:
<hello-world>2</hello-world>
This chapter describes the features and extensions that are specific to the Oracle implementation of XQuery. General information about XQuery and XQJ is documented outside of this document.
See Also:
XQuery Packages
in Oracle Database XML Java API Reference for the related API documentation
http://jcp.org/aboutJava/communityprocess/final/jsr225/
for information about JSR 225: XQuery API for Java (XQJ)
http://www.w3.org/TR/xquery/
for information about XQuery 1.0: An XML Query Language (Second Edition)
Note:
Oracle also implements XQuery and XQJ as part of Oracle XML DB. See Using XQuery API for Java to Access Oracle XML DB for details about Oracle XML DB.XDK extends XQJ with an entity resolver framework for controlling how documents, schemas, modules, collations, and external functions are obtained during query processing. The examples in this section show how to use an entity resolver for several types of entities. See the class oracle.xml.xquery.OXQEntity
in Oracle Database XML Java API Reference for a complete list of the types of entities that the query processor can request.
This section includes these subsections:
The example in this section shows how you can use an entity resolver to determine which document is returned by the fn:doc
function.
Example 7-2 displays the contents of books.xml
.
<books> <book> <title>A Game of Thrones</title> <author><first>George</first><last>Martin</last></author> <price>10.99</price> </book> <book> <title>The Pillars of the Earth</title> <author><first>Ken</first><last>Follett</last></author> <price>7.99</price> </book> </books>
Example 7-3 displays the contents of books.xq
.
for $book in fn:doc('books.xml')/books/book where xs:decimal($book/price) gt 10.00 return $book/title
Example 7-4 shows how to execute the query books.xq
with a custom entity resolver.
Example 7-4 Executing a Query with a Custom Entity Resolver
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URI; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQEntity; import oracle.xml.xquery.OXQEntityKind; import oracle.xml.xquery.OXQEntityLocator; import oracle.xml.xquery.OXQEntityResolver; import oracle.xml.xquery.OXQEntityResolverRequestOptions; import oracle.xml.xquery.OXQView; public class ResolveDocument { private static class MyEntityResolver extends OXQEntityResolver { @Override public OXQEntity resolveEntity(OXQEntityKind kind, OXQEntityLocator locator, OXQEntityResolverRequestOptions options) throws IOException { if (kind == OXQEntityKind.DOCUMENT) { URI systemId = locator.getSystemIdAsURI(); if ("file".equals(systemId.getScheme())) { File file = new File(systemId); FileInputStream input = new FileInputStream(file); OXQEntity result = new OXQEntity(input); result.enlistCloseable(input); return result; } } return null; } } public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); // OXQView is used to access Oracle extensions on XQJ objects. OXQConnection ocon = OXQView.getConnection(con); ocon.setEntityResolver(new MyEntityResolver()); File query = new File("books.xq"); // Relative URIs are resolved against the base URI before invoking the entity resolver. // The relative URI 'books.xml' used in the query will be resolved against this URI. XQStaticContext ctx = con.getStaticContext(); ctx.setBaseURI(query.toURI().toString()); FileInputStream queryInput = new FileInputStream(query); XQPreparedExpression expr = con.prepareExpression(queryInput, ctx); queryInput.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
The example generates this output:
<title>A Game of Thrones</title>
The instance of MyEntityResolver
is passed to the XQuery processor by setting it on the connection. The XQuery processor invokes the entity resolver during query processing to get the document to be returned by the fn:doc
function.
For each external function that is declared in a query, the entity resolver is called with the entity kind oracle.xml.xquery.OXQEntityKind.EXTERNAL_FUNCTION
. The oracle.xml.xquery.OXQEntityLocator
instance that is passed in the call to the entity resolver provides the name of the XQuery function and its argument types. The entity resolver can then return any class that extends oracle.xml.xquery.OXQFunctionEvaluator
and has a public constructor. Then, the XQuery processor instantiates the returned class. When the XQuery external function call is evaluated, the evaluate()
method is invoked.
Example 7-6 shows how you can use an entity resolver to define the implementation of an XQuery external function.
Example 7-5 displays the contents of trim.xq
.
declare namespace util = "http://example.com/util"; declare function util:trim($arg as xs:string) as xs:string external; (: a string with surrounding white space :) declare variable $input := " John Doe "; <result>{util:trim($input)}</result>
Example 7-6 runs trim.xq
, and shows how to define the implementation of an external function.
Example 7-6 Defining the Implementation of an External Function
import java.io.FileInputStream; import java.io.IOException; import java.util.Collections; import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQEntity; import oracle.xml.xquery.OXQEntityKind; import oracle.xml.xquery.OXQEntityLocator; import oracle.xml.xquery.OXQEntityResolver; import oracle.xml.xquery.OXQEntityResolverRequestOptions; import oracle.xml.xquery.OXQFunctionContext; import oracle.xml.xquery.OXQFunctionEvaluator; import oracle.xml.xquery.OXQFunctionMetaData; import oracle.xml.xquery.OXQView; public class ResolveExternalFunction { public static class TrimFunction extends OXQFunctionEvaluator { @Override public XQSequence evaluate(OXQFunctionContext context, XQSequence[] params) throws XQException { XQConnection con = context.getConnection(); XQSequence arg = params[0]; String value = arg.getSequenceAsString(null); String trimmed = value.trim(); return con.createSequence(Collections.singleton(trimmed).iterator()); } } private static class MyEntityResolver extends OXQEntityResolver { @Override public OXQEntity resolveEntity(OXQEntityKind kind, OXQEntityLocator locator, OXQEntityResolverRequestOptions options) throws XQException, IOException { if (kind == OXQEntityKind.EXTERNAL_FUNCTION) { OXQFunctionMetaData metaData = (OXQFunctionMetaData)locator.getExtension(); QName name = metaData.getName(); int arity = metaData.getParameterTypes().length; if ("http://example.com/util".equals(name.getNamespaceURI()) && "trim".equals(name.getLocalPart()) && arity == 1) { return new OXQEntity(TrimFunction.class); } } return null; } } public static void main(String[] args) throws IOException, XQException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); OXQConnection ocon = OXQView.getConnection(con); ocon.setEntityResolver(new MyEntityResolver()); FileInputStream query = new FileInputStream("trim.xq"); XQPreparedExpression expr = con.prepareExpression(query); query.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
The example generates this output:
<result>John Doe</result>
The external function util:trim
is used to remove white space from the beginning and end of a string value. This function is implemented in Java and called within the query.
In Example 7-6, the entity resolver returned a class that extends OXQFunctionEvaluator
. In some cases, it might be more convenient to return a Java static method instead of a class. When a static method is returned, the query processor automatically maps the method arguments and the return value to the XQuery data model, as defined by the XQJ specification.
Example 7-7 runs trim.xq
again, but this time the external function is bound to a Java static method.
Example 7-7 Binding an External Function to a Java Static Method
import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Method; import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQEntity; import oracle.xml.xquery.OXQEntityKind; import oracle.xml.xquery.OXQEntityLocator; import oracle.xml.xquery.OXQEntityResolver; import oracle.xml.xquery.OXQEntityResolverRequestOptions; import oracle.xml.xquery.OXQFunctionMetaData; import oracle.xml.xquery.OXQView; public class ResolveExternalFunction2 { public static String trim(String value) { return value.trim(); } private static class MyEntityResolver extends OXQEntityResolver { @Override public OXQEntity resolveEntity(OXQEntityKind kind, OXQEntityLocator locator, OXQEntityResolverRequestOptions options) throws XQException, IOException { if (kind == OXQEntityKind.EXTERNAL_FUNCTION) { OXQFunctionMetaData metaData = (OXQFunctionMetaData)locator.getExtension(); QName name = metaData.getName(); int arity = metaData.getParameterTypes().length; if ("http://example.com/util".equals(name.getNamespaceURI()) && "trim".equals(name.getLocalPart()) && arity == 1) { Method staticMethod = null; try { staticMethod = ResolveExternalFunction2.class.getMethod("trim", String.class); } catch (NoSuchMethodException e) { throw new IllegalStateException(e); } return new OXQEntity(staticMethod); } } return null; } } public static void main(String[] args) throws IOException, XQException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); OXQConnection ocon = OXQView.getConnection(con); ocon.setEntityResolver(new MyEntityResolver()); FileInputStream query = new FileInputStream("trim.xq"); XQPreparedExpression expr = con.prepareExpression(query); query.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
Again, the example generates this output:
<result>John Doe</result>
An XQuery library module provides functions and variables that can be imported by other modules. For each imported module, the entity resolver is called with the entity kind oracle.xml.xquery.OXQEntityKind.MODULE
. Using the oracle.xml.xquery.OXQEntityLocator
instance, you can invoke the getSystemId()
method to get the location of the module being imported. If no location is provided in the module import, you can invoke the method getNamespace()
to get the target namespace of the module. The entity resolver can then return the corresponding library module.
The example in this section shows how you can use an entity resolver to control the resolution of XQuery library modules.
Example 7-8 displays the contents of math.xq
.
module namespace math = "http://example.com/math"; declare variable $math:pi as xs:decimal := 3.14159265; declare function math:circumference($diameter as xs:decimal) { $math:pi * $diameter };
Example 7-9 displays the contents of main.xq
.
import module namespace math = "http://example.com/math" at "math.xq"; math:circumference(6.54)
Example 7-10 shows how to execute a query that imports a library module.
Example 7-10 Executing a Query that Imports a Library Module
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URI; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQEntity; import oracle.xml.xquery.OXQEntityKind; import oracle.xml.xquery.OXQEntityLocator; import oracle.xml.xquery.OXQEntityResolver; import oracle.xml.xquery.OXQEntityResolverRequestOptions; import oracle.xml.xquery.OXQView; public class ResolveLibraryModule { private static class MyEntityResolver extends OXQEntityResolver { @Override public OXQEntity resolveEntity(OXQEntityKind kind, OXQEntityLocator locator, OXQEntityResolverRequestOptions options) throws IOException { if (kind == OXQEntityKind.MODULE) { URI systemId = locator.getSystemIdAsURI(); if (systemId != null && "file".equals(systemId.getScheme())) { File file = new File(systemId); FileInputStream input = new FileInputStream(file); OXQEntity result = new OXQEntity(input); result.enlistCloseable(input); return result; } } return null; } } public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); // OXQView is used to access Oracle extensions on XQJ objects. OXQConnection ocon = OXQView.getConnection(con); ocon.setEntityResolver(new MyEntityResolver()); File query = new File("main.xq"); // Relative URIs are resolved against the base URI before invoking the entity resolver. // The relative URI 'math.xq' used in the query will be resolved against this URI. XQStaticContext ctx = con.getStaticContext(); ctx.setBaseURI(query.toURI().toString()); FileInputStream queryInput = new FileInputStream(query); XQPreparedExpression expr = con.prepareExpression(queryInput, ctx); queryInput.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
The example generates this output:
20.546015931
The query main.xq
imports the library module math.xq
, and then invokes the function math:circumference
to compute the circumference of a circle.
An XQuery schema import imports element declarations, attributes declarations, and type definitions from an XML schema. You can use imported declarations and definitions in a query to validate and test data instances.
The example in this section shows how you can use an entity resolver to control which XML schema is used when a query imports a schema.
Example 7-11 displays the contents of size.xsd
.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/size"> <xs:simpleType name="shirt-size"> <xs:restriction base="xs:string"> <xs:enumeration value="XS"/> <xs:enumeration value="S"/> <xs:enumeration value="M"/> <xs:enumeration value="L"/> <xs:enumeration value="XL"/> </xs:restriction> </xs:simpleType> </xs:schema>
Example 7-12 displays the contents of size.xq
.
import schema namespace ns = "http://example.com/size" at "size.xsd"; for $size in ("S", "big", "XL", 42) return if ($size castable as ns:shirt-size) then ns:shirt-size($size) else concat("INVALID:", $size)
Example 7-13 shows how to execute a query that imports a schema.
Example 7-13 Executing a Query that Imports a Schema
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URI; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQEntity; import oracle.xml.xquery.OXQEntityKind; import oracle.xml.xquery.OXQEntityLocator; import oracle.xml.xquery.OXQEntityResolver; import oracle.xml.xquery.OXQEntityResolverRequestOptions; import oracle.xml.xquery.OXQView; public class ResolveSchema { private static class MyEntityResolver extends OXQEntityResolver { @Override public OXQEntity resolveEntity(OXQEntityKind kind, OXQEntityLocator locator, OXQEntityResolverRequestOptions options) throws IOException { if (kind == OXQEntityKind.SCHEMA) { URI systemId = locator.getSystemIdAsURI(); if (systemId != null && "file".equals(systemId.getScheme())) { File file = new File(systemId); FileInputStream input = new FileInputStream(file); OXQEntity result = new OXQEntity(input); result.enlistCloseable(input); return result; } } return null; } } public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); // OXQView is used to access Oracle extensions on XQJ objects. OXQConnection ocon = OXQView.getConnection(con); ocon.setEntityResolver(new MyEntityResolver()); File query = new File("size.xq"); // Relative URIs are resolved against the base URI before invoking the entity resolver. // The relative URI 'math.xq' used in the query will be resolved against this URI. XQStaticContext ctx = con.getStaticContext(); ctx.setBaseURI(query.toURI().toString()); FileInputStream queryInput = new FileInputStream(query); XQPreparedExpression expr = con.prepareExpression(queryInput, ctx); queryInput.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
The example generates this output:
S INVALID:big XL INVALID:42
The query size.xq
uses the type shirt-size
defined in schema size.xsd
to test a list of values.
XDK includes several implementations of OXQEntityResolver
that you can use for common tasks such as file system and HTTP resolution. In the previous examples that resolve entities using the file system, you could replace MyEntityResolver
with the file entity resolver that is available in XDK.
The example in this section shows how you can run the query in Example 7-3 without having to implement your own entity resolver.
Example 7-14 shows how to execute the query books.xq
with a prefabricated file resolver.
Example 7-14 Executing a Query with a Prefabricated File Resolver
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQFileResolverFactory; import oracle.xml.xquery.OXQView; public class ResolverFactory { public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); // OXQView is used to access Oracle extensions on XQJ objects. OXQConnection ocon = OXQView.getConnection(con); OXQFileResolverFactory factory = ocon.createEntityResolverFactory(OXQFileResolverFactory.class); ocon.setEntityResolver(factory.createResolver()); File query = new File("books.xq"); // Relative URIs are resolved against the base URI before invoking the entity resolver. // The relative URI 'books.xml' used in the query will be resolved against this URI. XQStaticContext ctx = con.getStaticContext(); ctx.setBaseURI(query.toURI().toString()); FileInputStream queryInput = new FileInputStream(query); XQPreparedExpression expr = con.prepareExpression(queryInput, ctx); queryInput.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
Example 7-14 generates this output:
<title>A Game of Thrones</title>
An instance of the factory oracle.xml.xquery.OXQFileResolverFactory
is created from the connection. Then, this factory is used to create an entity resolver that resolves schemas, modules, and documents against the file system. By contrast with this example, Example 7-4 uses the custom entity resolver MyEntityResolver
to resolve only documents against the file system.
XDK provides these entity resolver factories:
oracle.xml.xquery.OXQFileResolverFactory
: Creates an entity resolver that resolves 'file:' URIs for schema, module, and document locations.
oracle.xml.xquery.OXQHttpResolverFactory
: Creates an entity resolver that resolves 'http:' URIs for schema, module, and document locations.
oracle.xml.xquery.OXQCompositeResolverFactory
: Creates an entity resolver that delegates requests to other entity resolvers. For any kind of request, the resolver returns the first nonnull result it receives from one of the delegate resolvers.
oracle.xml.xquery.OXQJavaResolverFactory
: Creates an entity resolver that resolves external functions and modules to Java static methods or classes.
See Also:
the packageoracle.xml.xquery
in Oracle Database XML Java API Reference for API information about these factory interfacesThe XDK XQuery processor provides several features for improving the performance and scalability of your application.
This section includes these subsections:
The XDK XQuery processor for Java supports streaming evaluation for many types of queries. Streaming evaluation requires a small amount of main memory, even when the input XML is very large.
To facilitate streaming evaluation, these actions are recommended:
Set the binding mode on the static context to deferred mode (see the method javax.xml.xquery.XQStaticContext.setBindingMode(int)
in Oracle Database XML Java API Reference). If the binding mode is not deferred, the input XML is fully materialized when it is bound.
Provide the input XML as an instance of java.io.InputStream
, java.io.Reader
, or javax.xml.stream.XMLStreamReader
. Input XML is provided to the query processor by binding it to the expression, or by returning it from an entity resolver.
Ensure that the javax.xml.xquery.XQSequence
instance is consumed in a way that does not require materialization:
The string serialization methods getSequenceAsString(...)
and getItemAsString(...)
produce data as a string that is held in memory. Instead, use the writeSequence(...)
or the writeItem(...)
method to serialize the sequence.
The getNode()
method builds a Document Object Model (DOM) node that is held in memory. Instead, consider using the getSequenceAsStream()
or the getItemAsStream()
method to get a Streaming API for XML (StAX) stream.
The getItem()
method copies and materializes the current item in memory. Instead, use methods directly on the java.xml.xquery.XQSequence
instance to access the current item (see the interface javax.xml.xquery.XQItemAccessor
in Oracle Database XML Java API Reference).
The example described in this section invokes a query using XQJ in a way that does not prevent streaming evaluation.
Example 7-15 displays the contents of books2.xq
.
declare variable $doc external; for $book in $doc/books/book where xs:decimal($book/price) gt 10.00 return $book/title
Example 7-16 sets up the query to enable streaming evaluation.
Example 7-16 Facilitating Streaming Evaluation
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQConstants; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQDataSource; public class Streaming { public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); XQStaticContext ctx = con.getStaticContext(); ctx.setBindingMode(XQConstants.BINDING_MODE_DEFERRED); con.setStaticContext(ctx); FileInputStream input = new FileInputStream("books.xml"); FileInputStream query = new FileInputStream("books2.xq"); FileOutputStream output = new FileOutputStream("result.xml"); XQPreparedExpression expr = con.prepareExpression(query); query.close(); expr.bindDocument(new QName("doc"), input, null, null); XQSequence result = expr.executeQuery(); result.writeSequence(output, null); result.close(); input.close(); output.close(); expr.close(); con.close(); } }
Example 7-16 writes this output to the file results.xml
:
<title>A Game of Thrones</title>
The binding mode is set to the value BINDING_MODE_DEFERRED
to avoid materializing books.xml
when it is bound to the prepared expression. Likewise, the result is written to an output stream, and it is not materialized.
To simplify the example, the input file books.xml
is small. Even if this file contained millions of books, evaluating the query would require only a small maximum heap size because only one book element is held in memory at one time. In contrast with the query books.xq
, shown in Example 7-3, the query books2.xq
does not require you to define an entity resolver. Both examples (books.xq
and books2.xq
) are streamable.
Depending on the query, the processor might have to store part of the input XML in main memory during query evaluation. For example, this scenario can occur in cases such as these:
A sequence is sorted.
The value bound to a variable is used multiple times.
A path expression uses a reverse-axis step.
To reduce memory usage in such cases, you can configure the XQuery processor to use external storage for materializing XML, rather than main memory. To enable the use of external storage, set the data source property OXQConstants.USE_EXTERNAL_STORAGE
to true
, and set an oracle.xml.scalable.PageManager
instance on the dynamic context.
Note:
Using external storage can significantly reduce the amount of main memory that is consumed during query processing. However, it can also reduce performance.Example 7-17 shows how to enable the XQuery processor to use disk-based storage rather than main memory when XML is materialized.
Example 7-17 Configuring the XQuery Processor to Use External Storage
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQConstants; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.scalable.FilePageManager; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQPreparedExpression; import oracle.xml.xquery.OXQView; public class ExternalStorage { public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); ds.setProperty(OXQDataSource.USE_EXTERNAL_STORAGE, "true"); XQConnection con = ds.getConnection(); XQStaticContext ctx = con.getStaticContext(); ctx.setBindingMode(XQConstants.BINDING_MODE_DEFERRED); con.setStaticContext(ctx); FileInputStream input = new FileInputStream("books.xml"); FileInputStream query = new FileInputStream("books2.xq"); FileOutputStream output = new FileOutputStream("results.xml"); XQPreparedExpression expr = con.prepareExpression(query); query.close(); expr.bindDocument(new QName("doc"), input, null, null); // Set a page manager that will be used by the XQuery processor if XML needs to be materialized OXQPreparedExpression oexpr = OXQView.getPreparedExpression(expr); File temporaryFile = File.createTempFile("books", ".pagefile"); temporaryFile.deleteOnExit(); oexpr.setPageManager(new FilePageManager(temporaryFile.getAbsolutePath())); XQSequence result = expr.executeQuery(); result.writeSequence(output, null); result.close(); input.close(); output.close(); expr.close(); con.close(); } }
Example 7-17 writes this output to the file results.xml
:
<title>A Game of Thrones</title>
The Oracle implementation of XQJ is not threadsafe. For example, an instance of javax.xml.xquery.XQSequence
must be accessed by only one thread. However, a restricted form of thread safety is supported for managing instances of javax.xml.xquery.XQConnection
.
An instance of XQConnection
serves as a factory for creating instances of XQExpression
, XQPreparedExpression
, XQItem
, XQSequence
, XQItemType
, and XQSequenceType
. One thread can manage the creation of these objects for use by other threads. For example, XQPreparedExpression
instances created in one thread by the same connection can be used in other threads. Each XQPreparedExpression
instance, however, must be executed by only one thread. Any user-defined implementations of oracle.xml.xquery.OXQEntityResolver
that are specified must be threadsafe when expressions from the same connection are evaluated concurrently.
The XQConnection.close()
method closes all XQExpression
and XQPreparedExpression
instances that were geted from the connection. Closing those instances closes all XQResultSequence
and XQResultItem
instances obtained from the expressions. The XQConnection.close()
method can be called while expressions obtained from the connection are being processed in other threads. In this case, all registered resources held by the expressions (such as java.io.InputStream
and java.io.Reader
) are closed. This contract assumes that all registered resources support a threadsafe close method. For example, many JDK implementations of java.io.Closeable
satisfy this requirement. But, many implementations of javax.xml.stream.XMLStreamReader
do not provide a threadsafe close method. Implementations without this support can give unpredictable results if they are closed while a second thread is still reading (see the interface oracle.xml.xquery.OXQCloseable
in Oracle Database XML Java API Reference).
See Also:
the methodoracle.xml.xquery.OXQConnection.copyExpression(XQPreparedExpression)
in Oracle Database XML Java API ReferenceXDK extends XQJ with the ability to execute updating queries. XML documents can be read as an instance of javax.xml.xquery.XQItem
, and then modified using XQuery Update Facility extensions. This feature is disabled by default. You can enable it by setting the update mode on the dynamic context to oracle.xml.xquery.OXQConstants.UPDATE_MODE_ENABLED
.
Documents to be updated must be bound in deferred mode (see the method javax.xml.xquery.XQStaticContext.setBindingMode(int)
in Oracle Database XML Java API Reference). If the binding mode is not set to deferred, the input bindings are copied before query execution. Thus, only the copy is updated.
The example in this section shows how you can modify an XML document using the XQuery Update Facility.
Example 7-18 displays the contents of configuration.xml
.
Example 7-18 configuration.xml
<configuration> <property> <name>hostname</name> <value>example.com</value> </property> <property> <name>timeout</name> <value>1000</value> </property> </configuration>
Example 7-19 displays the contents of update.xq
.
declare variable $doc external; let $timeout := $doc/configuration/property[name eq "timeout"] return replace value of node $timeout/value with 2 * xs:integer($timeout/value)
Example 7-20 displays the contents of configuration.xml
after an update.
Example 7-20 Updated File configuration.xml
<configuration> <property> <name>hostname</name> <value>example.com</value> </property> <property> <name>timeout</name> <value>2000</value> </property> </configuration>
Example 7-21 shows how execute the query update.xq
.
Example 7-21 Executing the Updating Query update.xq
import java.io.FileInputStream; import java.io.IOException; import java.io.FileOutputStream; import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQConstants; import javax.xml.xquery.XQException; import javax.xml.xquery.XQItem; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQConstants; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQView; public class UpdateDocument { public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); XQStaticContext ctx = con.getStaticContext(); // Set the binding mode to deferred so the document // item is not copied when it is bound. ctx.setBindingMode(XQConstants.BINDING_MODE_DEFERRED); con.setStaticContext(ctx); FileInputStream input = new FileInputStream("configuration.xml"); XQItem doc = con.createItemFromDocument(input, null, null); input.close(); System.out.println("Before update: \n" + doc.getItemAsString(null)); FileInputStream query = new FileInputStream("update.xq"); XQPreparedExpression expr = con.prepareExpression(query); query.close(); expr.bindItem(new QName("doc"), doc); // Enable updates (disabled by default) OXQView.getDynamicContext(expr).setUpdateMode(OXQConstants.UPDATE_MODE_ENABLED); expr.executeQuery(); System.out.println("After update: \n" + doc.getItemAsString(null)); // Write the modified document back to the file FileOutputStream out = new FileOutputStream("configuration.xml"); doc.writeItem(out, null); expr.close(); con.close(); } }
In the example, these actions occur:
The XML file configuration.xml
is read as an instance of javax.xml.xquery.XQItem
.
The item is bound to the prepared expression for the query update.xq
.
The query update.xq
is executed.
The modified document is written to the file configuration.xml
.
See Also:
http://www.w3.org/TR/xquery-update-10/
for information about XQuery Update Facility 1.0
The interface oracle.xml.xquery.OXQDynamicContext
in Oracle Database XML Java API Reference
The XDK XQuery processor for Java conforms with these standards and specifications:
Note:
The XDK XQuery processor for Java is not interoperable with other XQJ implementations, including the Oracle XQJ implementation for Oracle XML DB. (See JSR-225: XQuery API for Java for the meaning of interoperable.)This section includes these subsections:
The XQuery specification defines certain features as optional. Table 7-1 lists the optional XQuery features supported by XDK.
Table 7-1 XQuery Optional Features Supported by XDK
Feature | For more information |
---|---|
Schema import |
|
Schema validation |
|
Static typing |
|
Full axis support |
|
Modules |
|
Serialization |
The XQJ and XQuery specifications leave the definition of certain aspects up to the implementation. The tables in this section briefly describe the implementation-defined items for XDK.
Table 7-2 summarizes the XQJ implementation-defined items.
Table 7-2 XQJ Implementation-Defined Items
Description | Behavior |
---|---|
Class name of |
|
Properties defined on |
None. The username and password are silently ignored. |
JDBC connection support |
JDBC connections are not supported. |
Commands |
Not supported. |
Cancelling of query execution with method |
Yes |
Serialization |
Yes |
Additional StAX or SAX events |
None |
User-defined schema types |
Yes |
Node identity, document order, and full-node context preservation when a node is bound to an external variable |
Not preserved. |
Login timeout |
Not supported. |
Transactions |
Not supported. An exception is thrown if a transaction method is called. |
|
Exception |
|
A unique name. |
|
The schema URI is returned when a type is created from XQJ. No otherwise. |
|
Exception |
Additional error codes returned by class |
The qualified names of Oracle-specific error codes are in the namespace |
|
No |
|
JDBC connections are not supported. An exception is thrown if this method is called. |
|
Same as |
Note:
XDK support for the features in Table 7-2 differs from the Oracle XML DB support for them.Table 7-3 summarizes the XQuery implementation-defined items.
Table 7-3 XQuery Implementation-Defined Items
Item | Behavior |
---|---|
The version of Unicode that is used to construct expressions |
4.0 |
The statically-known collations |
Unicode codepoint collation and collations derived from classes |
The implicit time zone. |
Uses the default time zone, as determined by method |
The circumstances in which warnings are raised, and the ways in which warnings are handled |
None |
The method by which errors are reported to the external processing environment |
Exception |
Whether the implementation is based on the rules of XML 1.0 and XML Names, or the rules of XML 1.1 and XML Names 1.1 |
1.0 |
Any components of the static context or dynamic context that are overwritten or augmented by the implementation |
See Table 7-5 |
Which of the optional axes are supported by the implementation, if the Full-Axis Feature is not supported |
Full support |
The default handling of empty sequences returned by an ordering key (sortspec) in an order by clause (empty least or empty greatest) |
|
The names and semantics of any extension expressions (pragmas) recognized by the implementation |
None |
The names and semantics of any option declarations recognized by the implementation |
None |
Protocols (if any) by which parameters can be passed to an external function, and the result of the function can be returned to the invoking query |
Defined by XQJ |
The process by which the specific modules to be imported by a module import are identified, if the Module feature is supported (includes processing of location hints, if any) |
Entity resolvers |
Any static typing extensions supported by the implementation, if the Static Typing feature is supported |
Strict mode (based on subtype) and optimistic mode (based on type intersection). Optimistic mode is the default. |
The means by which serialization is invoked, if the Serialization feature is supported |
Defined by XQJ |
The default values for the |
See the interface |
Limits on ranges of values for various data types, as enumerated in XQuery 1.0 Specification, Section 5.3 |
Decimal and integer values have arbitrary precision. |
Table 7-4 summarizes the XQuery Update Facility implementation-defined items.
Table 7-4 XQuery Update Facility Implementation-Defined Items
Item | Behavior |
---|---|
The revalidation modes that are supported by this implementation. |
|
The default revalidation mode for this implementation. |
|
The mechanism (if any) by which an external function can return an XDM instance, or a pending update list, or both to the invoking query. |
Returning a pending update list from an external function is not supported. |
The semantics of |
Any node type is accepted. Storage of the node is determined by the entity resolver. See the class |
Table 7-5 summarizes the default initial values for the static context.
Table 7-5 Default Initial Values for the Static Context
Context Component | Default Value |
---|---|
Statically known namespaces |
Prefixes that begin with |
Default element/type namespace |
No namespace |
Default function namespace |
|
In-scope schema types |
Built-in types in |
In-scope element declarations |
None |
In-scope attribute declarations |
None |
In-scope variables |
None |
Context item static type |
|
Function signatures |
Functions in the |
Statically known collations |
Unicode codepoint collation and collations derived from classes |
Default collation |
Unicode codepoint collation:
|
Construction mode |
|
Ordering mode |
|
Default order for empty sequences |
|
Boundary-space policy |
|
Copy-namespaces mode |
|
Base URI |
As defined in standard |
Statically known documents |
None |
Statically known collections |
None |
Statically known default collection type |
|