在 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

在 Android 设备上开发 C#/.NET

将参数传递给 strings.xml ANDROID 中的字体大小

如何在 CBPeripheral 设备上编写命令?

如何在 Android TV 上编译驱动程序?

ffmpeg neon 在 android 上编译 - 汇编错误