2012-01-26 4 views
0

Я использую функцию, которая принимает два элемента DOM - родительский и дочерний из разных документов. Я импортирую дочерний элемент, преобразую его, а затем присоединяю его к родительскому элементу. Но последняя строка в следующем коде бросает исключение dom: org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: Узел используется в другом документе, кроме того, который его создал.Преобразование и добавление Dom Node

Пожалуйста, смотрите мой код ниже:

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, чтобы перенести его в свой целевой документ.

Но не делайте этого. Ваш код имеет два сериализации в String и анализирует их обратно в циклы документов, что очень неэффективно и не должно быть необходимым. После того, как вы вызвали importNode в начале, просто исправьте идентификаторы на месте и добавьте дочерний элемент в родительский элемент в конце.

+0

После импорта узла изначально я не уверен, как преобразовать идентификаторы рекурсивно. Если узел имеет несколько подуровней (2 под-уровня в моем примере), то я рекурсивно прохожу через каждый уровень? – sony

+0

Да, вы можете пройти дерево DOM с рекурсией, или вы можете получить доступ к набору узлов с идентификаторами так же, как в настоящее время с xpath. Просто измените первый параметр 'оценивать' на' child' и xpath на '........ [@id]" ' – Alohci

+0

. Xpath" .//node[@id] "в целевом элементе возвращает NodeList из только дочерние узлы. Скажем, цель «. Тогда только узлы с атрибутом id 102 и 103, но узел с id =" 101 "т.е. корень самого целевого элемента не возвращен, поэтому я сначала изменяю корень цели, а затем изменяю все дочерние узлы. Это выглядит не очень красиво. Именно поэтому я разбирался взад и вперед от xml до String. – sony