2012-01-26 36 views
0

我正在使用一个函数,它接受两个DOM元素 - 来自不同文档的父代和子代。我导入子元素,将其转换,然后将其附加到父元素。但是,以下代码中的最后一行是抛出一个dom异常:org.w3c.dom.DOMException:WRONG_DOCUMENT_ERR:节点在与创建节点不同的文档中使用。转换和添加Dom节点

请参阅下面我的代码:

public void attachNodeToParent (Element parent, Element child) throws Exception { 
     Document parent_doc = parent.getOwnerDocument(); 
     child = (Element)parent_doc.importNode(child, true); 
// Imported child Element is shown below: 
//  <node id="101"> 
//  <node id="102"> 
//   <node id="103" /> 
//  </node> 
//  <node id="104"> 
//   <node id="103" /> 
//  </node> 
//  </node> 

     // convert child Element into String 
     Source source = new DOMSource(child); 
     StringWriter stringWriter = new StringWriter(); 
     Result result = new StreamResult(stringWriter); 
     TransformerFactory factory = TransformerFactory.newInstance(); 
     Transformer transformer = factory.newTransformer(); 
     transformer.transform(source, result); 
     String childXml = stringWriter.getBuffer().toString(); 


     // Recursively modify the id attributes of every node 
     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
     DocumentBuilder db = dbf.newDocumentBuilder(); 
     Document doc = db.parse(new InputSource(new StringReader(childXml))); 
     XPathFactory xpathFactory = XPathFactory.newInstance(); 
     XPath xpath = xpathFactory.newXPath(); 
     NodeList nodes = (NodeList) xpath.compile("//node[@id]").evaluate(doc, XPathConstants.NODESET); 
     for (int nodeNumber = 0; nodeNumber < nodes.getLength(); ++nodeNumber) { 
      final Element node = (Element) nodes.item(nodeNumber); 
      final String nodeId = node.getAttribute("id"); 
      final String newNodeId = "prefix/" + nodeId; 
      node.getAttributeNode("id").setValue(newNodeId); 
     } 


     final StringWriter writer = new StringWriter(); 
     transformer.transform(source, new StreamResult(writer)); 
     writer.flush(); 
     writer.close(); 
     String transformedChildXml = writer.toString(); 

     // Prase transformedChildXml String into XML 
     dbf.setNamespaceAware(true); 
     DocumentBuilder builder = dbf.newDocumentBuilder(); 
     Document document = builder.parse(new InputSource(new StringReader(transformedChildXml))); 
     document.setXmlStandalone(false); 
     child = document.getDocumentElement(); 

     // child Element is now transformed to: 
//  <node id="prefix/101"> 
//   <node id="prefix/102"> 
//   <node id="prefix/103" /> 
//   </node> 
//   <node id="prefix/104"> 
//   <node id="prefix/103" /> 
//   </node> 
//  </node> 

     // append transformed child Element to parent Element 
     // Throws o rg.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: 
     // A node is used in a different document than the one that created it. 
     parent.appendChild(child); 
    } 

回答

0

简短的回答是,在倒数第二行的子元素属于该行

Document document = builder.parse(new InputSource(new StringReader(transformedChildXml))); 

,而不是所有者文件创建的文档父母。所以你将不得不再次使用importNode将其转移到目标文档。

但不这样做。您的代码有两个序列化为字符串并解析回文档循环,这是非常低效的,都不是必要的。一旦您在开始时调用importNode,只需简单地修复id,并在最后将子项追加到父项。

+0

最初导入节点后,我不确定如何递归转换ID。如果节点有多个子级(在我的例子中是2个子级),那么我是否递归循环遍历每个级别? – sony 2012-01-27 01:32:16

+0

是的,您可以使用递归来遍历DOM树,或者您可以像使用xpath一样使用id来访问节点集。只需将“evaluate”的第一个参数更改为“child”,将xpath更改为“”.// node [@id]“' – Alohci 2012-01-27 07:26:17

+0

目标Element上的xpath”.//node[@id]“返回NodeList只有子节点。假设目标为“。然后只有id为102和103的节点,但节点为id =”101“目标元素本身的根目录没有被返回,所以我首先修改了目标的根目录,然后修改了所有的子节点,这看起来不太漂亮,这就是为什么我从XML到String来回解析的原因。 – sony 2012-01-27 14:32:16