2010-02-18 17 views
35

Dada una instancia de org.w3c.dom.Document, ¿cómo puedo guardar su contenido en un archivo/corriente?escritura en Android

EDIT: Como señaló CommonsWare, no existe la posibilidad de utilizar clases de Android SDK anteriores a Android 2.2 (API 8). ¿Puede recomendar entonces una biblioteca de terceros para guardar los contenidos de Document en un archivo/secuencia?

+0

Escribir el documento XML en un archivo, al igual que en la tarjeta SD? –

+0

En realidad, no importa dónde. Serializar el DOM a una cadena es lo que quiero hacer. –

+1

Recomiendo http://jsoup.org, nunca es más fácil de manejar xml. Especialmente, evita el uso de 'NullPointerException'. –

Respuesta

39

Puede escribir XML como todos los demás archivos de texto. Para el análisis de documentos para la cadena utilicé:

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

Pero hay una forma más sencilla de hacer esto: 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

Gracias por esta respuesta. Sé que podría atravesar el documento yo solo, pero preferiría no hacerlo. El código que envió no se ve listo para la producción/fiable:/ –

+8

este código es ejemplo y no para la producción :) – Dmytro

+0

función getStringFromNode() funciona perfectamente para el contenido XML básico (no probado para XML complejo), muchas gracias. Eso ayuda mucho para las versiones de Android <2.2 cuando TransformerFactory no puede ser utilizado. –

20

Existe un marco muy ligero para leer y escribir XML desde Java anotada objetos. Es totalmente compatible con Android.

http://simple.sourceforge.net

+1

Probé este framework y es increíble en Android. Utiliza la reflexión, pero esto probablemente no será un problema para la mayoría de los casos. – Qberticus

+2

Utiliza la reflexión, sin embargo, la reflexión se realiza solo una vez para escanear el esquema XML en función de las clases anotadas. Toda la reflexión se almacena en caché para mejorar el rendimiento. Es mucho más rápido que los marcos similares como JAXB y XStream, y en muchos escenarios es incluso más rápido que la serialización Java XML nativa. –

+0

Aw impresionante, esto es lo que uso ahora. Lo uso en conjunto con ORMLite en realidad, y en conjunto tengo solo unas pocas clases, todas anotadas con estas dos librerías, y puedo deserializar desde XML y guardarlo en SQLite con solo unas pocas líneas de código. Bastante increíble :) – Adam

16

Desde el nivel API 8 se puede utilizar:

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

Mi aplicación apunta a nivel 4 de API –

7

realizo Isaac estaba buscando una solución usando API de nivel 4, pero para otros que pueden utilizar un nivel mínimo de 8, aquí está una buena solución basa fuera de lo Radek-K publicado:

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

Aquí hay una solución para la API de nivel 4. Se requiere una biblioteca externa, sin embargo, la biblioteca no es grande y hace que este sea mucho más fácil.

que utilizan XOM 1.2.6 y sus paquetes centrales única archivo jar.

código de actividad completo incluyendo las importaciones:

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

    } 
} 

No es terriblemente largo. Sería un poco más corto para API nivel 7+ ya que puede omitir todo el trabajo requerido para encontrar el elemento raíz. La aplicación resultante es 162k, así que no creo que XOM agregue mucho peso a un proyecto.

La magia está en DOMConverter.

Cuestiones relacionadas