2012-01-26 55 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