viernes, 25 de julio de 2008

Java y XML: DOM (II)

Este post complementa al post anterior exponiendo una serie de ejemplos de uso de DOM. Como no, este post pertenece a la serie de post dedicados a Java y XML.

Como ya comenté, utilizaremos las implementaciones DOM para Java JAXP (Java Api for XML Processing, desarrollada por Sun) y Xerces (desarrollada por Apache). La implementación JAXP viene con la librería básica de Java (vamos la que te descargas de la página oficial de Sun: SDK o JRE), tanto en la versión 1.4.2 como en las posteriores. Según he podido comprobar la implementación de DOM de Xerces también ha sido incluida en la librería básica de Java a partir de la versión 1.5.0. Por tanto si usas java 1.4.2 necesitarás incluir la librería de Xerces en tu aplicación. Por el contrario, con Java 1.5 o 1.6 no necesitarás librerías adicionales.

Vamos a partir del fichero XML siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<etiquetaPrincipal xmlns:xela="http://www.latascadexela.es" >
   <etiquetaHija id="1" atributo1="valorAtributo1" atributo2="valorAtributo2">
      Texto dentro de la etiqueta hija
   </etiquetaHija>
   <!-- Comentario -->
   <xela:etiquetaConNamespace descripcion="etiqueta con un namespace"/>   
</etiquetaPrincipal>

Parseando un XML

Vamos a ver como obtener el objeto Document del árbol de nodos partiendo de un fichero XML.

Con JAXP

// Construimos nuestro DocumentBuilder
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
// Procesamos el fichero XML y obtenemos nuestro objeto Document
Document doc = documentBuilder.parse(new InputSource(new FileInputStream("/ruta_a_fichero/fichero.xml")));

Con Xerces

// Creamos el parseador
DOMParser parser = new DOMParser();
// Procesamos el fichero XML
parser.parse(new InputSource(new FileInputStream("/ruta_a_fichero/fichero.xml")));
// Obtenemos el objeto Document
Document doc = parser.getDocument();

Recorriendo el árbol de nodos

Una vez tenemos el objeto Document podemos ir descendiendo por el árbol de nodos a partir de la etiqueta principal. Y así sucesivamente por los hijos de los nodos.

// Obtenemos la etiqueta raiz
Element elementRaiz = doc.getDocumentElement();
// Iteramos sobre sus hijos
NodeList hijos = elementRaiz.getChildNodes();
for(int i=0;i<hijos.getLength();i++){
   Node nodo = hijos.item(i);
   if (nodo instanceof Element){
      System.out.println(nodo.getNodeName());
   }
}

Como podéis ver no está de más asegurarse de que los nodos devueltos son Element.No todos los hijos de un Element lo serán. Puede evitar muchos errores el acostumbrase a ello, ya que son errores en tiempo de ejecución y el compilador no nos avisa de ellos.

Sin embargo, lo que nos interesa normalmente es obtener una serie de etiquetas a partir de su nombre. Es aquí donde podemos usar el método getElementsByTagName o getElementsByTagNameNS si buscamos etiquetas con espacios de nombres. Por cierto, getElementsByTagNameNS no me ha funcionado con JAXP, por lo que si usáis espacios de nombres os aconsejo Xerces.



// Buscamos una etiqueta dentro del XML
NodeList listaNodos = doc.getElementsByTagName("etiquetaHija");
for(int i=0;i<listaNodos.getLength();i++){
   Node nodo = listaNodos.item(i);
   if (nodo instanceof Element){
      System.out.println(nodo.getTextContent());
   }
}

// Buscamos una etiqueta dentro del XML con Namespaces
NodeList listaNodosNS = doc.getElementsByTagNameNS("http://www.latascadexela.es","etiquetaConNamespace");
for(int i=0;i<listaNodosNS.getLength();i++){
   Node nodo = listaNodosNS.item(i);
   if (nodo instanceof Element){
      System.out.println(nodo.getAttributes().getNamedItem("descripcion").getTextContent());
   }
}

Este método puede parecer la solución a todos tus problemas, pero ¿qué ocurre si tenemos etiquetas con el mismo nombre en distintas partes del XML? Por ejemplo, supongamos el XML siguente:

<?xml version="1.0" encoding="UTF-8"?>
<libros>
   <prestamo>
      <libro isbn="978-84-8346-520-2">
         <titulo>El Ocho</titulo>
         <autor>Katherine Neville</autor>
         <anyo>1988</anyo>
         <editorial>Ballantine Books</editorial>
      </libro>
      <libro isbn="84-226-6765-7">
         <titulo>Qumrán</titulo>
         <autor>Eliette Abécasis</autor>
         <anyo>1997</anyo>
         <editorial>Ediciones B</editorial>
      </libro>
   </prestamo>
   <venta>
      <libro isbn="84-675-069-X">
         <titulo>Memorias de Idhún I - La Resistencia</titulo>
         <autor>Laura Gallego García</autor>
         <anyo>2005</anyo>
         <editorial>Ediciones SM</editorial>
      </libro>
      <libro isbn="978-84-8346-808-1">
         <titulo>Next</titulo>
         <autor>Michael Crichton</autor>
         <anyo>2008</anyo>
         <editorial>DeBolsillo</editorial>
      </libro>
   </venta>
</libros>

Si buscamos las etiquetas que se llamen libro obtendremos tanto los libros en préstamo como los libros en venta. ¿Cómo diferenciamos cuáles son unos y cuáles otros? Evidentemente, preguntando por el padre getParentNode(). Pero hay una forma más sencilla, y es aquí cuando entra en escena nuestro amigo XPath.

Buscando con XPath

XPath(XML Path Language)
es un lenguaje que permite construir expresiones
que recorren y procesan un documento XML. La idea es parecida a las expresiones regulares pero aplicado a XML.

Básicamente se trata de describir una ruta a través del árbol de nodos como si cada etiqueta fuera un directorio. Por ejemplo, /etiquetaPrincipal/etiquetaHija. Esta ruta XPath seleccionaría la etiquetaHija de nuestro XML. Por supuesto, es mucho más complejo y pontente: hay funciones, caracteres comodín, condicionales,... Podría escribir mucho acerca de XPath pero creo lo mejor es que echéis un vistazo a la página de donde aprendí yo y de paso la guardéis en vuestros favoritos ya que es una buena web de referencia: Tutorial de XPath.

¿Cómo aplicamos XPath con DOM? Los siguientes ejemplos lo muestran:

Con JAXP

// Buscamos una etiqueta mediante XPath.
// Implementación de XPath por defecto en Java
Node etiquetaHija = (Node)(XPathFactory.newInstance().newXPath().evaluate("/etiquetaPrincipal/etiquetaHija", doc, XPathConstants.NODE));
if (etiquetaHija!=null){
   System.out.println(etiquetaHija.getTextContent());
}

Mediante el tercer parámetro del método evaluate, indicamos lo que esperamos recibir. Puede ser: booleano, lista de nodos, un nodo, un número o una cadena.

Si vamos a evaluar una misma expresión XPath sobre distintos Document es más eficiente compilar la expresión XPath y a partir del objeto XPathExpresion evaluar sobre los distintos Document:

XPathExpression xpathCompilada = XPathFactory.newInstance().newXPath().compile("/etiquetaPrincipal/etiquetaHija");
Node etiqueta1 = (Node)xpathCompilada.evaluate(doc1, XPathConstants.NODE);
Node etiqueta2 = (Node)xpathCompilada.evaluate(doc2, XPathConstants.NODE);
[..]
Node etiquetaN = (Node)xpathCompilada.evaluate(docN, XPathConstants.NODE);

Con Xerces

// Buscamos una etiqueta mediante XPath.
// Implementación de XPath de Xerces
Node etiquetaHija = XPathAPI.selectSingleNode(doc, "/etiquetaPrincipal/etiquetaHija");
if (etiquetaHija!=null){
   System.out.println(etiquetaHija.getTextContent());
}

Existen métodos distintos para obtener una lista de nodos o un único nodo. En este caso hemos usado el de seleccionar un único nodo.

Como podemos observar, el problema del XML de los libros se resuelve fácilmente con XPath. Podemos sacar la lista de libros en préstamo /libros/prestamo/libro y la lista de libros en venta /libros/venta/libro.

Modificando el XML

Como decía, con DOM también se puede modificar el XML. Esto se hace modificando el árbol de nodos. Por ejemplo, veamos cómo añadir una etiqueta nueva. Lo primero que hay que hacer es crearla usando el Document donde la vamos a insertar y después la añadimos como hija a otra etiqueta.

// Añadimos una nueva etiqueta al documento
// Primero creamos la etiqueta (element)
Element nuevaEtiqueta = doc.createElement("nuevaEtiqueta");
// Añadimos atributos
nuevaEtiqueta.setAttribute("atributoNuevo", "Es un nuevo atributo");
// Añadimos contenido
nuevaEtiqueta.setTextContent("Contenido dentro de la nueva etiqueta");
// después se la añadimos como hija a una etiqueta ya existente
etiquetaHija.appendChild(nuevaEtiqueta);

Creando XML desde cero

Con DOM también podemos crear un documento XML nuevo. Este sería el paso inverso al parseo, es decir, mapeo de objetos a XML. Para ello usamos el DocumentBuilder de JAXP.

// Vamos a crear un XML desde cero
// En este caso usamos DocumentBuilder
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
// Creamos el documento XML
Document docNuevo = docBuilder.newDocument();

Copiando nodos de un Document a otro

También podemos copiar o mover elementos de un Document a otro. Como decía en el post anterior, para que un nodo pueda ser añadido al árbol de nodos de un Document concreto ha de pertenecer al ámbito de dicho Document. Por ello lo primero es obtener una instancia del element que queremos copiar bajo el ámbito del Document sobre el que lo queremos pegar. Esto se hace mediante el método import, si queremos copiar, o mediante el método adopt, si lo que queremos es mover. Es decir, adopt elimina el elemento del Document anterior. Una vez hecho esto ya lo situamos donde deseemos.

// Incluso podemos copiar parte de otro documeto XML en este nuevo
// Vamos a copiar todo el XML parseado en este nuevo
// Primero obtenemos la etiqueta Raiz del XML parseado al principio
Element etiquetaRaizACopiar = doc.getDocumentElement();
// Luego la copiamos bajo nuestra etiqueta hijaRaiz, por ejemplo
Node etiquetaRaizCopiada = docNuevo.importNode(etiquetaRaizACopiar, true); // El segundo atributo indica si queremos copiar los hijos
// Ya tenemos una copia de la etiqueta en nuestro document. Ahora la situamos bajo etiquetaHija
hijaRaiz.appendChild(etiquetaRaizCopiada);

// ImportNode hace una copia, dejando el xml original intacto
// AdoptNode mueve, es decir, elimina los elementos del arbol original y los pega en el nuevo-
// Este método siempre es recursivo.
// Por ejemplo, adoptemos la etiquetaHija.
Node etiquetaHijaAdoptada = docNuevo.adoptNode(etiquetaHija);
// Ya tenemos la etiquetaHija en nuestro document y se ha eliminado del anterior.
// La situamos bajo la etiqueta raiz
raiz.appendChild(etiquetaHijaAdoptada);

Una vez ejecutado el ejemplo y si obtenemos la representación en formato de String de los dos Document veríamos lo siguiente:

XML parseado:
<?xml version="1.0" encoding="UTF-8"?>
<etiquetaPrincipal xmlns:xela="http://www.latascadexela.es">
   <!-- Comentario -->
   <xela:etiquetaConNamespace descripcion="etiqueta con un namespace"/>
</etiquetaPrincipal>

XML nuevo:
<?xml version="1.0" encoding="UTF-8"?>
<etiquetaRaiz>
   <etiquetaHijaRaiz>
      <etiquetaPrincipal xmlns:xela="http://www.latascadexela.es">
         <etiquetaHija atributo1="valorAtributo1" atributo2="valorAtributo2" id="1">
Texto dentro de la etiqueta hija
<nuevaEtiqueta atributoNuevo="Es un nuevo atributo">Contenido dentro de la nueva etiqueta</nuevaEtiqueta>
         </etiquetaHija>
         <!-- Comentario -->
         <xela:etiquetaConNamespace descripcion="etiqueta con un namespace"/>
      </etiquetaPrincipal>
   </etiquetaHijaRaiz>
   <etiquetaHija atributo1="valorAtributo1" atributo2="valorAtributo2" id="1">
Texto dentro de la etiqueta hija
<nuevaEtiqueta atributoNuevo="Es un nuevo atributo">Contenido dentro de la nueva etiqueta</nuevaEtiqueta>
   </etiquetaHija>
</etiquetaRaiz>

Como podemos observar, la etiquetaHija fue adoptada por el nuevo Documento y por tanto eliminada del original. Esto no ocurre con el resto de etiquetas ya que tan sólo fueron importadas.

Serializando el XML

Lo primero que hicimos fue pasar un fichero XML a un árbol DOM. A partir de ahí hemos aprendido a modificar el árbol, incluso a crear nuevos documentos XML. Ahora vamos a ver como volver a convertir dicho árbol en un fichero XML. Digo fichero XML pero podría ser un String o un array de bytes. En general, cualquier cosa que pueda ser serializable mediante un Writer o un OutputStream.

// Vamos a convertir el arbol DOM en un String
// Definimos el formato de salida: encoding, identación, separador de línea,...
// Pasamos doc como argumento para tener un formato de partida
OutputFormat format = new OutputFormat(doc);
format.setLineSeparator(LineSeparator.Unix);
format.setIndenting(true);
format.setLineWidth(0);
format.setPreserveSpace(false);
// Definimos donde vamos a escribir. Puede ser cualquier OutputStream o un Writer
CharArrayWriter salidaXML = new CharArrayWriter();
// Serializamos el arbol DOM
XMLSerializer serializer = new XMLSerializer((Writer)salidaXML,format);
serializer.asDOMSerializer();
serializer.serialize(doc);
// Ya tenemos el XML serializado en el objeto salidaXML
System.out.println(salidaXML.toString());

Vemos como hemos hecho uso del OutputFormat para controlar el formato de salida. Podemos controlar si queremos que salga la declaración de xml (<?xml version ....), el encoding, la identación, si queremos un salto de línea tras cada etiqueta,....

Con esto hemos visto lo más importante de DOM según mi punto de vista. A continuación dejo el código completo tanto de la clase de ejemplo de uso de Xerces como la de JAXP.

ProcesaXMLJAXP.java

package es.latascadexela.xml.dom;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
* Clase de ejemplo de procesado de XML mediante DOM.
* Usa la implementación por defecto de Java (JAXP)
*
* @author Xela
*
*/
public class ProcesaXMLJAXP {

   public static void main(String[] args) {
      
      try {
            
         // Implementación DOM por defecto de Java
         // Construimos nuestro DocumentBuilder
         DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
         // Procesamos el fichero XML y obtenemos nuestro objeto Document
         Document doc = documentBuilder.parse(new InputSource(new FileInputStream("/ruta_a_fichero/fichero.xml")));
         
         // Obtenemos la etiqueta raiz
         Element elementRaiz = doc.getDocumentElement();
         // Iteramos sobre sus hijos
         NodeList hijos = elementRaiz.getChildNodes();
         for(int i=0;i<hijos.getLength();i++){
            Node nodo = hijos.item(i);
            if (nodo instanceof Element){
               System.out.println(nodo.getNodeName());
            }
         }
         
         // Buscamos una etiqueta dentro del XML
         NodeList listaNodos = doc.getElementsByTagName("etiquetaHija");
         for(int i=0;i<listaNodos.getLength();i++){
            Node nodo = listaNodos.item(i);
            if (nodo instanceof Element){
               System.out.println(nodo.getTextContent());
            }
         }
         
         // Buscamos una etiqueta dentro del XML con Namespaces
         NodeList listaNodosNS = doc.getElementsByTagNameNS("http://www.latascadexela.es","etiquetaConNamespace");
         for(int i=0;i<listaNodosNS.getLength();i++){
            Node nodo = listaNodosNS.item(i);
            if (nodo instanceof Element){
               System.out.println(nodo.getAttributes().getNamedItem("descripcion").getTextContent());
            }
         }
         
         // Buscamos una etiqueta mediante XPath.
         // Implementación de XPath por defecto en Java
         Node etiquetaHija = (Node)(XPathFactory.newInstance().newXPath().evaluate("/etiquetaPrincipal/etiquetaHija", doc, XPathConstants.NODE));
         if (etiquetaHija!=null){
            System.out.println(etiquetaHija.getTextContent());
         }
         
         // Añadimos una nueva etiqueta al documento
         // Primero creamos la etiqueta (element)
         Element nuevaEtiqueta = doc.createElement("nuevaEtiqueta");
         // después se la añadimos como hija a una etiqueta ya existente
         etiquetaHija.appendChild(nuevaEtiqueta);
         
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      } catch (SAXException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      } catch (XPathExpressionException e) {
         e.printStackTrace();
      } catch (ParserConfigurationException e) {
         e.printStackTrace();
      }
      
   }

}

ProcesaXMLXerces.java

package es.latascadexela.xml.dom;

import java.io.CharArrayWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Writer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.sun.org.apache.xerces.internal.parsers.DOMParser;
import com.sun.org.apache.xml.internal.serialize.LineSeparator;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import com.sun.org.apache.xpath.internal.XPathAPI;

/**
* Clase de ejemplo de procesado de XML mediante DOM.
* Usa la implementación de Xerces
*
* @author Xela
*
*/
public class ProcesaXMLXerces {

   public static void main(String[] args) {
      
      try {
         
         // Implementación DOM de Xerces
         // Creamos el parseador
         DOMParser parser = new DOMParser();
         // Procesamos el fichero XML
         parser.parse(new InputSource(new FileInputStream("/ruta_a_fichero/fichero.xml")));
         // Obtenemos el objeto Document
         Document doc = parser.getDocument();

         // Obtenemos la etiqueta raiz
         Element elementRaiz = doc.getDocumentElement();
         // Iteramos sobre sus hijos
         NodeList hijos = elementRaiz.getChildNodes();
         for(int i=0;i<hijos.getLength();i++){
            Node nodo = hijos.item(i);
            if (nodo instanceof Element){
               System.out.println(nodo.getNodeName());
            }
         }
         
         // Buscamos una etiqueta dentro del XML
         NodeList listaNodos = doc.getElementsByTagName("etiquetaHija");
         for(int i=0;i<listaNodos.getLength();i++){
            Node nodo = listaNodos.item(i);
            if (nodo instanceof Element){
               System.out.println(nodo.getTextContent());
            }
         }
         
         // Buscamos una etiqueta dentro del XML con Namespaces
         NodeList listaNodosNS = doc.getElementsByTagNameNS("http://www.latascadexela.es","etiquetaConNamespace");
         for(int i=0;i<listaNodosNS.getLength();i++){
            Node nodo = listaNodosNS.item(i);
            if (nodo instanceof Element){
               System.out.println(nodo.getAttributes().getNamedItem("descripcion").getTextContent());
            }
         }
         
         // Buscamos una etiqueta mediante XPath.
         // Implementación de XPath de Xerces
         Node etiquetaHija = XPathAPI.selectSingleNode(doc, "/etiquetaPrincipal/etiquetaHija");
         if (etiquetaHija!=null){
            System.out.println(etiquetaHija.getTextContent());
         }
         
         // Añadimos una nueva etiqueta al documento
         // Primero creamos la etiqueta (element)
         Element nuevaEtiqueta = doc.createElement("nuevaEtiqueta");
         // Añadimos atributos
         nuevaEtiqueta.setAttribute("atributoNuevo", "Es un nuevo atributo");
         // Añadimos contenido
         nuevaEtiqueta.setTextContent("Contenido dentro de la nueva etiqueta");
         // después se la añadimos como hija a una etiqueta ya existente
         etiquetaHija.appendChild(nuevaEtiqueta);
         
         // Vamos a convertir el arbol DOM en un String
         // Definimos el formato de salida: encoding, identación, separador de línea,...
         // Pasamos doc como argumento para tener un formato de partida
         OutputFormat format = new OutputFormat(doc);
         format.setLineSeparator(LineSeparator.Unix);
         format.setIndenting(true);
         format.setLineWidth(0);
         format.setPreserveSpace(false);
         // Definimos donde vamos a escribir. Puede ser cualquier OutputStream o un Writer
         CharArrayWriter salidaXML = new CharArrayWriter();
         // Serializamos el arbol DOM
         XMLSerializer serializer = new XMLSerializer((Writer)salidaXML,format);
         serializer.asDOMSerializer();
         serializer.serialize(doc);
         // Ya tenemos el XML serializado en el objeto salidaXML
         System.out.println(salidaXML.toString());
         

         // Vamos a crear un XML desde cero
         // En este caso usamos DocumentBuilder
         DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
         // Creamos el documento XML
         Document docNuevo = docBuilder.newDocument();
         // Creamos la etiqueta raiz
         Element raiz = docNuevo.createElement("etiquetaRaiz");
         docNuevo.appendChild(raiz);
         // Creamos una etiqueta hija de la etiqueta raiz
         Element hijaRaiz = docNuevo.createElement("etiquetaHijaRaiz");
         raiz.appendChild(hijaRaiz);

         // Incluso podemos copiar parte de otro documeto XML en este nuevo
         // Vamos a copiar todo el XML parseado en este nuevo
         // Primero obtenemos la etiqueta Raiz del XML parseado al principio
         Element etiquetaRaizACopiar = doc.getDocumentElement();
         // Luego la copiamos bajo nuestra etiqueta hijaRaiz, por ejemplo
         Node etiquetaRaizCopiada = docNuevo.importNode(etiquetaRaizACopiar, true); // El segundo atributo indica si queremos copiar los hijos
         // Ya tenemos una copia de la etiqueta en nuestro document. Ahora la situamos bajo etiquetaHija
         hijaRaiz.appendChild(etiquetaRaizCopiada);
         
         // ImportNode hace una copia, dejando el xml original intacto
         // AdoptNode mueve, es decir, elimina los elementos del arbol original y los pega en el nuevo-
         // Este método siempre es recursivo.
         // Por ejemplo, adoptemos la etiquetaHija.
         Node etiquetaHijaAdoptada = docNuevo.adoptNode(etiquetaHija);
         // Ya tenemos la etiquetaHija en nuestro document y se ha eliminado del anterior.
         // La situamos bajo la etiqueta raiz
         raiz.appendChild(etiquetaHijaAdoptada);
         
         // Veamos los dos XML el nuevo y cómo ha quedado el parseado.
         // Definimos donde vamos a escribir. Puede ser cualquier OutputStream o un Writer
         CharArrayWriter salidaXMLParseado = new CharArrayWriter();
         // Serializamos el arbol DOM
         XMLSerializer serializerXMLParseado = new XMLSerializer((Writer)salidaXMLParseado,format);
         serializerXMLParseado.asDOMSerializer();
         serializerXMLParseado.serialize(doc);
         // Ya tenemos el XML serializado en el objeto salidaXMLParseado
         System.out.println("XML parseado: \n"+salidaXMLParseado.toString());
         
         // Definimos donde vamos a escribir. Puede ser cualquier OutputStream o un Writer
         CharArrayWriter salidaXMLNuevo = new CharArrayWriter();
         // Serializamos el arbol DOM
         XMLSerializer serializerXMLNuevo = new XMLSerializer((Writer)salidaXMLNuevo,format);
         serializerXMLNuevo.asDOMSerializer();
         serializerXMLNuevo.serialize(docNuevo);
         // Ya tenemos el XML serializado en el objeto salidaXMLNuevo
         System.out.println("XML nuevo: \n"+salidaXMLNuevo.toString());         
         
         
      } catch (FileNotFoundException e) {
         e.printStackTrace();
      } catch (SAXException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      } catch (TransformerException e) {
         e.printStackTrace();
      } catch (ParserConfigurationException e) {
         e.printStackTrace();
      }
      
   }

}


Espero que este post tan largo sea de utilidad.

5 comentarios:

Danyel Darkcloud dijo...

Voy a revisar eso del XPath.. la verdad no lo conocia... ahi si sabes como hacer esto pero en J2ME me avisas... muy buena info gracias

Xela dijo...

Muchas gracias Danyel. Para J2ME he oido hablar de NanoXML, kXML y TinyXML. He visto que hay una API llamada minixpath que permite hacer búsquedas XPath sobre documentos XML en J2ME. Usa kXML como parseador.

Debes tener en cuenta que para hacer búsquedas XPath es necesario usar DOM en lugar de SAX. Si has leído mis otros post sobre XML, habrás podido ver que el único caso en que recomiendo usar SAX en lugar de DOM es cuando el rendimiento es crítico. Esto se debe a que SAX parsea el fichero XML a trozos por lo que no necesita tenerlo al completo en memoria, mientras que DOM genera un árbol representativo del documento XML en memoria.

En el caso de aplicaciones J2ME tanto el rendimiento como el consumo de memoria es muy crítico, por lo que no sé si será muy adecuado usar DOM y XPath. De cara al desarrollador las ventajas son muchas, pero quizás en tu caso prime el rendimiento, no? Supongo que dependerá también del dispositivo sobre el que quieras ejecutar tu aplicación. Todo es ponerse probar.

Ya nos cuentas.

vaickiballs dijo...

Muchas gracias!!! estaba al borde del suicidio!

Jesus dijo...

Hola blogeros
Me gustaría retocar una aplicación que contiene ficheros XML y de pronto he visto que estos contienen unas etiquetas algo extrañas...buscando por ahí he descubierto que son processing instructions... En concreto empiezan asi <?xm-insertion_mark_start
Me gustaría eliminar dichas etiquetas (pero no su contenido) ya que estas estan dentro de otras y así tras elimianrlas que me resulte más fácil trabajar luego con el XML y el XSL.
¿Como se podrían eliminar estas etiquetas con DOM? ¿O es mejor con SAX? Si existe algun ejemplo de como hacerlo y me decis donde puedo verlo os lo agradezco ya que me estoy iniciando en esto solo para retocar dicha aplicación.
Saludos cordiales como decía aquel.

mafalda dijo...

Hola!
Muchas gracias por el post :) muy útil y muy bien explicado.
A pesar de esto al poner en práctica el parseo con DOM me he encontrado con un problema, a ver si me puedes ayudar.
El problema surge al leer el nombre de los nodos: getNodeName(), en lugar de devolverme el nombre del nodo me devuelve #text, y cuando pongo node instanceof Element me detecta que no es un nodo de tipo elemento. Creo que tiene que ver cuando el contenido del nodo es de tipo texto, porque cuando està vacío no me pasa... sabes como puedo detectar correctamente el nombre de los nodos?? que produce que se ponga el valor de #text??
Muchas gracias!!!