我有两个包含类似XML文档的文档对象。
<tt:root xmlns:tt="http://myurl.com/">
<tt:child/>
<tt:child/>
</tt:root>另一个是:
<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>我需要将它们合并为一个包含一个根元素和四个子元素的文档。问题是,如果我使用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>如您所见,ns2在xsi:type中使用,但在任何地方都没有定义。有什么自动解决这个问题的方法吗?
谢谢。
添加:
如果这个任务无法使用默认的java库来完成,那么可能还有其他库可以用来完成我的任务吗?
发布于 2011-06-08 21:46:32
XQuery的一行可以完成以下工作:构造一个名为上下文根元素的新节点,然后将其子节点与其他文档中的子节点一起导入:
declare variable $other external; element {node-name(*)} {*/*, $other/*/*}虽然在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;
}发布于 2011-06-01 11:04:47
如果我修复了第二个文件中的命名空间问题(通过绑定"xsi“前缀),并使用下面的代码进行合并,名称空间绑定将保留在输出上;或者至少在这里( Windows 1.6.0_24上的普通Java64位)。
String s1 = "<!-- 1st XML document here -->";
String s2 = "<!-- 2nd XML document here -->";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware( true );
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc1 = builder.parse( new ByteArrayInputStream( s1.getBytes() ) );
Document doc2 = builder.parse( new ByteArrayInputStream( s2.getBytes() ) );
Element doc1root = ( Element )doc1.getDocumentElement();
Element doc2root = ( Element )doc2.getDocumentElement();
NamedNodeMap atts1 = doc1root.getAttributes();
NamedNodeMap atts2 = doc2root.getAttributes();
for( int i = 0; i < atts1.getLength(); i++ )
{
String name = atts1.item( i ).getNodeName();
if( name.startsWith( "xmlns:" ) )
{
if( atts2.getNamedItem( name ) == null )
{
doc2root.setAttribute( name, atts1.item( i ).getNodeValue() );
}
}
}
NodeList nl = doc1.getDocumentElement().getChildNodes();
for( int i = 0; i < nl.getLength(); i++ )
{
Node n = nl.item( i );
doc2root.appendChild( doc2.importNode( n, true ) );
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
StreamResult streamResult = new StreamResult( System.out );
transformer.transform( new DOMSource( doc2 ), streamResult );发布于 2011-06-06 09:01:01
这里的问题是在属性值中使用名称空间前缀;在创建命名空间标准时从未考虑到的问题,以及一些常见的Java /XML工具无法轻松处理的问题。但是,你可以通过
xsi:type="prefix:value"的每个实例替换为xsi:type="{namespace}value"。通过这样做,您不依赖于前缀映射。在您的示例中,<xsi:type="ns2:SomeType"将变成xsi:type="{http://myotherurl.com/}SomeType"。https://stackoverflow.com/questions/6198485
复制相似问题