2010-02-18 4 views
35

org.w3c.dom.Document örneği verildiğinde, içeriğini bir dosya/akışa nasıl kaydederim?Android'de XML Yazma

DÜZENLEME: CommonsWare'in belirttiği gibi, Android SDK'sından Android 2.2'den önceki sınıflar kullanıldığında böyle bir olasılık yoktur (API 8). Daha sonra bir dosya/akışa Document içeriğini kaydetmek için üçüncü taraf kitaplığı önerebilir misiniz?

+0

xml belgesini sd kartında olduğu gibi bir dosyaya yazmak mı istiyorsunuz? –

+0

Aslında nerede olduğu önemli değil. DOM'yi bir diziye dizgelemek yapmak istediğim şey. –

+1

http://jsoup.org'u öneririm, xml işlemek için asla daha kolay değildir. Özellikle, kullanımda 'NullPointerException' önler. –

cevap

39

Diğer tüm metin dosyaları gibi xml yazabilirsiniz.

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(); 
    } 

Ama bunu yapmanın bir daha basit bir yolu vardır: dizeye Belgesi ayrıştırma için kullandım açıklamalı Java bir okuma için çok hafif çerçeve ve yazma XML yoktur 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

Bu cevap için teşekkürler. Belgesini tek başıma geçebileceğimi biliyorum ama bunu yapmamayı tercih ediyorum. Gönderdiğiniz kod, üretime hazır/güvenilir görünmüyor:/ –

+8

bu kod örnekte ve üretim için değil :) – Dmytro

+0

getStringFromNode() işlevi, temel XML içeriği için mükemmel bir şekilde çalışıyor (karmaşık XML için test edilmiyor), çok teşekkürler. Bu, TransformerFactory kullanılamayacağı zaman Android sürümleri <2.2'ye çok yardımcı oluyor. –

20

nesneler. Android ile tamamen uyumludur.

http://simple.sourceforge.net

+1

Bu çerçeveyi denedim ve Android'de harika. Yansıma kullanıyor ama bu büyük olasılıkla vakaların çoğunluğu için bir sorun olmayacak. – Qberticus

+2

Yansıma kullanır, ancak yansıma, açıklamalı sınıflara dayalı XML şemasını taramak için yalnızca bir kez gerçekleştirilir. Tüm yansıma performansı artırmak için önbelleğe alınır. JAXB ve XStream gibi benzer çerçevelerden daha hızlıdır ve birçok senaryoda yerel Java XML serileştirmesinden bile daha hızlıdır. –

+0

Awesome lib, şu an kullandığım şey bu. Ben aslında ORMLite ile birlikte kullanıyorum ve birlikte sadece birkaç tane sınıf var, hepsi bu iki lib ile açıklamalı, ve ben XML'den serileştirip SQLite'e sadece birkaç satır koduyla kaydedebiliyorum. Oldukça harika :) – Adam

16

API düzeyinde 8 yana kullanabilirsiniz:

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

Uygulama hedeflerim API düzey 4 –

7

Isaac API düzeyi 4 kullanarak bir çözüm arıyordu farkındayım ama diğerleri için minimum düzeyde 8 kullanabilecek kişileri, burada güzel bir çözüm nedir dışına göre Radek-k yayınlanmıştır:

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

İşte Harici kütüphane, ancak, kütüphane büyük değil gerektirir ve bu çok daha kolay hale getirir API seviyesi 4. yönelik bir çözümdür.

XOM 1.2.6 ve çekirdek paketlerini yalnızca jar dosyası kullanıyorum. ithalat dahil

Tam aktivite kodu:

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

    } 
} 

O korkunç uzun değil. Kök öğeyi bulmak için gereken tüm işleri atlayabileceğiniz için API seviyesi 7+ için biraz daha kısa olacaktır. Sonuç yaratan apk 162d, bu yüzden XOM'un bir projeye çok fazla ağırlık kattığını hissetmiyorum.

Sihir, DOMConverter'dadır.