Convert String XML fragment to Document Node in Java
In Java how can you convert a String that represents a fragment of XML for insertion into an XML document?
e.g.
String newNode = "<node>value</node>"; // Convert this to XML
Then insert this node into an org.w3c.dom.Document as the child of a given node?
Solution 1:
Element node = DocumentBuilderFactory
.newInstance()
.newDocumentBuilder()
.parse(new ByteArrayInputStream("<node>value</node>".getBytes()))
.getDocumentElement();
Solution 2:
You can use the document's import (or adopt) method to add XML fragments:
/**
* @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);
}
Solution 3:
For what it's worth, here's a solution I came up with using the dom4j library. (I did check that it works.)
Read the XML fragment into a org.dom4j.Document
(note: all the XML classes used below are from org.dom4j; see Appendix):
String newNode = "<node>value</node>"; // Convert this to XML
SAXReader reader = new SAXReader();
Document newNodeDocument = reader.read(new StringReader(newNode));
Then get the Document into which the new node is inserted, and the parent Element (to be) from it. (Your org.w3c.dom.Document would need to be converted to org.dom4j.Document here.) For testing purposes, I created one like this:
Document originalDoc =
new SAXReader().read(new StringReader("<root><given></given></root>"));
Element givenNode = originalDoc.getRootElement().element("given");
Adding the new child element is very simple:
givenNode.add(newNodeDocument.getRootElement());
Done. Outputting originalDoc
now yields:
<?xml version="1.0" encoding="utf-8"?>
<root>
<given>
<node>value</node>
</given>
</root>
Appendix: Because your question talks about org.w3c.dom.Document
, here's how to convert between that and 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);
(If you'd need both kind of Document
s regularly, it might make sense to put these in neat utility methods, maybe in a class called XMLUtils
or something like that.)
Maybe there are better ways to do this, even without any 3rd party libraries. But out of the solutions presented so far, in my view this is the easiest way, even if you need to do the dom4j <-> w3c conversions.
Update (2011): before adding dom4j dependency to your code, note that it is not an actively maintained project, and has some other problems too. Improved version 2.0 has been in the works for ages, but there's only an alpha version available. You may want to consider an alternative, like XOM, instead; read more in the question linked above.
Solution 4:
Here's yet another solution, using the XOM library, that competes with my dom4j answer. (This is part of my quest to find a good dom4j replacement where XOM was suggested as one option.)
First read the XML fragment into a nu.xom.Document
:
String newNode = "<node>value</node>"; // Convert this to XML
Document newNodeDocument = new Builder().build(newNode, "");
Then, get the Document and the Node under which the fragment is added. Again, for testing purposes I'll create the Document from a string:
Document originalDoc = new Builder().build("<root><given></given></root>", "");
Element givenNode = originalDoc.getRootElement().getFirstChildElement("given");
Now, adding the child node is simple, and similar as with dom4j (except that XOM doesn't let you add the original root element which already belongs to newNodeDocument
):
givenNode.appendChild(newNodeDocument.getRootElement().copy());
Outputting the document yields the correct result XML (and is remarkably easy with XOM: just print the string returned by originalDoc.toXML()
):
<?xml version="1.0"?>
<root><given><node>value</node></given></root>
(If you wanted to format the XML nicely (with indentations and linefeeds), use a Serializer
; thanks to Peter Štibraný for pointing this out.)
So, admittedly this isn't very different from the dom4j solution. :) However, XOM may be a little nicer to work with, because the API is better documented, and because of its design philosophy that there's one canonical way for doing each thing.
Appendix: Again, here's how to convert between org.w3c.dom.Document
and nu.xom.Document
. Use the helper methods in XOM's DOMConverter
class:
// 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