2010-02-18 41 views
35

給定org.w3c.dom.Document的實例,如何將其內容保存到文件/流?在Android上書寫XML

編輯: 正如CommonsWare指出的那樣,在Android 2.2之前(API 8)使用Android SDK的類沒有這種可能性。你可以推薦一個第三方庫來保存Document內容到文件/流?

+0

將xml文檔寫入文件,就像在SD卡上一樣? – 2010-02-18 18:08:04

+0

其實哪裏都沒關係。序列化DOM到一個字符串是我想要做的。 – 2010-02-18 19:25:25

+1

我推薦http://jsoup.org,這對於處理xml來說絕不簡單。特別是,它避免了使用中的'NullPointerException'。 – 2012-02-27 05:42:22

回答

39

您可以像所有其他文本文件一樣編寫xml。 爲了解析文檔字符串我用:

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); 
    } 
} 
+2

感謝您的回答。我知道我可以自己遍歷文檔,但我寧願不要這樣做。您發佈的代碼看起來沒有生產就緒/可靠:/ – 2010-02-19 13:28:12

+8

此代碼僅爲示例,不適用於生產:) – Dmytro 2010-02-19 14:59:39

+0

getStringFromNode()函數完美適用於基本XML內容(未針對複雜XML進行測試),非常感謝。當TransformerFactory無法使用時,這對Android版本有很大的幫助。 – 2012-09-27 12:17:28

20

有從帶註釋的Java讀取一個非常輕量級的框架和編寫XML對象。它完全兼容Android。

http://simple.sourceforge.net

+1

我試過這個框架,它在android上很棒。它確實使用了反思,但這可能不會成爲大多數情況下的問題。 – Qberticus 2010-05-04 17:50:56

+2

它確實使用了反射,但是僅基於註釋的類來執行一次掃描XML模式的反射。所有反射都緩存以提高性能。它比類似JAXB和XStream的框架速度更快,在許多情況下甚至比原生Java XML序列化還要快。 – 2010-05-31 14:14:33

+0

真棒lib,這是我現在使用的。實際上,我將它與ORMLite結合使用,並且我只用了幾個類,所有這些都用這兩個庫進行了註釋,並且我可以從XML中反序列化並使用幾行代碼保存到SQLite。太棒了:) – Adam 2011-09-02 16:50:45

16

由於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); 
+0

我的應用程序定位API 4級 – 2010-08-23 22:05:10

7

我知道艾薩克使用API​​級別4尋找解決的辦法,但對於其他人誰可以使用最小的8級,這裏是基於關閉的有什麼很好的解決方案拉狄克-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; 
    } 
} 
10

下面是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增加了一個項目的重量。

神奇的是在​​。