转换和附加Dom节点 [英] Transforming and appending a Dom Node

查看:113
本文介绍了转换和附加Dom节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using a function which takes in two DOM Elements - parent and child from different documents. I import the child element, transform it, then append it to the parent element. But, the last line in the following code is throwing a dom exception: org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.

请在下面查看我的代码:

Please see my code below:

    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); 
    }

推荐答案

简短的答案是倒数第二行的子元素属于该行创建的文档

The short answer is that the child element on the penultimate line belongs to the document created by the line

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

,而不是父级的所有者文档.因此,您将不得不再次使用importNode将其传输到目标文档中.

and not the owner document of the parent. So you would have to use importNode again to transfer it to your target document.

但是不要那样做.您的代码有两个序列化为String并解析回Document循环,这效率非常低,而且都不是必需的.一开始调用importNode后,只需将ID固定就位,然后在最后将子代附加到父代.

But don't do that. Your code has two serialize to String and parse back to Document cycles, which is very inefficient and neither should be necessary. Once you've called importNode at the start, simply fix up the ids in place, and append the child to the parent at the end.

这篇关于转换和附加Dom节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆