在 Android 上编写 XML
Posted
技术标签:
【中文标题】在 Android 上编写 XML【英文标题】:Writing XML on Android 【发布时间】:2011-01-18 10:57:07 【问题描述】:给定org.w3c.dom.Document
的实例,如何将其内容保存到文件/流中?
【问题讨论】:
将 xml 文档写入文件,比如 sd 卡上? 其实在哪里都无所谓。将 DOM 序列化为字符串是我想要做的。 我推荐jsoup.org,处理 xml 从未如此简单。特别是在使用中避免NullPointerException
。
【参考方案1】:
您可以像所有其他文本文件一样编写 xml。 为了将 Document 解析为我使用的字符串:
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();
但还有一种更简单的方法可以做到这一点: 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);
【讨论】:
感谢您的回答。我知道我可以自己遍历文档,但我不想这样做。您发布的代码看起来不适合生产/可靠:/ getStringFromNode() 函数非常适用于基本的 XML 内容(未针对复杂的 XML 进行测试),非常感谢。这对于不能使用 TransformerFactory 的 Android 版本 【参考方案2】:有一个非常轻量级的框架用于从带注释的 Java 对象中读取和写入 XML。它与Android完全兼容。
http://simple.sourceforge.net
【讨论】:
我试过这个框架,它在安卓上很棒。它确实使用了反射,但在大多数情况下这可能不是问题。 它确实使用了反射,但是反射只执行一次以根据带注释的类扫描 XML 模式。所有反射都被缓存以提高性能。它比 JAXB 和 XStream 等类似框架更快,并且在许多情况下甚至比原生 Java XML 序列化更快。 很棒的库,这就是我现在使用的。实际上,我将它与 ORMLite 结合使用,并且我只有几个类,所有这些类都使用这两个库进行注释,并且我可以用几行代码从 XML 反序列化并保存到 SQLite。太棒了:)【参考方案3】:从 API 级别 8 开始,您可以使用:
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);
【讨论】:
【参考方案4】:我知道 Isaac 正在寻找使用 API 级别 4 的解决方案,但对于可以使用最低级别 8 的其他人,这里有一个基于 radek-k 发布的不错的解决方案:
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;
【讨论】:
【参考方案5】:这里有一个 API 级别 4 的解决方案。它需要一个外部库,但是,该库并不大,并且使这变得容易得多。
我使用了XOM 1.2.6,它的核心包只有jar文件。
包括导入在内的完整活动代码:
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);
这不是很长。对于 API 级别 7+,它会更短一些,因为您可以跳过查找根元素所需的所有工作。生成的 apk 为 162k,所以我觉得 XOM 不会给项目增加太多重量。
魔法就在DOMConverter
。
【讨论】:
以上是关于在 Android 上编写 XML的主要内容,如果未能解决你的问题,请参考以下文章
无法在 Android 上编写 jarlist 缓存文件 Facebook SDK