在保留xsi:type的同时合并文档

bez*_*max 5 java xml dom xsitype

我有2个Document对象,文档包含类似的XML.例如:

<tt:root xmlns:tt="http://myurl.com/">
  <tt:child/>
  <tt:child/>
</tt:root>
Run Code Online (Sandbox Code Playgroud)

而另一个:

<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>
Run Code Online (Sandbox Code Playgroud)

我需要将它们合并到1个带有1个根元素和4个子元素的文档中.问题是,如果我使用document.importNode函数进行合并,它可以在任何地方正确处理命名空间但是xsi:type元素.所以我得到的结果是:

<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>
Run Code Online (Sandbox Code Playgroud)

如您所见,ns2用于xsi:type但未在任何地方定义.有没有自动解决这个问题的方法?

谢谢.

添加:

如果使用默认的java DOM库无法完成此任务,可能还有一些其他库可用于完成我的任务?

Gun*_*her 1

单行XQuery就可以完成这项工作:构造一个名为上下文根元素的新节点,然后将其子节点与其他文档中的子节点一起导入:

declare variable $other external; element {node-name(*)} {*/*, $other/*/*}
Run Code Online (Sandbox Code Playgroud)

尽管在 XQuery 中您无法完全控制名称空间节点(至少在 XQuery 1.0 中),但它有一个copy-namespaces模式设置,可用于要求保持名称空间上下文完整,以防实现默认情况下保留它。

如果 XQuery 是一个可行的选择,那么saxon9he.jar可能就是您所追求的“神奇 xml 库”。

以下是使用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;
  }
Run Code Online (Sandbox Code Playgroud)