Given an instance of org.w3c.dom.Document
, how do I save its contents to a file/stream?

- 18,333
- 31
- 67
- 74

- 4,075
- 6
- 49
- 50
-
Writing the xml document to a file, like on the sd card? – Patrick Kafka Feb 18 '10 at 18:08
-
Actually it doesn't matter where. Serializing the DOM to a string is what I want to do. – Marek Stój Feb 18 '10 at 19:25
-
1I recommend http://jsoup.org, it's never simpler for handling xml. Especially, it avoids of `NullPointerException` in using. – Feb 27 '12 at 05:42
5 Answers
You can write xml like all others text files. For parsing Document to string I used:
public static String getStringFromNode(Node root) throws IOException {
StringBuilder result = new StringBuilder();
if (root.getNodeType() == 3)
result.append(root.getNodeValue());
else {
if (root.getNodeType() != 9) {
StringBuffer attrs = new StringBuffer();
for (int k = 0; k < root.getAttributes().getLength(); ++k) {
attrs.append(" ").append(
root.getAttributes().item(k).getNodeName()).append(
"=\"").append(
root.getAttributes().item(k).getNodeValue())
.append("\" ");
}
result.append("<").append(root.getNodeName()).append(" ")
.append(attrs).append(">");
} else {
result.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
}
NodeList nodes = root.getChildNodes();
for (int i = 0, j = nodes.getLength(); i < j; i++) {
Node node = nodes.item(i);
result.append(getStringFromNode(node));
}
if (root.getNodeType() != 9) {
result.append("</").append(root.getNodeName()).append(">");
}
}
return result.toString();
}
But there is one more simple way to do this: http://www.ibm.com/developerworks/opensource/library/x-android/index.html#list11
private String writeXml(List<Message> messages){
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
try {
serializer.setOutput(writer);
serializer.startDocument("UTF-8", true);
serializer.startTag("", "messages");
serializer.attribute("", "number", String.valueOf(messages.size()));
for (Message msg: messages){
serializer.startTag("", "message");
serializer.attribute("", "date", msg.getDate());
serializer.startTag("", "title");
serializer.text(msg.getTitle());
serializer.endTag("", "title");
serializer.startTag("", "url");
serializer.text(msg.getLink().toExternalForm());
serializer.endTag("", "url");
serializer.startTag("", "body");
serializer.text(msg.getDescription());
serializer.endTag("", "body");
serializer.endTag("", "message");
}
serializer.endTag("", "messages");
serializer.endDocument();
return writer.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

- 2,200
- 3
- 20
- 32
-
2Thanks for this answer. I know I could traverse the Document by myself but I'd rather not do this. The code you posted doesn't look production-ready/reliable :/ – Marek Stój Feb 19 '10 at 13:28
-
getStringFromNode() function works perfectly for basic XML content (not tested for complex XML), thanks a lot. That helps a lot for Android versions < 2.2 when TransformerFactory cannot be used. – Benjamin Piette Sep 27 '12 at 12:17
There is a very lightweight framework for reading and writing XML from annotated Java objects. It is fully compatible with Android.

- 7,099
- 1
- 38
- 42
-
1I tried this framework and it's awesome on android. It does use reflection but this probably won't be an issue for the majority of cases. – Rich Schuler May 04 '10 at 17:50
-
2It does use reflection, however reflection is performed only once to scan the XML schema based on the annotated classes. All reflection is cached to improve performance. It musch faster than similar frameworks such as JAXB and XStream, and on many scenarios is even faster than native Java XML serialization. – ng. May 31 '10 at 14:14
-
Awesome lib, this is what I use now. I use it in conjunction with ORMLite actually, and together I have just a few classes, all annotated with these two libs, and I can deserialize from XML and save to SQLite with just a few lines of code. Pretty awesome :) – Adam Sep 02 '11 at 16:50
Since API level 8 you can use:
javax.xml.transform.TransformerFactory factory = new javax.xml.transform.TransformerFactory();
javax.xml.transform.Transformer transformer = factory.newTransformer();
javax.xml.transform.dom.DOMSource domSource = new javax.xml.transform.dom.DOMSource(rootNode);
javax.xml.transform.stream.StreamResult result = new javax.xml.transform.stream.StreamResult(outputStream);
transformer(domSource, result);

- 7,926
- 4
- 34
- 39
Here's a solution for API Level 4. It requires an external library, however, the library is not large and makes this a lot easier.
I used XOM 1.2.6 and its core packages only jar file.
Full activity code including imports:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import nu.xom.converters.DOMConverter;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
public class XOMTestActivity extends Activity {
private static final String TAG = "XOMTestActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
//Used XOM project.xml file for testing
InputStream rawStream = this.getResources().openRawResource(R.raw.project);
Document document = docBuilder.parse(rawStream);
//API Level 4 will not always return a valid Document for XOM
//So, find the root level element manually
NodeList nodeList = document.getChildNodes();
Node elementNode = null;
for(int i = 0 ; i < nodeList.getLength() ; i++) {
Node n = nodeList.item(i);
if(n instanceof Element) {
elementNode = n;
break;
}
}
//assuming there was a root level element
DocumentFragment docFragment = document.createDocumentFragment();
docFragment.appendChild(elementNode);
nu.xom.Nodes nodes = DOMConverter.convert(docFragment);
nu.xom.Document xomDoc = new nu.xom.Document((nu.xom.Element) nodes.get(0));
Log.d(TAG, "onCreate: " + xomDoc.toXML());
String outFile =
Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "wc3-xom-doc.xml";
Writer writer = new FileWriter(outFile);
writer.write(xomDoc.toXML());
writer.close();
} catch(DOMException de) {
Log.e(TAG, "onCreate: dom exception: " + de.code, de);
} catch(Exception e) {
Log.e(TAG, "onCreate: exception", e);
}
}
}
It's not terribly long. It would be quite a bit shorter for API level 7+ since you can skip all the work required to find the root element. Resulting apk is 162k so I don't feel XOM adds much weight to a project.
The magic is in DOMConverter
.

- 41,814
- 6
- 72
- 59
I realize Isaac was looking for a solution using API level 4, but for others who can use a minimum level 8, here is a nice solution based off of what radek-k posted:
StringOutputStream.java:
import java.io.OutputStream;
class StringOutputStream extends OutputStream
{
private StringBuilder m_string;
StringOutputStream()
{
m_string = new StringBuilder();
}
@Override
public void write(int b) throws IOException
{
m_string.append( (char) b );
}
@Override
public String toString()
{
return m_string.toString();
}
}
XMLHelper.java:
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
public class XMLhelper
{
private static String serializeDocument(Document doc)
{
String xml = null;
try
{
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
Properties outFormat = new Properties();
outFormat.setProperty( OutputKeys.INDENT, "yes" );
outFormat.setProperty( OutputKeys.METHOD, "xml" );
outFormat.setProperty( OutputKeys.OMIT_XML_DECLARATION, "no" );
outFormat.setProperty( OutputKeys.VERSION, "1.0" );
outFormat.setProperty( OutputKeys.ENCODING, "UTF-8" );
transformer.setOutputProperties( outFormat );
DOMSource domSource = new DOMSource( doc.getDocumentElement() );
OutputStream output = new StringOutputStream();
StreamResult result = new StreamResult( output );
transformer.transform( domSource, result );
xml = output.toString();
android.util.Log.i( "XMLHELPER", xml );
}
catch (TransformerConfigurationException e)
{
android.util.Log.d( "XMLHELPER", "Exception: " + e );
e.printStackTrace();
}
catch (TransformerException e)
{
android.util.Log.d( "XMLHELPER", "Exception: " + e );
e.printStackTrace();
}
return xml;
}
}

- 25,966
- 23
- 76
- 87