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