将字符串 XML 片段转换为 Java 中的文档节点

Posted

技术标签:

【中文标题】将字符串 XML 片段转换为 Java 中的文档节点【英文标题】:Convert String XML fragment to Document Node in Java 【发布时间】:2010-10-18 07:04:35 【问题描述】:

在 Java 中,如何将表示 XML 片段的字符串转换为插入 XML 文档?

例如

String newNode =  "<node>value</node>"; // Convert this to XML

然后将此节点作为给定节点的子节点插入到 org.w3c.dom.Document 中?

【问题讨论】:

另见:***.com/a/7607435/363573 这能回答你的问题吗? How can I parse a html string in Java? @Suma 这个问题是关于 HTML,这是关于 XML。 【参考方案1】:
Element node =  DocumentBuilderFactory
    .newInstance()
    .newDocumentBuilder()
    .parse(new ByteArrayInputStream("<node>value</node>".getBytes()))
    .getDocumentElement();

【讨论】:

.parse(new StringInputStream(.... 应该读为 .parse(new ByteArrayInputStream(new String("xml").getBytes())); 我只是讨厌这些评论框以及它们缺乏标记(或降价,就此而言) 但这不会复制孩子们......例如,如果你在“blah blah 它只得到 没有它的孩子 这对我不起作用,因为它没有像 grobartn 所指出的那样复制孩子。 @McDowell 的解决方案确实有效。【参考方案2】:

您可以使用文档的import(或adopt)方法添加XML片段:

  /**
   * @param docBuilder
   *          the parser
   * @param parent
   *          node to add fragment to
   * @param fragment
   *          a well formed XML fragment
   */
  public static void appendXmlFragment(
      DocumentBuilder docBuilder, Node parent,
      String fragment) throws IOException, SAXException 
    Document doc = parent.getOwnerDocument();
    Node fragmentNode = docBuilder.parse(
        new InputSource(new StringReader(fragment)))
        .getDocumentElement();
    fragmentNode = doc.importNode(fragmentNode, true);
    parent.appendChild(fragmentNode);
  

【讨论】:

嗯。如果这是最简单的解决方案,我必须说对于这么小的问题来说它是相当复杂的。 我已将其缩减到最低限度 - 不过,它仍然使用您在 JRE API 中获得的内容,因此有些冗长是不可避免的。 这正是我想要的。我没有意识到我必须先将片段导入到 dom 中,然后才能将其附加到父节点! 如果你不想冗长,你一定不要使用Java,Luke。感谢您的回答,任何人都没有机会弄清楚这一点。 尽管根据用户的要求选择的答案是正确的,但这个分析器“更”正确。【参考方案3】:

对于它的价值,这是我使用dom4j 库提出的解决方案。 (我确实检查过它是否有效。)

将 XML 片段读入org.dom4j.Document(注意:下面使用的所有 XML 类均来自 org.dom4j;见附录):

  String newNode = "<node>value</node>"; // Convert this to XML
  SAXReader reader = new SAXReader();
  Document newNodeDocument = reader.read(new StringReader(newNode));

然后获取插入新节点的 Document 以及其中的父 Element(将要成为)。 (您的 org.w3c.dom.Document 需要在此处转换为 org.dom4j.Document。)出于测试目的,我创建了一个这样的:

    Document originalDoc = 
      new SAXReader().read(new StringReader("<root><given></given></root>"));
    Element givenNode = originalDoc.getRootElement().element("given");

添加新的子元素非常简单:

    givenNode.add(newNodeDocument.getRootElement());

完成。输出originalDoc 现在产生:

<?xml version="1.0" encoding="utf-8"?>

<root>
    <given>
        <node>value</node>
    </given>
</root>

附录:因为您的问题涉及org.w3c.dom.Document,所以这里是如何在它和org.dom4j.Document 之间进行转换。

// dom4j -> w3c
DOMWriter writer = new DOMWriter();
org.w3c.dom.Document w3cDoc = writer.write(dom4jDoc);

// w3c -> dom4j
DOMReader reader = new DOMReader();
Document dom4jDoc = reader.read(w3cDoc);

(如果您经常需要这两种Documents,将它们放在简洁的实用方法中可能是有意义的,可能放在名为XMLUtils 或类似的类中。)

也许有更好的方法来做到这一点,即使没有任何 3rd 方库。但在目前提供的解决方案中,我认为这是最简单的方法,即使您需要进行 dom4j w3c 转换。

更新 (2011):在将 dom4j 依赖项添加到您的代码之前,请注意 it is not an actively maintained project, and has some other problems too。改进的 2.0 版已经投入使用多年,但只有 alpha 版可用。您可能需要考虑替代方案,例如 XOM;在上面链接的问题中阅读更多内容。

【讨论】:

如果 dom4j 不可行,请尝试以下解决方案:***.com/a/7607435/363573【参考方案4】:

这是另一个解决方案,使用XOM library,与my dom4j answer 竞争。 (这是我的quest to find a good dom4j replacement 的一部分,其中建议将 XOM 作为一种选择。)

首先将XML片段读入nu.xom.Document

String newNode = "<node>value</node>"; // Convert this to XML
Document newNodeDocument = new Builder().build(newNode, "");

然后,获取添加片段的文档和节点。同样,出于测试目的,我将从字符串创建文档:

Document originalDoc = new Builder().build("<root><given></given></root>", "");
Element givenNode = originalDoc.getRootElement().getFirstChildElement("given");

现在,添加子节点很简单,与 dom4j 类似(除了 XOM 不允许添加已经属于 newNodeDocument 的原始根元素):

givenNode.appendChild(newNodeDocument.getRootElement().copy());

输出文档会产生正确的 XML 结果(使用 XOM 非常容易:只需打印 originalDoc.toXML() 返回的字符串):

<?xml version="1.0"?>
<root><given><node>value</node></given></root>

(如果您想很好地格式化 XML(带有缩进和换行符),请使用 Serializer;感谢 Peter Štibraný 指出这一点。)

所以,诚然,这与 dom4j 解决方案没有太大区别。 :) 但是,使用 XOM 可能会更好一些,因为 API 有更好的文档记录,并且因为它的设计理念是每件事都有一个规范的方法。

附录:再次说明如何在org.w3c.dom.Documentnu.xom.Document 之间进行转换。使用 XOM 的 DOMConverter 类中的辅助方法:

// w3c -> xom
Document xomDoc = DOMConverter.convert(w3cDoc);

// xom -> w3c
org.w3c.dom.Document w3cDoc = DOMConverter.convert(xomDoc, domImplementation);  
// You can get a DOMImplementation instance e.g. from DOMImplementationRegistry

【讨论】:

请注意,不是 new Builder().build(new StringReader(""));你也可以使用 new Builder().build("", "test.xml"); (其中“test.xml”是一些随机的基础 URI) “如果您想很好地格式化 XML(带有缩进和换行),我不知道如何使用 XOM 来做到这一点。” -- 使用序列化器类。使用 setIndent 和 setMaxLength 配置它,并调用 write(document)。 序列化器也很容易通过子类化来定制。 谢谢!我真的不明白 baseURI 参数的确切含义是什么;传递一个空字符串也可以,所以我正在使用它。无论如何,这确实在一定程度上简化了代码。对于格式化,Serializer 确实可以正常工作。 我认为 baseURI 将用于解析对 DTD 或 XInclude 的相对引用 (lists.ibiblio.org/pipermail/xom-interest/2004-November/…)【参考方案5】:
/**
*
* Convert a string to a Document Object
*
* @param xml The xml to convert
* @return A document Object
* @throws IOException
* @throws SAXException
* @throws ParserConfigurationException
*/
public static Document string2Document(String xml) throws IOException, SAXException, ParserConfigurationException 

    if (xml == null)
    return null;

    return inputStream2Document(new ByteArrayInputStream(xml.getBytes()));




/**
* Convert an inputStream to a Document Object
* @param inputStream The inputstream to convert
* @return a Document Object
* @throws IOException
* @throws SAXException
* @throws ParserConfigurationException
*/
public static Document inputStream2Document(InputStream inputStream) throws IOException, SAXException, ParserConfigurationException 
    DocumentBuilderFactory newInstance = DocumentBuilderFactory.newInstance();
    newInstance.setNamespaceAware(true);
    Document parse = newInstance.newDocumentBuilder().parse(inputStream);
    return parse;

【讨论】:

【参考方案6】:

如果你使用 dom4j,你可以这样做:

文档文档 = DocumentHelper.parseText(text);

(dom4j 现在在这里找到:https://github.com/dom4j/dom4j)

【讨论】:

刚刚访问了他们的网站。他们将 Google Ads 直接放入典型的 Maven 生成的导航栏中!难以置信! 显然,该网站不再由 dom4j 家伙运营,但一些域名抢夺者接管了......【参考方案7】:

...如果您使用的是纯 XOM,则如下所示:

    String xml = "<fakeRoot>" + xml + "</fakeRoot>";
    Document doc = new Builder( false ).build( xml, null );
    Nodes children = doc.getRootElement().removeChildren();
    for( int ix = 0; ix < children.size(); ix++ ) 
        otherDocumentElement.appendChild( children.get( ix ) );
    

XOM 在内部使用 fakeRoot 来做几乎相同的事情,所以它应该是安全的,即使不是很优雅。

【讨论】:

【参考方案8】:

试试jcabi-xml,用一个衬里:

Node node = new XMLDocument("<node>value</node>").node();

【讨论】:

jcabi-xml 构建错误Unresolved references to [com.jcabi.xml] by class(es) on the Bundle-Classpath[Jar:dot]

以上是关于将字符串 XML 片段转换为 Java 中的文档节点的主要内容,如果未能解决你的问题,请参考以下文章

有没有比这段代码更优雅的方式将 XML 文档转换为 Java 中的字符串?

需要示例代码片段帮助

将 XSLT 转换的 XML 片段写入 XMLStreamWriter

如何删除 xml 文档中的独立属性声明?

java项目中的文档转换案例实战——Word转换为PDF

java项目中的文档转换案例实战——Word转换为PDF