XStream: Leer ficheros XML desde Java


Hace unos días me surgió la necesidad de leer y escribir ficheros XML desde Java. Los ficheros que debía leer y escribir eran colecciones de beans, lo comente con mis compañeros y tras ver varias opciones me decante por utilizar XStream.

Las dos razones por la cuales me decante por utilizar esta librería son las siguientes:

  • Los ficheros XML que tenia que escribir para posteriormente leer, no debían seguir ninguna DTD o esquema.

  • Lo sencilla que es la librería XStream de aprender y utilizar.

 Os podría seguir contando lo maravillosa que es la librería XStream, pero para eso ya esta su web. Solo comentaros algunas características:

  • Fácil de usar.

  • No requiere modificaciones en los objetos Java que se van a serializar.

  • Integración sencilla con otros APIs para XML

  • Soporte para Anotaciones (definición de alias para los atributos de una clase, conversores, omisión de tags,  etc).

 Veamos un ejemplo sencillo, vamos a suponer que el cliente nos a impuesto el siguiente modelo XML para persistir un Blog:

<blog>

<autor>

<nombre>Héctor Fuente</nombre>

</autor>

<entrada>

<titulo>XStream: Leer ficheros desde Java en 3 Lineas(I)</titulo>

<descripcion>XStream: Leer ficheros desde Java en 3 Lineas(I)</descripcion>

</entrada>

<entrada>

<titulo>XStream: Leer ficheros desde Java en 3 Lineas(II)</titulo>

<descripcion>XStream: Leer ficheros desde Java en 3 Lineas(II)</descripcion>

</entrada>

<entrada>

<titulo>XStream: Leer ficheros desde Java en 3 Lineas(III)</titulo>

<descripcion>XStream: Leer ficheros desde Java en 3 Lineas(III)</descripcion>

</entrada>

</blog>

 

A partir de este modelo XML vamos a crear nuestro modelo de datos en Java, compuesto por 3 clases Blog, Autor y Entrada:

 

package es.fuenteperez.xstream.modelo;

 

public class Entrada {

 

private String titulo, descripcion;

 

public Entrada(){

 

}

 

public Entrada(String titulo,

String descripcion) {

this.titulo = titulo;

this.descripcion = descripcion;

}

 

package es.fuenteperez.xstream.modelo;

 

public class Autor {

 

private String nombre;

 

public Autor(){

 

}

 

public Autor(String nombre) {

this.nombre = nombre;

}

 

public String getNombre() {

return nombre;

}

 

public void setNombre(String nombre) {

this.nombre = nombre;

}

}

 

 

package es.fuenteperez.xstream.modelo;

 

import java.util.ArrayList;

import java.util.List;

 

public class Blog {

 

private Autor autor;

private List<Entrada> entradas =

new ArrayList<Entrada>();

 

public Blog(){

 

}

 

public Autor getAutor() {

return autor;

}

 

public void setAutor(Autor autor) {

this.autor = autor;

}

 

public void add(Entrada entrada) {

entradas.add(entrada);

}

 

public List<Entrada> getEntradas() {

return entradas;

}

}

 

Las clases anteriores son simples bean, no hay que añadir absolutamente nada para poder utilizarlos con XStream, aunque puedas ver en todas el construcción por defecto no es necesario.

Ahora vamos ver como leer y escribir con XStream. Para escribir un fichero simplemente tenemos que utilizar el método toXML(Object o, OutputStream stream);

Como se puede ver es muy sencillo, le pasamos un Object y es capaz de generar de forma ‘mágica’ un XML, la magia se llama Reflection. XStream utiliza el Reflection API para conseguir la serialización con los objetos Java sin necesidad de ficheros de mapeo (DTD o esquemas).

En el siguiente fragmento de código podemos alguna opción más, que esta comentada a nivel de código.

package es.fuenteperez.xstream.main;

 

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import com.thoughtworks.xstream.XStream;

import es.fuenteperez.xstream.modelo.Autor;

import es.fuenteperez.xstream.modelo.Blog;

import es.fuenteperez.xstream.modelo.Entrada;

 

public class TestEscritura {

/**

* @param args

* @throws FileNotFoundException

*/

public static void main(String[] args){

try {

//Creamos un objeto Blog

Blog blog = new Blog();

//Creamos un autor y se lo asociamos al blog

Autor autor = new Autor(“Héctor Fuente”);

blog.setAutor(autor);

//A continuacion creamos una serie de entradas para posteriomente asocialas al Blog

Entrada entrada1 = new Entrada(“XStream: Leer ficheros desde Java en 3 Lineas(I)”, “XStream: Leer ficheros desde Java en 3 Lineas(I)”);

Entrada entrada2 = new Entrada(“XStream: Leer ficheros desde Java en 3 Lineas(II)”, “XStream: Leer ficheros desde Java en 3 Lineas(II)”);

Entrada entrada3 = new Entrada(“XStream: Leer ficheros desde Java en 3 Lineas(III)”, “XStream: Leer ficheros desde Java en 3 Lineas(III)”);

blog.add(entrada1);

blog.add(entrada2);

blog.add(entrada3);

//Creamos una instancia de XStream

XStream xstream = new XStream();

//Instanciamos el metodo toXML pasamos como atributos el objeto Blog y un FileOutputStream

xstream.toXML(blog, new FileOutputStream(“testXStream1.xml”));

//XStream nos da diferentes opciones a la hora de nombrar los nodos del fichero XML

//para cambiar por ejemplo <es.fuenteperez.xstream.modelo.Autor> por Autor utilizamos el metodo alias

xstream.alias(“blog”, Blog.class);

xstream.alias(“autor”, Autor.class);

xstream.alias(“entrada”, Entrada.class);

xstream.toXML(blog, new FileOutputStream(“testXStreamAlias.xml”));

 

//Existen otras opciones como omitir por ejemplo el nombre de las colecciones

//en nuestro caso podemos realizarlo sobre la coleccion entradas

//Omitir el tag ‘entradas’, utilizamos el metodo addImplicitCollection

xstream.addImplicitCollection(Blog.class, “entradas”);

xstream.toXML(blog, new FileOutputStream(“testXStreamOmitirTags.xml”));

} catch (Exception e) {

e.printStackTrace();

}

}

}

En el ejemplo anterior se crean 3 ficheros XML (testXStream1.xml, testXStreamAlias.xml y testXStreamOmitirTags.xml) donde se puede ver texto XML generado según las opciones seleccionadas.

Ahora vamos ver como se pueden leer ficheros XML con XStream, para leer ficheros XML utilizamos el metodo xstream.fromXML(InputStream i).

La sencillez del siguiente fragmento de código seguro os va a sorprender:

package es.fuenteperez.xstream.main;

 

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import com.thoughtworks.xstream.XStream;

import es.fuenteperez.xstream.modelo.Blog;

 

public class TestLectura {

 

/**

* @param args

* @throws FileNotFoundException

*/

public static void main(String[] args) {

try {

//Creamos una instancia de XStream

XStream xstream = new XStream();

//Para leer los datos del fichero

//simplemente utilizamos el metodo fromXML

//pasandole un FileInputStream

Blog blog = (Blog) xstream.fromXML(new FileInputStream(“testXStream1.xml”));

} catch (Exception e) {

e.printStackTrace();

System.out.println(“Tal vez debas ejecutar primero TestEscritura.java”);

}

}

}

 

Con una simple llamada a un método, obtenemos el objeto Blog.

 

Podéis descargaros el proyecto para Eclipse con el código que aparece en el artículo en la siguiente dirección:

http://www.fuenteperez.es/resources/testXStream.zip

 

Otras alternativas más formales para leer y escribir ficheros XML son JAXB o XMLBeans, si conocéis alguna otra librería de acceso a XML estaría encantado de que lo comentarais.

 

Salu2. ;)

Información y enlaces

Participa comentando, viendo lo que otros tienen que decir, o enlazandolo desde tu blog.


Otros Posts
Ini4j e IniEditor: Leer fichero INI con Java
Salvar al Burgos C.F

Escriba un comentario

Tomate un momento para comentar y contar lo que piensas sobre el post. Puedes usar un HTML b´sico para formatear.

Comentarios leidos

[…] - Advice On K&N 66 0901 X Stream Top Filter saved by Coreslider2008-08-14 - XStream: Leer ficheros XML desde Java saved by headachebaby2008-08-12 - K&N Xstream Universal Air Cleaner Lid For Serious Racers 9 […]

La clase TestLectura funciona para el primer fichero generado “testXStream1.xml” y no así para los otros dos; ¿podrías explicar el motivo?

Hola Javi,

Para que te funcionen correctamente el TestLectura con el resto de fichero en los cuales hemos utilizados alias y omitido tags debes incluir al objeto xstream los alias y la omisión del la etiqueta.
Añade las siguiente líneas en TestLectura después de la líneas :
//Creamos una instancia de Xtream
XStream xstream = new XStream();

Este el código a añadir:
xstream.alias(”blog”, Blog.class);
xstream.alias(”autor”, Autor.class);
xstream.alias(”entrada”, Entrada.class);
xstream.addImplicitCollection(Blog.class, “entradas”);

Gracias por comentarmelo,
Salu2. Héctor.

Hola.
He seguido tus instrucciones para leer un fichero xml con XStream pero me da el siguiente error:
com.thoughtworks.xstream.converters.ConversionException: orderperson : orderperson : orderperson : orderperson
—- Debugging information —-
message : orderperson : orderperson
cause-exception : com.thoughtworks.xstream.mapper.CannotResolveClassException
cause-message : orderperson : orderperson

El fichero xml es el siguiente;

John Smith

Ola Nordmann
Langgt 23
4000 Stavanger
Norway

Empire Burlesque
Special Edition
1
10.90

Hide your heart
1
9.90

Tengo una clase Shiporder con los atributos:
String orderperson;
Shipto shipto;
Vector itemList;

La clase Shipto:
String name;
String address;
String city;
String country;

Y por último la clase Item:
String title;
String note;
String quantity;
String price;

En el main de TestLectura he puesto:
XStream xstream = new XStream();
xstream.alias(”shiporder”, Shiporder.class);
xstream.alias(”shipto”, Shipto.class);
xstream.alias(”item”, Item.class);
Shiporder shiporder = (Shiporder) xstream.fromXML(new FileInputStream(”shiporder.xml”));

Sabes por qué se produce el error?. Muchísimas gracias.

Para que funcione la serialización con colecciones anidadas la estructura del xml debe ser la siguiente:

def1

prop1
false
0
20

prop1
false
0
20

def2

muy importante el tag que contiene a su vez los

Añadir en el codigo java

xstream.alias(”definiciones”, ExportacionManager.class);
xstream.alias(”definicion”, Definicion.class);
xstream.alias(”elemento”, PropiedadEntidad.class);

xstream.addImplicitCollection(ExportacionManager.class, “definiciones”);
xstream.addImplicitCollection(Definicion.class, “definicion”);

thanks !! very helpful post!

Tengo un problema a la hora de que me escriba las variables. Necesito que mis variables sean del tipo num_max, num_min; con un guión bajo entre medias del nombre de la variable. A la hora de escribir el xml, xstream me hace dos guiones bajos seguidos, es decir: num__max y num__min. El programa que debe leer el fichero no me lo reconoce por este problema. ¿Sabría alguien decirme como solucionarlo? Gracias por adelantado.

Hola David,

Para solucionar este problema tienes que utilizar la clase XmlFriendlyReplacer, que te permite indicar porque quieres que se sustituyan los valores $ y _ al crear el XML. Las razones de esto lo explican en el FAQ de XStream: http://xstream.codehaus.org/faq.html#XML_double_underscores.

Para solucionar el problema vas con sustituir:
XStream xstream = new XStream();

por:

XmlFriendlyReplacer replacer = new XmlFriendlyReplacer(”$”, “_”);
XStream xstream = new XStream(new DomDriver(”UTF-8″, replacer));

Espero haberte ayudado.

Salu2 y muchas gracias por leer mi blog.

Buenas tardes.

Me podrias decir como leer un archivo xml, en donde los tags estan compuestos de la siguiente forma

Al intentar hacerlo me muestra la siguiente excepcion:

com.thoughtworks.xstream.mapper.CannotResolveClassException: