7

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));
      }
   }    
}
zx485
  • 28,498
  • 28
  • 50
  • 59
Rahul ray
  • 191
  • 1
  • 4
  • 12
  • You could pass the string as a parameter and parse it inside the XQuery code with `parse-xml($param)` or you can parse the XML in Java and pass it as parameter to your XQuery code. Can you show us your Java code using Saxon? Which API(s) of Saxon do you use? – Martin Honnen May 23 '15 at 17:01
  • @MartinHonnen thanks for comment.I have added java code please see above. – Rahul ray May 23 '15 at 17:40

2 Answers2

6

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.

Florent Georges
  • 2,190
  • 1
  • 15
  • 24
  • **XQuery** with namespaces [using s9api for XQuery] (http://www.saxonica.com/documentation9.5/index.html#!using-xquery/api-query/s9api-query )`compiler.declareNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");compiler.compile("for $x in /soap:Envelope return $x/soap:Body");` [Saxon-HE-*.jar](http://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE ) – Yash Dec 03 '15 at 10:32
  • what do you mean by build the tree in memory? – Thufir Jan 18 '19 at 04:14
  • XML is a tree of nodes (elements, attributes, text...) Parsing some XML as a string is to build the corresponding tree in memory. But you can also use S9API to build the tree in memory directly, without going through the step of generating a string then parsing it (by using instead functions like "create element", "add text", "create attribute", etc.) – Florent Georges Jan 23 '19 at 17:37
1

here is how I implemented as suggested by above user-

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

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
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 net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XQueryCompiler;
import net.sf.saxon.s9api.XQueryEvaluator;
import net.sf.saxon.s9api.XQueryExecutable;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XdmValue;

import com.saxonica.xqj.SaxonXQDataSource;


public class Xml {  public static void main(String[] args){
    try {
        process();
     } catch (FileNotFoundException e) {
        e.printStackTrace();
     } catch (Exception e) {
        e.printStackTrace();
     }
  }
public static void process() throws SaxonApiException, IOException{
    // the Saxon processor object
    Processor saxon = new Processor(false);

    // compile the query
    XQueryCompiler compiler = saxon.newXQueryCompiler();
    XQueryExecutable exec;
    exec = compiler.compile(new File("E:\\abc.xqy"));


    // parse the string as a document node
    DocumentBuilder builder = saxon.newDocumentBuilder();
    String input = "<data><employee id=\"1\"><name>A</name>"
        + "<title>Manager</title></employee>+<employee id=\"2\"><name>B</name>"
        + "<title>Manager</title></employee>+</data>";
    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();
    System.out.println(result.itemAt(0));
}
Rahul ray
  • 191
  • 1
  • 4
  • 12
  • I am not sure how you create `input` for real, but I suggest you get a look at [DocumentBuilder.newBuildingStreamWriter](http://www.saxonica.com/html/documentation/javadoc/net/sf/saxon/s9api/DocumentBuilder.html#newBuildingStreamWriter%28%29) for a way to construct the tree directly, programmatically, instead of generating a string to be parsed. – Florent Georges May 24 '15 at 11:12
  • @FlorentGeorges but why I need lock?I am fetching this xml data from webservice and then I am reading some particular element from that.Do i need lock in this case? – Rahul ray May 24 '15 at 11:15
  • Mmh, not sure what you mean by "*lock*". If you retrieve the document as a string, then yes you have to parse it. But this was not clear from your question, and if you build the string yourself (like using concats and stuff), then usually it's a bad idea. – Florent Georges May 24 '15 at 11:32
  • @FlorentGeorges u have suggested me in above comment get a look at DocumentBuilder.newBuildingStreamWriter,I was talking about the same.Do i need in that case,here I am fetching xml from webservice. – Rahul ray May 24 '15 at 11:38