Hi Christian,
Our application is attempting inserting some new nodes into an XML document, we are using our own namespace for our elements.
The XML for these new nodes is in a Java String, I was planning to create am XQuery with an external variable, then bind the Java variable to it and execute the query to perform the insert.
I have been prototyping the insert using the BaseX GUI and struggling with how to perform the insert without having to parse/modify the XML containing the new nodes.
I could create a new Java String with a complete XQUery statement that includes a "let $part :=", but I come from an SQL world where we prepare an SQL statement with ? placeholders and then provide host variables with various values at run time, so the binding of variables to a "static" query seemed more natural and efficient :-)
I have conducted some experiments below, are the results what you would expect?
Thanks to all for your consideration and advice.
First example without user defined namespace
-------------------------------------------------------------------
Using the GUI create a new database (testdb) and add a single document partlist.xml
<partlist>
<part id="1"/>
</partlist>
Click on the $ symbol and define a variable :-
$part with a value <part id="2" />
Run the following query ...
declare variable $part external;
insert nodes $part as last into db:open("testdb")/partlist/part[@id="1"]
Result ...
<partlist>
<part id="1"><part id="2" /></part>
</partlist>
Note that the < and > have been converted to < >
Compare with
let $part := <part id="2" />
return
insert nodes $part as last into db:open("testdb")/partlist/part[@id="1"]
Result ...
<partlist>
<part id="1">
<part id="2"/>
</part>
</partlist>
Note that the < > are not converted to < >
Returning to the first example, modify the query ...
declare variable $part external;
insert nodes fn:parse-xml($part) as last into db:open("testdb")/partlist/part[@id="1"]
Result ...
<partlist>
<part id="1">
<part id="2"/>
</part>
</partlist>
So I assume using fn:parse-xml is required when the variable is external.
The problems begin when you introduce a namespace
Replace the filelist.xml document with ...<asy:partlist xmlns:asy="
http://www.acme.com/">
<asy:part id="1"/>
</asy:partlist>
change the first query to ...declare namespace asy="
http://www.acme.com/";
let $part := <asy:part id="2"/>
return
insert nodes $part as last into db:open("testdb")/asy:partlist/asy:part[@id="1"]
Result:<asy:partlist xmlns:asy="
http://www.acme.com/">
<asy:part id="1">
<asy:part id="2"/>
</asy:part>
</asy:partlist>
Now try using an external variable $path ...
change the value of $path to <asy:part id="2"/>
change the query ...
declare namespace asy="
http://www.acme.com";
declare variable $part external;
insert nodes $part as last into db:open("testdb")/*:partlist/*:part[@id="1"]
Result:
<asy:partlist xmlns:asy="
http://www.acme.com/">
<asy:part id="1"><asy:part id="2"/></asy:part>
</asy:partlist>
Try the parse-xml trick ...
declare namespace asy="
http://www.acme.com";
declare variable $part external;
insert nodes fn:parse-xml($part) as last into db:open("testdb")/*:partlist/*:part[@id="1"]
Gives the error ...SAX: "<asy:part id="2"/> (line 1): The prefix "asy" for element "asy:part" is not bound.
Result:
<asy:partlist xmlns:asy="
http://www.acme.com/">
<asy:part id="1">
<asy:part id="2"/>
</asy:part>
</asy:partlist>
Alternative:change the value of $path to ..declare namespace asy="
http://www.acme.com"; <asy:part id="2"/>
change the query todeclare namespace asy="
http://www.acme.com";
declare variable $part external;
insert nodes xquery:eval($part) as last into db:open("testdb")/*:partlist/*:part[@id="1"]
Conclusion:
o The behavior of let $path := and declaring $path external produces different results.
o Binding variables to XML that uses namespaces makes inserting nodes difficult because the the xml must be modified to include xmlns:
o Using the xquery:eval function and adding a declare namespace at the start of the notes to be inserted appears to work but still seems like a hack.