javaxmlxquerysaxonxqj

Howto refer dynamically to an XML file in XQuery in Saxon


I am using the XQuery processor Saxon.
Now we write our XQuery in a ".xqy" file where we refer to the XML file on which we will perform our XQuery.
Please see the example below:

for $x in doc("books.xml")/books/book
where $x/price>30
return $x/title

Now I want to use dynamically generated XML not stored in some path. Say, for example, I want to refer below XML that is available as a string.

How to do that?

String book=
<books>
   <book category="JAVA">
      <title lang="en">Learn Java in 24 Hours</title>
      <author>Robert</author>
      <year>2005</year>
      <price>30.00</price>
   </book>
   <book category="DOTNET">
      <title lang="en">Learn .Net in 24 hours</title>
      <author>Peter</author>
      <year>2011</year>
      <price>40.50</price>
   </book>
   <book category="XML">
      <title lang="en">Learn XQuery in 24 hours</title>
      <author>Robert</author>
      <author>Peter</author> 
      <year>2013</year>
      <price>50.00</price>
   </book>
   <book category="XML">
      <title lang="en">Learn XPath in 24 hours</title>
      <author>Jay Ban</author>
      <year>2010</year>
      <price>16.50</price>
   </book>
</books>

Java code:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

import javax.xml.xquery.XQConnection;
import javax.xml.xquery.XQDataSource;
import javax.xml.xquery.XQException;
import javax.xml.xquery.XQPreparedExpression;
import javax.xml.xquery.XQResultSequence;

import com.saxonica.xqj.SaxonXQDataSource;

public class XQueryTester {
   public static void main(String[] args){
      try {
         execute();
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      } catch (XQException e) {
         e.printStackTrace();
      }
   }

   private static void execute() throws FileNotFoundException, XQException{
      InputStream inputStream = new FileInputStream(new File("books.xqy"));
      XQDataSource ds = new SaxonXQDataSource();
      XQConnection conn = ds.getConnection();
      XQPreparedExpression exp = conn.prepareExpression(inputStream);
      XQResultSequence result = exp.executeQuery();
      while (result.next()) {
         System.out.println(result.getItemAsString(null));
      }
   }    
}

Solution

  • If you look for a way to bind the input (the context item) of the query using Java, I recommend using Saxon's S9API (the most intuitive API for XSLT, XPath and XQuery processing in Java).

    Here is how to instantiate Saxon, compile the query, parse the input and evaluate the query with the input document bound as its context item:

    // the Saxon processor object
    Processor saxon = new Processor(false);
    
    // compile the query
    XQueryCompiler compiler = saxon.newXQueryCompiler();
    XQueryExecutable exec = compiler.compile(new File("yours.xqy"));
    
    // parse the string as a document node
    DocumentBuilder builder = saxon.newDocumentBuilder();
    String input = "<xml>...</xml>";
    Source src = new StreamSource(new StringReader(input));
    XdmNode doc = builder.build(src);
    
    // instantiate the query, bind the input and evaluate
    XQueryEvaluator query = exec.load();
    query.setContextItem(doc);
    XdmValue result = query.evaluate();
    

    Note that if the Java code is generating the XML document, I strongly advice you to use S9API to build the tree directly in memory, instead of generating the XML document as a string, then parse it. If possible.