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


76

在Java中,如何转换表示XML片段的String插入XML文档中?

例如

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

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


Answers:


64
Element node =  DocumentBuilderFactory
    .newInstance()
    .newDocumentBuilder()
    .parse(new ByteArrayInputStream("<node>value</node>".getBytes()))
    .getDocumentElement();

3
;该.parse(新StringInputStream(....应阅读.parse(新ByteArrayInputStream的(新的String( “XML”).getBytes()))
斯蒂恩

5
我只是恨这些commentboxes和缺乏标记(或降价,对于这个问题)
斯蒂恩

4
但这不会复制子级...例如,如果您在“ <tag1> <tag2> <tag3> blah </ tag3> blah </ tag2> </ tag1>的情况下执行此操作,则只会获取<tag1>而不会它的孩子们
grobartn 2012年

1
这对我没有用,因为它没有像grobartn所说的那样复制孩子。@McDowell的解决方案确实有效。
Upgradingdave

33

您可以使用文档的import(或采用)方法添加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);
  }

5
嗯 如果这是最简单的解决方案,那么对于一个如此小的问题,我必须说它相当复杂。
Jonik

我已将其缩减到最低限度-不过,它仍然使用您在JRE API中获得的功能,因此不可避免地会有一些冗长的细节。
McDowell

3
那正是我想要的。我没有意识到在将片段附加到父节点之前必须将其导入dom!
Tony Eichelberger,2009年

如果您不想冗长,则不得使用Java,Luke。感谢您的回答,任何人都没有机会弄清楚这一点。
2012年

给定用户的要求,所选答案是正确的,此回答“更”正确。
13年

15

对于它的价值,这是我使用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,并从中获取父元素。(在这里,您的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经常需要这两种方法,可以将它们放在整洁的实用程序方法中,也许放在一个叫做的类之类的方法XMLUtils中。)

即使没有任何第三方库,也许还有更好的方法可以做到这一点。但是,在到目前为止提出的解决方案中,我认为这是最简单的方法,即使您需要进行dom4j <-> w3c转换。

更新(2011):在将dom4j依赖项添加到代码中之前,请注意,不是一个主动维护的项目,并且也存在一些其他问题。改进的2.0版本已经使用了很长时间,但是只有一个alpha版本可用。您可能需要考虑使用XOM之类的替代方法。阅读以上链接的问题中的更多内容。


如果dom4j不能使用,请尝试以下解决方案:stackoverflow.com/a/7607435/363573
Stephan

6

这是另一个使用XOM库的解决方案,它可以与我的dom4j answer竞争。(这是我寻求一个好的dom4j替代品的一部分,其中建议将XOM作为一种选择。)

首先将XML片段读取为nu.xom.Document

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

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

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(“ <root> <given> </ given> </ root>”))); 您还可以使用new Builder()。build(“ <root> <given> </ given> </ root>”,“ test.xml”); (其中“ test.xml”是一些随机基本URI)
PeterŠtibraný09年

1
“如果您想很好地格式化XML(使用缩进和换行符),我不确定如何使用XOM进行格式化。” -使用Serializer类。使用setIndent和setMaxLength对其进行配置,然后调用write(document)。
PeterŠtibraný09年

序列化器也很容易通过子类进行自定义。
PeterŠtibraný09年

谢谢!我真的不了解baseURI参数的确切含义。传递一个空字符串也可以,所以我正在使用它。无论如何,这确实简化了代码。对于格式化,Serializer确实可以正常工作。
约尼克,

我认为baseURI将用于解决对DTD或XInclude的相对引用(lists.ibiblio.org/pipermail/xom-interest/2004年
11

6
/**
*
* 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;
}

4

如果您使用的是dom4j,则可以执行以下操作:

文档document = DocumentHelper.parseText(text);

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


刚去他们的网站。他们将Google Ads置于典型的Maven生成的导航栏中!难以置信!
Thilo

2
显然,该站点不再由dom4j家伙运营,但是一些域名抢夺者接手了……
Thilo 2010年

1

...如果您使用的是纯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来做几乎相同的事情,因此,即使不是很优雅,它也应该是安全的。


1

尝试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]
Ikenna Anthony Okafor
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.