将字符串 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())); 我只是讨厌这些评论框以及它们缺乏标记(或降价,就此而言) 但这不会复制孩子们......例如,如果你在“您可以使用文档的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);
(如果您经常需要这两种Document
s,将它们放在简洁的实用方法中可能是有意义的,可能放在名为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.Document
和nu.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("/**
*
* 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 中的字符串?