I have 2 Document objects with documents that contain similiar XML's. For example:
<tt:root xmlns:tt="http://myurl.com/">
<tt:child/>
<tt:child/>
</tt:root>
And the other one:
<ns1:root xmlns:ns1="http://myurl.com/" xmlns:ns2="http://myotherurl.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns1:child/>
<ns1:child xsi:type="ns2:SomeType"/>
</ns1:root>
I need to merge them to 1 document with 1 root element and 4 child elements.
Problem is, if I use document.importNode
function to do the merging, it properly handles the namespaces everywhere BUT xsi:type element. So what I'm getting in result is this:
<tt:root xmlns:tt="http://myurl.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<tt:child/>
<tt:child/>
<ns1:child xmlns:ns1="http://myurl.com/"/>
<ns1:child xmlns:ns1="http://myurl.com/" xsi:type="ns2:SomeType"/>
</tt:root>
As you can see, ns2 is used in xsi:type
but is not defined anywhere. Is there any automated way to solve this problem?
Thanks.
ADDED:
If this task is impossible to complete using the default java DOM libraries, maybe there is some other library I can use to complete my task?
A single-line of XQuery could do the job: construct a new node named as the context root element, then import its children together with those from the other document:
declare variable $other external; element {node-name(*)} {*/*, $other/*/*}
Though in XQuery you don't have full control over namespace nodes (at least in XQuery 1.0), it has a copy-namespaces
mode setting that can be used to ask for keeping the namespace context intact, in case the implementation does preserve it by default.
If XQuery is a viable option, then saxon9he.jar could be the "magic xml library" that you are after.
Here is sample code exposing some context, using the s9api API:
import javax.xml.parsers.DocumentBuilderFactory;
import net.sf.saxon.s9api.*;
import org.w3c.dom.Document;
...
Document merge(Document context, Document other) throws Exception
{
Processor processor = new Processor(false);
XQueryExecutable executable = processor.newXQueryCompiler().compile(
"declare variable $other external; element {node-name(*)} {*/*, $other/*/*}");
XQueryEvaluator evaluator = executable.load();
DocumentBuilder db = processor.newDocumentBuilder();
evaluator.setContextItem(db.wrap(context));
evaluator.setExternalVariable(new QName("other"), db.wrap(other));
Document doc =
DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
processor.writeXdmValue(evaluator.evaluate(), new DOMDestination(doc));
return doc;
}