Introducing XQJ: A Java API for XQuery

Query is a declarative language for querying XML that’s similar to SQL for querying relational data. Most Java developers are familiar with JDBC, which provides a standard Java API to interact with a variety of SQL engines operating against relational data sources. XQJ has the same goal: It provides Java developers with a standard Java API for interacting with a variety of XQuery engines operating on XML data sources.

XQJ is also referred to as JSR 225 because it is designed through the Java Community Process (JCP). The JSR 225 specification defines a set of interfaces and classes that enable Java applications to submit XQuery queries against one or more XML data sources to an XQuery engine and consume the results. This article provides an introduction to XQJ by showing a basic use-case example and discussing several key interfaces in XQJ that underlie XQuery concepts. In addition, the article highlights how XQL differs from JDBC.

Fortunately for developers already familiar with JDBC, XQJ follows several familiar patterns. The typical code sequence to perform a query?obtaining a connection, preparing XQuery expressions, binding values to variables in the prepared XQuery expressions, executing the expressions, consuming the XQuery result and cleaning up resources?is exactly the same as that of JDBC. However, several key concepts in XQuery require creating specific interfaces in XQJ, such as the static context, dynamic context, the XQuery data model, and XQuery Sequence Type. Furthermore, one of the main items in the XQuery data model is the XML node. XQJ needs to integrate with existing XML node manipulation APIs such as DOM, SAX, and StAX. XQuery allows nodes to be typed using XMLSchema. XQJ defines it’s relationship with XMLSchema through the XQuery Sequence Type interface.

A Basic Example
Here’s a basic code example that uses XQJ to execute a query that illustrates a typical use. Note that error handling has been omitted for clarity.

   // obtain an XQDataSource instance   XQDataSource xqds = (XQDataSource)       Class.forName("com.jsr225.xqj").newInstance();      // obtain a connection   XQConnection con = xqds.getConnection("usr", "passwd");      // prepare an XQuery Expression   String xqry = "for $i in fn:collection('dept') " +       "where $i/deptname = %dname return count($i/employees)";   XQPreparedExpression expr = con,preparedExpression(xqry);      // bind variable with value   expr.bindString(new Qname("dname"), "engineering");      // execute the XQuery Expression   XQResultSequence rs = expr.executeQuery();      // Consume results   while (rs.next())   {     System.out.printLn(rs.getInt());   }      // clean up resources   rs.close();   con.close();   

In the preceding code, XQDataSource is an interface from which you obtain XQuery connections. You can create the initial implementation class for the XQDataSource interface via a typical data source instantiation mechanism, such as JNDI look up or an explicit class-loading method. This is similar to the design of JDBC’s DataSource and Connection interfaces.

After obtaining an XQConnection, you execute the XQuery using either the XQExpression or XQPreparedExpression interfaces. You’d use XQExpression when you want to execute an XQuery expression once, and XQPreparedExpression when you want to prepare the XQuery expression once and execute it multiple times with different bind values, as illustrated in the preceding example. These two interfaces are similar to the concepts of Statement and PreparedStatement in JDBC, respectively.

An XQuery result is an instance of the XQuery data model. The XQResultSequence shown in the example provides a cursor-centric interface that allows users to iterate through each item in the result sequence. Users can obtain values from each item, either atomic values or XML nodes. This is similar to iterating through a JDBC result set.

After consuming the XQuery results, developers need to clean up the resources by calling the close() method on the XQResultSequence and XQConnection interfaces. Proper error-handling code for releasing resources is critical to avoid resource leakage. The framework implicitly closes items created from the sequence result when the sequence result is closed. Similarly, the sequence result is implicitly closed if the connection is closed.

Editor’s Note: The authors of this article are current or former Oracle employees. We felt this article had sufficient technical merit to warrant publication on DevX.

XQuery Context Support
XQuery has dual “context” concepts: static context and dynamic context. XQJ provides XQStaticContext and XQDynamicContext interfaces to model them. The XQStaticContext provides methods to retrieve information defined in the XQuery static context, such as the base URI, the boundary-space policy, etc, letting applications retrieve information about the global static context. For example, the XQConnection interface extends the XQStaticContext interface.

In contrast, the XQDynamicContext interface enables applications to retrieve information about the dynamic context, and to change that information. In particular, it provides methods to bind XQuery variables, which are part of the dynamic context, with a variety of values. Both XQPreparedExpression and XQExpression extend the XQDynamicContext. The preceding example can call the bindString() method on an XQPreparedExpression because bindString() is actually a method exposed by the base XQDynamicContext interface.

Unlike JDBC, because the values bound to XQuery variables may not necessarily be simple scalar values, the bindXXX() methods in XQDynamicContext can have a deferred binding mode. In deferred binding mode, the bind value may not be consumed until the XQuery processor actually accesses the variable, which enables XQJ to potentially employ a pipeline-based lazy value evaluation model.

XQuery Data Model Support
Again, an XQuery result is an instance of the XQuery data model, which consists of sequence of XQuery items. Each item can be an atomic value or an XML node (document, element, attribute, comment, processing instruction, or text). The XQSequence interface models the XQuery data model. It contains zero or more XQItem interface objects. The XQItem interface represents an item in the XQuery data model. Developers obtain an XQItem by invoking either the XQSequence.getItem() method or the XQConnection.createItem() method.

While XQItem and XQSequence can represent XQuery items and sequences created independent of an XQuery result, XQResultItem and XQResultSequence (which extend XQItem and XQSequence respectively) represent XQuery items and sequences obtained as the result of an XQuery execution.

When an XQItem is an atomic value, you can convert it into the corresponding Java data type using one of the getXXX() methods, which include getInt(), getString(), and so forth. When XQItem is an XML node, you can access it via existing XML node manipulation interfaces, such as DOM, SAX, or StAX. Both XQItem and XQSequence extend the XQItemAccessor interface, which defines a variety of item accessor methods. For example, the getNode() method returns a DOM node. The writeItemToSAX() method generates a SAX event by serializing a sequence into SAX events. The getItemAsStream() method serializes the sequence into an XMLStreamReader event stream. Furthermore, XQJ has defined a set of standard mapping between Java data types and XQuery data types to facilitate binding standard Java types to XQuery variables.

XQuery Type System Support
XQuery has types?and interfaces to support them. The XQSequenceType and XQItemType interfaces allow users to work with XQuery type systems. XQSequenceType interface represents a sequence type defined in XQuery, whereas XQItemType represents an item type defined in XQuery. It extends XQSequenceType but restricts its occurrence indicator to exactly one. The XQItem interface contains methods to obtain information about an XQuery item type, such as its item type, its base type, the node name (if any), the note type name (if any), and any XML schema URI associated with the type.

XQJ allows for considerable implementation freedom to deal with XML schema types. Because XQJ is designed to work with a variety of XQuery engines, you can’t assume any particular relationship between the XQJ implementation and the underlying XQuery engine with which it communicates. Therefore you can’t assume that a particular implementation combination of XQJ and the XQuery engine share the same XML Schema repository. To ameliorate this problem, the XQJ API uses an XQMetaData method called isUserDefinedXMLSchemaTypeSupported() to decide whether the XQJ implementation can answer questions that depend on the knowledge XML schemas. For a tightly coupled system where the XQuery engine and the XQJ implementation share the same XML schema repository, isUserDefinedXMLSchemaTypeSupported is set to true; for loosely coupled systems, this value is set to false.

Working with XQMetaData
The XQMetaData interface provides users with additional information about the underlying XQJ and XQuery implementation. It has methods to query whether specific XQuery features, such as StaticTypingFeature and SchemaImportFeature, are supported. It also provides general information about the data source. The XQMetaData interface functions as a portable layer for XQJ users. This is similar to the DatabaseMetaData interface in JDBC.

Future Directions
As SQL/XML becomes the standard, developers will be able to embed and execute XQuery within SQL?so JDBC will eventually be enhanced with XQuery support. However, we believe that XQJ is still necessary, because not all XQuery processors that require XQJ will support SQL and SQL/XML. Furthermore, XQJ has defined a number of important interfaces (as described earlier) that model the key concepts in XQuery, as well as classical XML Java interfaces such as DOM, SAX, and StaX. These XQJ interfaces will be leveraged when JDBC eventually supports SQL/XML 2006, which allows XQuery invocation in SQL. A potential integration point is to have the JDBC XMLType support a method for creating XQuery data models using interfaces defined by XQJ.

This article provided a brief introduction to XQJ, the XQuery Java API and discussed some of the interfaces that model key concepts in XQuery. Just as JDBC was successful with relational data, we believe XQJ will become a widely used Java API for interacting with XQuery engines operating on XML data sources.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

More From DevX