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/%22%3E <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/%22%3E <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/%22%3E <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.
Modify the value of $path to <asy:part id="2" xmlns:asy=" http://www.acme.com/%22/%3E
*Result:*
<asy:partlist xmlns:asy="http://www.acme.com/%22%3E <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 to*
declare 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"]
*Result:*
<asy:partlist xmlns:asy="http://www.acme.com/%22%3E <asy:part id="1"> <asy:part xmlns:asy="http://www.acme.com" id="2"/> </asy:part> </asy:partlist>
*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.
On Tue, Dec 15, 2015 at 3:11 AM, Christian Grün christian.gruen@gmail.com wrote:
Hi Mike,
Sorry for the late reply.
declare namespace asy="http://xml.acme.com/asy"; declare variable $part external; insert nodes $part as first into db:open("PARTDB")/asy:assembly[@name="ZB09010"]
The characters in the xs:string $path reserved for XML e.g. < > etc are converted to < > etc and the insert silently fails.
Just to be sure: Does it really 'fail' (e.g. by showing some errors), or is your XML input added as a string (which will then be output with < and > encoded as < and >)?
if I change the insert statement to :
insert nodes fn:parse-xml($part) as first into db:open("PARTDB")/asy:assembly[@name="ZB09010"]
I get the message
FODC0006 (Line 1): The prefix "asy" for element "asy:part" is not bound.
I guess your XML input did not contain an xmlns:asy namespace declaration? Without the declaration, it won’t be possible to parse it as well-formed XML input.
declare namespace asy="http://xml.acme.com/asy"; at the beginning of the $path variable contents before the XML I get FODC0006 (Line 1): Content is not allowed in prolog.
I’m not sure how to reproduce this one. If my comment above doesn’t help, feel free to provide with an example.
Hope this helps, Christian