1
votes

I need to insert a new element into an XML document using XQuery insert expression. I am using saxon as a java api. I am new to XQuery so I am not sure about the exact structure of the insert expression. Can anyone help me in this please.

My XML file looks like the following:

<?xml version="1.0" encoding="ISO-8859-1"?>
<breakfast_menu>
<food>
 <name>Belgian Waffles</name>
 <price>$5.95</price>
 <description>two of our famous Belgian Waffles with plenty of real maple syrup<description>
 <calories>650</calories>
</food>
 </breakfast_menu>

and the java code I have for executing the insertion is

public void insert() throws XQException{
    String queryString =
            //"declare variable $docName as xs:string external;"  + sep +
            "variable $stores := doc("+"food.xml"+")/*;"+
            "insert node element food {"+
            "element name { \"brnj\" },"+
            "element price { \"$20\" },"+
            "element description { \"whatever\" },"+
            "element calories { 300 },"+
            "} into $stores;";

 XQPreparedExpression expr = conn.prepareExpression(queryString);
 expr.bindObject(new QName("stores"), "food.xml", null);
 XQResultSequence rs = expr.executeQuery();
}

the error I get is in the syntax of the query string. Please help.

3

3 Answers

1
votes

BaseX XQJ API supports XQuery Update Facility 1.0 and 3.0, which allows you to update documents in the BaseX database.

You can also update in-database documents via the MarkLogic XQJ API, Sedna XQJ API and eXist XQJ APIs although not via XQuery Update Facility, as these implementations do not support XQUF (yet).

Finally and possibly most importantly for your question, you may find Ryan Grimm's "in-mem-update" library module very useful [1]. I certainly have, countless times in the past.

You can

  • Use the library module with ANY XQuery processor + XQJ
  • Perform updates to an in-memory XML document (no need to write to disk).
  • Perform "multiple" update operations against a document in one single XQuery
  • Post updated in-memory documents can be returned in an XQResultSequence (great for you).

Also, just to make something clear here, the XQJ 1.0 Specification doesn't disallow vendors from supporting XQuery Update Facility.

An excerpt from the Specification:

"18.6 Support for Updates and Transactions

Although update functionality is not part of [XQuery], XQJ expects that some implementations will include some proprietary extensions to handle update functionality."

[1] https://github.com/marklogic/commons/blob/master/memupdate/in-mem-update.xqy

2
votes

The XQJ API doesn't support XQuery updates. I believe that some vendors have extended XQJ to support updates, but since the license conditions for XQJ impose the death penalty on anyone who tries to extend the API, I refrained from doing this in Saxon. (I'm also not aware of any initiative to define such extensions - XQJ was strangled by lawyers from the day it started, for reasons I have never understood.)

If you're using Saxon as your XQuery update engine, I recommend using the s9api interface. Here is an example:

   public void run() throws SaxonApiException {
        Processor proc = new Processor(true);
        XQueryCompiler comp = proc.newXQueryCompiler();
        comp.setUpdatingEnabled(true);
        XQueryExecutable exp = comp.compile(
                "for $p in doc('data/books.xml')//PRICE " +
                "return replace value of node $p with $p + 0.05");

        XQueryEvaluator eval = exp.load();
        eval.run();
        for (Iterator<XdmNode> iter = eval.getUpdatedDocuments(); iter.hasNext();) {
            XdmNode root = iter.next();
            URI rootUri = root.getDocumentURI();
            if (rootUri != null && rootUri.getScheme().equals("file")) {
                try {
                    Serializer out = proc.newSerializer(new FileOutputStream(new File(rootUri)));
                    out.setOutputProperty(Serializer.Property.METHOD, "xml");
                    out.setOutputProperty(Serializer.Property.INDENT, "yes");
                    out.setOutputProperty(Serializer.Property.OMIT_XML_DECLARATION, "yes");
                    System.err.println("Rewriting " + rootUri);
                    proc.writeXdmValue(root, out);
                } catch (FileNotFoundException e) {
                    System.err.println("Could not write to file " + rootUri);
                }
            } else {
                System.err.println("Updated document not rewritten: location unknown or not updatable");
            }
        }
    }

Most of the complexity is in writing the updated document back to filestore - which is not necessarily what you want to do, of course.

Note that XQuery Update is supported only in the commercial editions of Saxon.

1
votes

It is possible now.

Upload queries:

public static void ejecutarConsultaU(String cadenaAConsultar) throws XQException {
    XQExpression consulta;
    consulta = xqc.createExpression();
    System.out.println("Inicio consulta \n");
    System.out.println(cadenaAConsultar);
    System.out.println("fin consulta \n");
    consulta.executeCommand(cadenaAConsultar);}

Insert/select queries:

public static void ejecutarConsulta(String cadenaAConsultar) throws XQException {
    XQPreparedExpression consulta;
    consulta = xqc.prepareExpression(cadenaAConsultar);
    XQResultSequence resultado = consulta.executeQuery();
}