In today's post of the XQJ series, we'll have a closer look at how XQJ interacts with the XQuery type system. XQuery is a strongly typed language, the type system is based on XML Schema. As it is an inherent part of XQuery, you'll need some notions of it to be really effective with XQuery. However, it is out of scope for this XQJ tutorial to go into all the details, my recent XQuery book recommendation is probably a good start if you're interested to know more about the XQuery type system.
XQuery defines a sequence type, as a type that can be expressed using the SequenceType syntax. It consists of an item type that constrains the type of each item in the sequence, and a cardinality that constrains the number of items in the sequence. Having sequences and items in the XQuery type system, XQJ defines two corresponding interfaces XQSequenceType and XQItemType.
XQSequenceType is a rather simple interface with only 3 methods,
XQItemType encapsulates more information,
XQSequenceType and XQItemType objects are used in two different contexts,
Lat's have a closer look at XQItemType, which specifies the item kind and base type,
[cc lang="java"]... XQSequenceType xqtype = ... XQItemType xqitype = xqtype.getItemType(); int itemKind = xqitype.getItemKind(); int schemaType = xqitype.getBaseType(); ...[/cc]
XQJ defines constants for each of the item kinds representable in XQuery SequenceType syntax,
.nobrtable br { display: none }
Sequence Type | XQJ definition | ||
---|---|---|---|
QName | XQITEMKIND_ATOMIC | ||
element(...) | XQITEMKIND_ELEMENT | ||
attribute(...) | XQITEMKIND_ATTRIBUTE | ||
comment() | XQITEMKIND_COMMENT | ||
document-node() | XQITEMKIND_DOCUMENT | ||
document-node(element(...)) | XQITEMKIND_DOCUMENT_ELEMENT | ||
processing-instruction(...) | XQITEMKIND_PI | ||
text() | XQITEMKIND_TEXT | ||
item() | XQITEMKIND_ITEM | ||
node() | XQITEMKIND_NODE |
getBaseType() is used to determine more precisely the type in case of for example XQITEMKIND_ATOMIC. When we have an atomic type, is it an xs:string or xs:integer? XQJ defines constants for all the built-in XML Schema and XQuery types. It's a long list, too long for this post.
XML Schema type | XQJ definition | ||
---|---|---|---|
xs:string | XQBASETYPE_STRING | ||
xs:integer | XQBASETYPE_INTEGER | ||
xs:untypedAtomic | XQBASETYPE_UNTYPEDATOMIC | ||
... | ... |
Iterating over query results, XQJ allows you to request precise type information about each item. Suppose you want to use a different getXXX() method, depending on the item type,
[cc lang="java"]XQSequence xqs = ... while (xqs.next()) { XQItemType xqtype = xqs.getItemType(); if (xqtype.getItemKind() == XQItemType.XQITEMKIND_ATOMIC) { // We have an atomic type switch (xqtype.getBaseType()) { case XQItemType.XQBASETYPE_STRING:
case XQItemType.XQBASETYPE_UNTYPEDATOMIC: { String s = (String)xqs.getObject(); ... break; } case XQItemType.XQBASETYPE_INTEGER: { long l = xqs.getLong(); ... break; } ... } } else { // We have a node, retrieve it as a DOM node org.w3c.dom.Node node = xqs.getNode(); ... } }[/cc]
OK, this can make your code rather complex and long. Sometimes it is needed, but most of the time a number of shortcuts can be taken. As explained in XQJ Part IV - Processing query results, you can use some of the more the general purpose methods. Suppose you need a DOM node in case the query returns a node, and the string value for all atomic values. The next simple example shows how to do this,
[cc lang="java"]XQSequence xqs = ... while (xqs.next()) { XQItemType xqtype = xqs.getItemType(); if (xqtype.getItemKind() == XQItemType.XQITEMKIND_ATOMIC) { // We have an atomic type String s = xqs.getAtomicValue(); ... } else { // We have a node, retrieve it as a DOM node org.w3c.dom.Node node = xqs.getNode(); ... } }[/cc]
That's it for the dynamic type of items. The next example shows how to retrieve the static type of a query (for the JDBC, ODBC and SQL users, this is somehow similar to "describe information")
[cc lang="java"]... XQPreparedExpression xqe = xqc.prepareExpression("1+2"); XQSequenceType xqtype = xqe.getStaticResultType(); System.out.println(xqtype.toString()); ...[/cc]With DataDirect XQuery this examples outputs xs:integer to stdout. Similar, you can inquire the prepared expression to retrieve information about the external variables. As shown in the next examples, first we determine the external variables declared in the query, next we retrieve the static type of each of the external variables,[cc lang="java"]... XQPreparedExpression xqe = xqc.prepareExpression( "declare variable $i as xs:integer external; $i+1"); QName variables[] = xqe.getAllExternalVariables(); for (int i=0; i<variables.length; i++) { XQSequenceType xqtype = xqe.getStaticVariableType(variables[i]); System.out.println(variables[i] + ": " + xqtype.toString()); } ...[/cc]
Why would one care about all this? Let's have a quick look at a use case. The idea of exposing XQueries as web services is not new, remember for example the XQuery at Your Web Service research paper. A fully functional example of such 'XQuery Web Service' is available on xquery.com, and can be downloaded here. It is basically a servlet that reads xqueries from a specific directory, and makes each of the queries available as functions accessible through SOAP. The servlet needs to determine the external variables in each of the queries in order to generate the WSDL, which contains an XML Schema definition describing the parameters for each operation. Something as follows, assuming an XQuery with two external variables, $employeeName and $hiringDate, declared as xs:string and xs:date.
[cc lang="java"]...
...[/cc]
All the information required to generate such XML schema definition, is available in the sequence type of each declared variable. And through XQJ this information becomes immediately accessible. We can write a piece of code translating the relevant item kinds and base types to an XML Schema definition as shown above, only a matter of a number of Java switch statements. But is there an easier way?
XQJ defines toString() on XQItemType as implementation dependent. Well, more precisely, it is a requirement to return a human-readable string. In any case, with DataDirect XQuery the string representation is based on the XQuery sequence type syntax, where the QName prefixes are as follows,
Going back to our XQuery Web Service use case, the strategy to map the external variable declaration to the WSDL becomes rather simple using toString(),
I hope this post gave you a feel for the XQSequenceType and XQItemType interfaces, and how you can take advantage of them in your application. Applications have also the ability to create XQItemType objects. We'll show how this can be done and detail out use cases in the next post of the XQJ series.
digg_skin = 'compact';
View all posts from Marc Van Cappellen on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.
Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.
Learn MoreSubscribe to get all the news, info and tutorials you need to build better business apps and sites