【问题标题】:Concatenate two org.w3c.dom.Document连接两个 org.w3c.dom.Document
【发布时间】:2019-08-28 15:24:30
【问题描述】:

我想连接两个 org.w3c.dom.Document ,我有这样的东西:

Document finalDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
Document document1 = createDocumentOne();
Document document2 = createDocumentTwo();

// This didn't work
changeFileDocument.appendChild(document1);
changeFileDocument.appendChild(document2);

document1和document2的格式是这样的:

<headerTag>
    <tag1>value</tag1>  
</headerTag>

最后,我想要的是这样的文档:

<headerTag>
    <tag1>valueForDocument1</tag1>  
</headerTag>
<headerTag>
    <tag1>valueForDocument2</tag1>  
</headerTag>

我认为你不能这样做,因为他们应该有一个共同的父母。如果是这样,我想创建那个“假”父级,连接文件,然后只恢复元素列表 headerTag

我该怎么做?

【问题讨论】:

  • headerTag 是您的根元素吗?如果不是,根元素是什么?
  • 您需要一个根元素来构建正确的 xml 文档。如果不是 xml,请提及构建它的标记语言。此外,为什么不将 org.w3c.Document (s) 转换为相应的字符串文件并将它们连接起来,最后从中制作另一个 org.w3c.Document 实例。
  • @A4L,“headerTag”是由“createDocument1”和“createDocument2”方法创建的文档的根元素,我唯一想要的就是一个接一个地连接,即使我有创建根父级。

标签: java xml concatenation document


【解决方案1】:

您在创建新文档、解析部分并将其节点添加到新文档方面处于正确的轨道上。

您的方法失败了,因为您尝试将整个文档附加到另一个文档,这是不可能的。

你可以试试这样的:

public org.w3c.dom.Document concatXmlDocuments(String rootElementName, InputStream... xmlInputStreams) throws ParserConfigurationException, SAXException, IOException {
    DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    org.w3c.dom.Document result = builder.newDocument();
    org.w3c.dom.Element rootElement = result.createElement(rootElementName);
    result.appendChild(rootElement);
    for(InputStream is : xmlInputStreams) {
        org.w3c.dom.Document document = builder.parse(is);
        org.w3c.dom.Element root = document.getDocumentElement();
        NodeList childNodes = root.getChildNodes();
        for(int i = 0; i < childNodes.getLength(); i++) {
            Node importNode = result.importNode(childNodes.item(i), true);
            rootElement.appendChild(importNode);
        }
    }
    return result;
}

上面的代码复制了在每个文档的根元素下找到的所有节点。当然,您可以选择仅选择性地复制您感兴趣的节点。生成的文档将反映两个文档中的所有节点。

测试

@Test
public void concatXmlDocuments() throws ParserConfigurationException, SAXException, IOException, TransformerException {
    try (
            InputStream doc1 = new ByteArrayInputStream((
                "<headerTag>\r\n" + 
                "    <tag1>doc1 value</tag1>\r\n" + 
                "</headerTag>").getBytes(StandardCharsets.UTF_8));
            InputStream doc2 = new ByteArrayInputStream((
                "<headerTag>\r\n" + 
                "    <tag1>doc2 value</tag1>\r\n" + 
                "</headerTag>").getBytes(StandardCharsets.UTF_8));
            ByteArrayOutputStream docR = new ByteArrayOutputStream();

        ) {

        org.w3c.dom.Document result = concatXmlDocuments("headerTag", doc1, doc2);
        TransformerFactory trf = TransformerFactory.newInstance();
        Transformer tr = trf.newTransformer();
        tr.setOutputProperty(OutputKeys.INDENT, "yes");
        DOMSource source = new DOMSource(result);
        StreamResult sr = new StreamResult(docR);
        tr.transform(source, sr);
        System.out.print(new String(docR.toByteArray(), StandardCharsets.UTF_8));
    }
}

输出

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<headerTag>
    <tag1>doc1 value</tag1>
    <tag1>doc2 value</tag1>
</headerTag>

编辑

我想创建那个“假”父级,连接文件,然后只恢复元素列表 headerTag

如你所说,创建一个 fake 父级。你可以这样做:

1) 进行连接

public org.w3c.dom.Document concatXmlDocuments(InputStream... xmlInputStreams) throws ParserConfigurationException, SAXException, IOException {
    DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    org.w3c.dom.Document result = builder.newDocument();
    org.w3c.dom.Element rootElement = result.createElement("fake");
    result.appendChild(rootElement);
    for(InputStream is : xmlInputStreams) {
        org.w3c.dom.Document document = builder.parse(is);
        org.w3c.dom.Element subRoot = document.getDocumentElement();
        Node importNode = result.importNode(subRoot, true);
        rootElement.appendChild(importNode);
    }
    return result;
}

2) 恢复headerTag的节点列表

public NodeList recoverTheListOfElementsHeaderTag(String xml) throws ParserConfigurationException, SAXException, IOException {
    NodeList listOfElementsHeaderTag = null;
    DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    try (InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
        listOfElementsHeaderTag = recoverTheListOfElementsHeaderTag(builder.parse(is));
    }
    return listOfElementsHeaderTag;
}

public NodeList recoverTheListOfElementsHeaderTag(org.w3c.dom.Document doc) {
    org.w3c.dom.Element root = doc.getDocumentElement();
    return root.getChildNodes();
}

测试

@Test
public void concatXmlDocuments() throws ParserConfigurationException, SAXException, IOException, TransformerException {
    try (
            InputStream doc1 = new ByteArrayInputStream((
                "<headerTag>" + 
                "<tag1>doc1 value</tag1>" + 
                "</headerTag>").getBytes(StandardCharsets.UTF_8));
            InputStream doc2 = new ByteArrayInputStream((
                "<headerTag>" + 
                "<tag1>doc2 value</tag1>" + 
                "</headerTag>").getBytes(StandardCharsets.UTF_8));

        ) {

        org.w3c.dom.Document result = concatXmlDocuments(doc1, doc2);
        String resultXML = toXML(result);
        System.out.printf("%s%n", resultXML);
        NodeList listOfElementsHeaderTag = null;
        System.out.printf("===================================================%n");
        listOfElementsHeaderTag = recoverTheListOfElementsHeaderTag(resultXML);
        printNodeList(listOfElementsHeaderTag);
        System.out.printf("===================================================%n");
        listOfElementsHeaderTag = recoverTheListOfElementsHeaderTag(result);
        printNodeList(listOfElementsHeaderTag);
    }
}


private String toXML(org.w3c.dom.Document result) throws TransformerFactoryConfigurationError, TransformerConfigurationException, TransformerException, IOException {
    String resultXML = null;
    try (ByteArrayOutputStream docR = new ByteArrayOutputStream()) {
        TransformerFactory trf = TransformerFactory.newInstance();
        Transformer tr = trf.newTransformer();
        DOMSource source = new DOMSource(result);
        StreamResult sr = new StreamResult(docR);
        tr.transform(source, sr);
        resultXML = new String(docR.toByteArray(), StandardCharsets.UTF_8);
    }
    return resultXML;
}

private void printNodeList(NodeList nodeList) {
    for(int i = 0; i < nodeList.getLength(); i++) {
        printNode(nodeList.item(i), "");
    }
}

private void printNode(Node node, String startIndent) {
    if(node != null) {
        System.out.printf("%s%s%n", startIndent, node.toString());
        NodeList childNodes = node.getChildNodes();
        for(int i = 0; i < childNodes.getLength(); i++) {
            printNode(childNodes.item(i), startIndent+ "    ");
        }
    }
}

输出

<?xml version="1.0" encoding="UTF-8" standalone="no"?><fake><headerTag><tag1>doc1 value</tag1></headerTag><headerTag><tag1>doc2 value</tag1></headerTag></fake>
===================================================
[headerTag: null]
    [tag1: null]
        [#text: doc1 value]
[headerTag: null]
    [tag1: null]
        [#text: doc2 value]
===================================================
[headerTag: null]
    [tag1: null]
        [#text: doc1 value]
[headerTag: null]
    [tag1: null]
        [#text: doc2 value]

【讨论】:

  • 嗨@A4L,感谢您的评论,但这不是我感兴趣的输出。我有兴趣&lt;headerTag&gt; &lt;tag1&gt;dic1 value&lt;/tag1&gt; &lt;/headerTag&gt; &lt;headerTag&gt; &lt;tag1&gt;doc2 value&lt;/tag1&gt; &lt;/headerTag&gt;
  • @Manuelarte,好的,那为什么还要麻烦 XML 解析呢?您想要的输出不是有效的 XML,然后根标记出现两次或没有根标记,因此只需将两个文件作为文本读取并应用 + 运算符。如果您之后需要将其解析为 XML,则需要将其包装在名称不是 headerTag 的根标签中,然后您可以使用 Document#getDocumentElement().getElementsByTagName("tag1"); 获取所需的节点
  • @Manuelarte,我已经编辑了我的答案,希望它反映了您的要求。
【解决方案2】:

正如您所说,您需要有一个根节点 - 并且您需要导入其他文档。例如:

Element root = finalDocument.createElement("root");
finalDocument.appendChild(root);
root.appendChild(
    finalDocument.importNode(document1.getDocumentElement(), true));
root.appendChild(
    finalDocument.importNode(document2.getDocumentElement(), true));

【讨论】:

  • 然后,我使用 finalDocument.changeFileDocument.getChildNodes() 检索我感兴趣的元素?我呢?
  • @Manuelarte:嗯,完全不清楚changeFileDocument 是什么意思,或者你所说的“我感兴趣的元素”是什么意思。
  • 您使用方法 createDocument1()、createDocument2() 创建 XML 文档。然后,您希望将它们连接成一个文档,称为 finalDocument。稍后,我想从 finalDocument 中仅恢复节点。是不是更清楚了?
  • @Manuelarte:只有哪些个节点?你的问题是关于连接文件......我已经向你展示了如何做到这一点。之后你对文档的处理听起来像是一个完全不同的问题。
  • 感谢您的回答。实际上,这是问题的一部分,但现在没关系,因为只有将它们连接起来才是我感兴趣的。谢谢
猜你喜欢
  • 2023-04-09
  • 2016-11-18
  • 2016-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多