XQJ Part VII - Typing

XQJ Part VII - Typing

Posted on September 10, 2007 0 Comments

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,

 

  • getItemType() retrieves the item type of the sequence type
  • getItemOccurrence() retrieves the cardinality that constraints the number of items
  • toString() yields a string representation of the sequence type

 

XQItemType encapsulates more information,

 

  • getItemKind() returns whether it is an element, attribute, atomic type, etc
  • getBaseType() specifies the built-in schema type closest matching this item type. E.g. xs:anyType, xs:string, etc
  • getNodeName() yields the name of the node, which is a QName. getPIName() yields the name of a processing instruction, which is a String
  • getTypeName() specifies a QName identifying the XML Schema type of the item type. This can be either a built-in XML Schema type or user defined
  • toString() yields a string representation of the item type
  • there are some more attributes defined on XQItemType related to user defined schema type, but that would bring us too far in the context of this introductory series.

 

XQSequenceType and XQItemType objects are used in two different contexts,

 

  • the representation of the static type of an external variable defined in a query and the query result. In this context, the type is possibly abstract, like item(), node()+ or xs:anyAtomicType?
  • the concrete type of an item, here abstract types are not applicable

 

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,

 

  • for QNames representing built-in XML schema types, the xs prefix is always used.
  • for QNames representing element or attribute names the prefixes as defined in the query are used. In case of duplicates, one is chosen in an implementation dependent manner

 

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(),

 

  • if the XQItemType is an atomic type, use the string representation
  • if the XQItemType is anything else, use xs:anyType

 

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';

 

XQJ

Marc Van Cappellen

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.

Comments

Comments are disabled in preview mode.
Topics

Sitefinity Training and Certification Now Available.

Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.

Learn More
Latest Stories
in Your Inbox

Subscribe to get all the news, info and tutorials you need to build better business apps and sites

Loading animation