XDM Model within XQJ

This section discusses the XQuery Data Model within XQJ, creating XQItems XQSequences from scratch and validating data based on XML Schema datatype constraints.

1. XQDataFactory and XQDynamicContext

XQDataFactory, a superinterface of XQConnection provides factory methods for creating XQJ specific Objects, namely:

XQItem
Describes a XQuery item which holds a value, e.g. an element or an atomic value.
XQItemType
Describes a XQuery item type, i.e. the content, datatype and constraints of an XQuery item. Every XQuery item has an XQuery item type.
XQSequence
Describes an array or sequence of XQuery items
XQSequenceType
Describes a XQuery sequence type, e.g. what types of XQuery items the sequence can hold and their occurrence.

XQDynamicContext, a superinterface of XQExpression and XQPreparedExpression provides methods to bind values from Java to XQuery variables within an Expression which are declared as external.

Note:

* All methods within XQDataFactory are used to generate XQItems and XQSequences.
* All methods within XQDynamicContext are used to bind values to XQuery expressions.

2. Creating Atomic Types which pass XML Schema constraints

There are a couple of methods to create XQItem objects from Java primitives.

[SNAPSHOT]: XQDataFactory Interface (for Java primitives)

public interface XQDataFactory { XQItem createItemFromBoolean(boolean flag, XQItemType xqItemType); XQItem createItemFromByte(byte b, XQItemType xqItemType); XQItem createItemFromDouble(double d, XQItemType xqItemType); XQItem createItemFromFloat(float f, XQItemType xqItemType); XQItem createItemFromInt(int i, XQItemType xqItemType); XQItem createItemFromLong(long l, XQItemType xqItemType); XQItem createItemFromString(String s, XQItemType xqItemType); // Other XQDataFactory methods ... }

Calling any of these methods, passing a null argument for the XQItemType will result in an XQItem with an XQItemType that directly corrolates with the Java native type, for instance

XQItem[] items = new XQItem[7];

// Create an XQItem type, with a type of xs:int and a value of 0
items[0] = conn.createItemFromInt(0, null);

XQItemType xs_integer = conn.createAtomicType(XQItemType.XQBASETYPE_INTEGER);
XQItemType xs_string = conn.createAtomicType(XQItemType.XQBASETYPE_STRING);
XQItemType xs_byte = conn.createAtomicType(XQItemType.XQBASETYPE_BYTE);
XQItemType xs_decimal = conn.createAtomicType(XQItemType.XQBASETYPE_DECIMAL);
XQItemType xs_long = conn.createAtomicType(XQItemType.XQBASETYPE_LONG);

// Create an XQItem, with a type of xs:integer and a value of 1
items[1] = conn.createItemFromInt(1, xs_integer);

// Create an XQItem, with a type of xs:string and a value of 2
items[2] = conn.createItemFromInt(2, xs_string);

// Create an XQItem, with a type of xs:byte and a value of 3
items[3] = conn.createItemFromInt(3, xs_byte);

// Create an XQItem, with a type of xs:decimal and a value of 4
items[4] = conn.createItemFromInt(4, xs_decimal);

// Create an XQItem, with a type of xs:long and a value of 5
items[5] = conn.createItemFromInt(5, xs_long);

// Try to create an XQItem, with a type of xs:byte and a value of 1000
// This causes an XQException, because the
// value 1000 is outside the range of xs:byte (-128 to 127)
items[6] = conn.createItemFromInt(1000, xs_byte);

One easy way of creating an XQItem with a desired XQItemType is by using the factory method 'createItemFromAtomicValue', this will also perform validation of the lexical string against the specified XQItemType for you.

XQItemType date = // xs:date
conn.createAtomicType(XQItemType.XQBASETYPE_DATE);

XQItemType hex = // xs:hexBinary
conn.createAtomicType(XQItemType.XQBASETYPE_HEXBINARY);

XQItem dateValue = conn.createItemFromAtomicValue("2007-01-23", date);
XQItem binaryData = conn.createItemFromAtomicValue("48656C6C6F", hex);

3. Creating XQItems from Java Objects

You can create XQItem's direct from a Java Object without declaring an XQItemType, in this instance the XQJ decides the XQItemType based on the type of the Object.

XQItem[] items = new XQItem[3];

// Create an XQItem with a type of xs:int
XQItem items[0] = conn.createItemFromObject(new Integer(5), null);

// Create an XQItem with a type of xs:float
XQItem items[1] = conn.createItemFromObject(new Float(123.4f), null);

// Create an XQItem with a type of xs:hexBinary
XQItem items[2] = conn.createItemFromObject(new byte[] { 1,2,3,4 }, null);

4. Creating and binding XQuery Sequences

The following example illustrates creating your own XQSequence objects from Lists of XQItem Objects and POJOs. The XQJ API supports the binding POJOs (e.g. Integer, String and Double) as it can convert them to XQItem Objects on the fly.

List list = new ArrayList(); // from java.util package
list.add(conn.createItemFromInt(1, null));
list.add(conn.createItemFromInt(2, null));
list.add(conn.createItemFromInt(3, null));
// Plain Old Java Objects are ok:
list.add(new Integer(4));
list.add(new Integer(5));
list.add(new Integer(6));

XQSequence sequence = conn.createSequence(list.iterator());

XQPreparedExpression xqpe =
conn.prepareExpression("declare variable $x as xs:int+ external; $x");

xqpe.bindSequence(new QName("x"), sequence);

XQResultSequence rs = xqpe.executeQuery();

while(rs.next())
  System.out.println(rs.getItemAsString(null) + "," + rs.getItemType());

This code should produce the following output in a console/shell.

1,xs:int
2,xs:int
3,xs:int
4,xs:int
5,xs:int
6,xs:int

4.1 Binding XQResultSequences to XQuery Expressions

Binding XQSequences to XQuery external variables is no different to binding XQResultSequences to XQuery external variables. Take a look at the following example:

XQExpression expr = conn.createExpression();

String xqueryString =
"for $x in doc('books.xml')//book/@isbn return xs:string($x)";

XQResultSequence rs = expr.executeQuery(xqueryString);

// Create a copy of the XQResultSequence that is scrollable and in memory.
XQSequence sequence = conn.createSequence(rs);

expr.bindSequence(new QName("isbnCodes"), sequence);

xqueryString = "declare variable $isbnCodes external; $isbnCodes";

rs = expr.executeQuery(queryString);

5. Retrieving XML Nodes

Retrieving XML DOM Nodes (like Element and Document) from XQuery Result Sequences is pretty simple, but one thing to remember is calling a method like getNode() on a result item which is not a Node will result in an XQException.

XQExpression expr = conn.createExpression();

String xqueryString = "doc('books.xml')//book";

XQResultSequence rs = expr.executeQuery(xqueryString);

while(rs.next())
{
  Element book = rs.getNode(); // org.w3c.dom.Element
}

5.1 Creating XML Nodes

Creating XML Nodes locally as XQItem values is also relatively straight forward, take a look at the following example:

Document docObj = getDocumentInstance(); // method returns a DOM Document
Element elementObj = docObj.createElement("e"); // from org.w3c.dom

// Create an XQItem with a type of element()
XQItem item1 = conn.createItemFromObject(elementObj, null);

// Create an XQItem with a type of document-node()
XQItem items2 = conn.createItemFromObject(docObj, null);

6. Retrieving Date values

In the XQJ API, there are no helper methods to retrieve Date/Time and Duration values directly from an XQItem. In these instance, you need to cast to the appropriate Object with the getObject() method.

XQExpression expr = conn.createExpression();

String xqueryString =
"for $x in doc('books.xml')//book/publish_date return xs:date($x)";

XQResultSequence rs = expr.executeQuery(xqueryString);

while(rs.next())
{
  XMLGregorianCalendar cal = (XMLGregorianCalendar)rs.getObject();
  int day   = cal.getDay();
  int month = cal.getMonth();
  int year  = cal.getYear();
}

End of section summary

Now you're quite comfortable with creating XQItems, XQSequences and binding Java variables to XQuery Expressions, it's time to look at a really powerful part of the XQuery API for Java™.

The next section covers streaming XML to the XQuery processor, enabling you to XQuery against potentially gigabytes of XML data.