Binding Java variables to XQuery

1. Protect your XQuery code from the jokers

In Java/SQL based applications, one of the worst things a developer could can do is pass user content directly into an SQL expression string. Because if the end user knows what they are doing and has a malicious streak in them, they could easily start writing additional SQL code for you. Bad times.

The same story is true in your Java/XQuery applications, which is why it's best to bind these values as XQuery external variables. The XQJ will take care of that 'interesting' content.

2. XML Schema datatype validation

This mechanism also lets the XQJ API do some additional datatype checking for you. For instance, in the XML Schema datatype model there is a type xs:unsignedInt. The XQJ API can check that an int value you're attempting to bind for instance, actually passes the requirements for the xs:unsignedInt datatype before the expression is even executed.

The following code illustrates binding a Java variable to an XQExpression object.

LookupByISBN.java

import javax.xml.xquery.*; import javax.xml.namespace.QName; import net.cfoster.sedna.xqj.SednaXQDataSource; public class LookupByISBN { private static final String DEFAULT_ISBN = "059652112X"; public static void main(String[] args) throws XQException { XQDataSource xqs = new SednaXQDataSource(); xqs.setProperty("serverName", "localhost"); xqs.setProperty("databaseName", "test"); XQConnection conn = xqs.getConnection("SYSTEM", "MANAGER"); XQExpression xqe = conn.createExpression(); String ISBN_ID = args.length > 0 ? args[0]:DEFAULT_ISBN; // Bind variable to expression xqe.bindString(new QName("userisbn"), ISBN_ID, null); String xqueryString = "declare variable $userisbn external; " + "for $x in doc('books.xml')//book " + "where $x/@isbn = $userisbn " + "return $x/title/text()"; XQResultSequence rs = xqe.executeQuery(xqueryString); while(rs.next()) System.out.println(rs.getItemAsString(null)); conn.close(); } }

Executing the program without passing any parameters should produce the result.

Java Web Services: Up and Running

Passing a parameter to the application, e.g. '0470192747' will yield a different result.

3. XQPreparedExpression and XML Schema datatype validation

Let's look at two further concepts, XQPreparedExpression which essentially allows you to first compile an XQuery expression which can be executed repeatedly and validating bound variables against an XML Schema datatype.

LookupByDateRange.java

import javax.xml.xquery.*; import javax.xml.namespace.QName; import net.cfoster.sedna.xqj.SednaXQDataSource; public class LookupByDateRange { public static void main(String[] args) throws XQException { XQDataSource xqs = new SednaXQDataSource(); xqs.setProperty("serverName", "localhost"); xqs.setProperty("databaseName", "test"); XQConnection conn = xqs.getConnection("SYSTEM", "MANAGER"); String xqueryString = "declare variable $fromDate as xs:date external; " + "declare variable $toDate as xs:date external; " + "for $x in doc('books.xml')//book " + "let $publishDate := xs:date($x/publish_date) " + "where $publishDate > $fromDate and $publishDate < $toDate " + "return $x/title/text()"; XQPreparedExpression xqpe = conn.prepareExpression(xqueryString); // xs:date, we can use this to validate against when binding XQItemType dateType = conn.createAtomicType(XQItemType.XQBASETYPE_DATE); try { xqpe.bindAtomicValue( // validate against dateType (xs:date) new QName("fromDate"), "2008-01-32", dateType); // There are NOT 32 days in January, so this should fail! } catch(XQException e) { System.err.println("XQException: "+e.getMessage()); // Now set a proper date xqpe.bindAtomicValue( // validate against dateType (xs:date) new QName("fromDate"), "2008-01-01", dateType); } xqpe.bindAtomicValue( // validate against dateType (xs:date) new QName("toDate"), "2011-01-01", dateType); XQResultSequence rs = xqpe.executeQuery(); while(rs.next()) System.out.println(rs.getItemAsString(null)); conn.close(); } }

This program should produce the following output

XQException: Problem parsing xs:date string. Invalid value 32 for Day field.
XSLT 2.0 and XPath 2.0 (4th Edition)
Java Web Services: Up and Running
Effective Java (2nd Edition)
	

As you can see, when we tried to bind an invalid date by the lexical representation '2008-01-32' to an XQuery variable which was declared as the type 'xs:date' it threw an XQException at runtime, showing our error.

End of section summary

We've covered the basics of binding Java variables to XQuery variables in XQExpression and XQPreparedExpression. We've also seen a first glimpse of the power of validating bound variables against XML Schema datatypes.

The next section focuses more on the XML Schema / datatypes side of the XQJ, the ability to validate against various different types, generating our own XQuery Items and Sequences for use with XQJ.