debug_mode=ON

Buscar en

 
 

Mapeando Java Objects a XML o Generar XML desde Java

Escrito por vladdy hace 1 años bajo una licencia de Creative Commons Creative Commons License
9192 visitas. Etiquetas: objeto, lenguaje, java, xml, parser

Hace algunos días me vi en el dilema de tener que utilizar archivos XML como almacenamiento temporal, estos archivos almacenaban los datos de varios objetos y por tanto tendría que tener un mapeador asociado a cada objeto. Viendo un poco mas el asunto me di cuenta que estos objetos se diferencian básicamente por los atributos que tienen. La conformación de los objetos no es de mucha importancia pues son simplemente objetos de transición, que no tienen ningún método complejo. Por lo tanto en lugar de hacer un generador especifico para cada objeto y como estaba un poco aburrido decidí hacer un generador XML universal.

El objetivo de esta mini librería es tener la posibilidad de convertir un objeto o conjunto de objetos cualquiera de Java en un xml estándar con todos los beneficios que implica. Si quieres conocer algo más obre algunas de las cualidades de XML puedes darte una vuelta por este link.

El principal logro que tiene este generador universal es poder convertir un objeto o una lista de objetos Java de cualquier tipo en un archivo XML. Claro con algunas limitaciones, entre las peores están que: los atributos del objeto deben ser del tipo String, es necesario seguir los estándares de creación de objetos recomendadas por Sun como que los atributos sean privados y la forma de acceder a estos atributos sea por medio de los respectivos get y set. Limitaciones que sin duda no son críticas pero con algo de tiempo estas podrían ser eliminadas y esta utilidad podría ser mejorada sin duda.

Este generador utiliza la librería xerces para la creación de documentos xml; misma que podremos descargar desde su página principal.http://xerces.apache.org/xerces-j/

Lo primero es inicializar los documentos y crear el nodo raíz que se utilizará

private void startDocumentXML() {
try {
        // 1. Crear objeto DocumentBuilderFactory
        DocumentBuilderFactory dbFactory = DocumentBuilderFactoryImpl.newInstance();
        // 2. A partir del objeto DocumentBuilderFactory crear 
        //    un objeto DocumentBuilder
        DocumentBuilder docBuilder = dbFactory.newDocumentBuilder();
        // 3. Generar el documento XML
            documentXML = docBuilder.newDocument();
        } catch (Exception e) {
            System.out.println("Error : " + e);
        }
        // 4. Crear el elemento "descargas"
        document = documentXML.createElement(getRootName());
        // 5. Agregar al documento principal
        documentXML.appendChild(document);
    }

La idea principal es que la clase reciba una lista de objetos y esta sea capaz de iterar sobre la lista y haciendo uso de algunas propiedades más o menos avanzadas de java como ser Reflection poder encontrar los elementos que conformarán el documento xml.

private void populateDocumetnXML(List elements) {

        Element nElement;
        Element item;

        // 1. Crear elemento
        nElement = documentXML.createElement(getRootName());

    // iteramos sobre la lista de objetos que se recibe se 
    //construirá un elemento por cada objeto recibido
        for (int a = 0; a < elements.size(); a++) {
            Object value = "";
            Method met;
            Class obj;
            Field[] stra;

            obj = elements.get(a).getClass();
            stra = obj.getDeclaredFields();

    // posteriormente obtenemos una lista con los atributos que tiene cada objeto
    // y de forma similar creamos nuevos nodos por cada atributo del objeto
            for (int i = 0; i < stra.length; i++) {

                try {
           // utilizamos algo de reflection para obtener los valores de los atributos
                    met = obj.getMethod(getterFind(stra[i].getName()), new Class[]{});
                    value = (String) met.invoke(elements.get(a), new Object[]{});
                } catch (Exception ex) {
                }

        // Si este es el primer elemento le asignamos el nombre del 
        // objeto como nombre del nodo en XML y le añadimos el primer
        // atributo como identificador de atributo  al nodo
                if (i == 0) {
                    String tempSt = obj.getSimpleName().toLowerCase();
                    // 1. Crear elemento
                    nElement = documentXML.createElement(tempSt);
                    // 2. Asignar un atributo
                    nElement.setAttribute(stra[i].getName(), "" + value.toString());
                    // 3. Añadir elemento al documento
                    document.appendChild(nElement);
                } else {
                    // a. Crear item
                    item = documentXML.createElement(stra[i].getName());
                    // b. Asignar un dato al item
                    item.appendChild(documentXML.createTextNode(value.toString()));
                    // c. Aniadir el item
                    nElement.appendChild(item);
                }
            }
        }
    }

El método getterFind lo único que hace es devolver el método al que se accede para obtener el valor del atributo de algún objeto.

private String getterFind(String atName) {
    atName = atName.replaceFirst(atName .substring(0, 1), atName.substring(0, 1).toUpperCase());
    atName = "get" +  atName;
    return attributeName;
}

Ahora se utiliza el parser para generar el archivo XML con los datos generados anteriormente

private String generateTextXML() {
        StringWriter strWriter = null;
        XMLSerializer serializeXML = null;
        OutputFormat ouputFormat = null;
        try {
            serializeXML = new XMLSerializer();
            strWriter = new StringWriter();
            ouputFormat = new OutputFormat();
            // 1. Establecer el formato
            ouputFormat.setEncoding(getEncodingXML());
            ouputFormat.setVersion(getVersionXML());
            ouputFormat.setIndenting(true);
            ouputFormat.setIndent(4);
            // 2. Definir un objeto donde se generara el codigo
            serializeXML.setOutputCharStream(strWriter);
            // 3. Aplicar el formato
            serializeXML.setOutputFormat(ouputFormat);
            // 4. Serializar documento XML
            serializeXML.serialize(documentXML);
            strWriter.close();
        } catch (IOException ioEx) {
            System.out.println("Error : " + ioEx);
        }
        return strWriter.toString();
    }

Finalmente se guarda el archivo generado

private void saveDocumentXML(String texto) {
        try {
            OutputStream fout = new FileOutputStream(getFileName());
            OutputStream bout = new BufferedOutputStream(fout);
            OutputStreamWriter out = new OutputStreamWriter(bout, getEncodingJava());
            out.write(texto);
            out.flush();
            out.close();
        } catch (UnsupportedEncodingException e) {
            System.out.println("Error encoding");
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } catch (Exception e) {
            System.out.println("Error : " + e);
        }
    }

para probar el invento podemos utilizar temporalmente el método

public static void main(String args[]) {

        // A. Crear el objeto(s) a Descarga
        Descarga descarga = new Descarga("1", "Libs", "http://algo.org", "2546");
        Descarga descarga2 = new Descarga("2", "Otros", "http://algo.org", "1654");
//  User user = new User(1, "123", "Vladimir C", "Calle 149", "Cochabamba");
        List elementList = new ArrayList();
        elementList.add(descarga);
        elementList.add(descarga2);
//        elementList.add(user);

        GenerateXML generator = new GenerateXML();

        generator.generateXML(elementList);
    }

Naturalmente necesitamos una clase con los atributos mencionados provistas ademas de sus métodos accesores.

Y el resultado de correr el main anterior es:

<?xml version="1.0" encoding="ISO-8859-1"?>
<Root>
    <descarga id="1">
        <titulo>Libs</titulo>
        <ruta>http://algo.org</ruta>
        <hits>2546</hits>
    </descarga>
    <descarga id="2">
        <titulo>Otros</titulo>
        <ruta>http://algo.org</ruta>
        <hits>1654</hits>
    </descarga>
</Root>

Funciona genial para una lista de objetos del mismo tipo; pero que sucede cuando utilizamos más de un objeto en la lista? (descomenta las líneas que hacen referencia a la clase User en el main)

<?xml version="1.0" encoding="ISO-8859-1"?>
<Root>
    <descarga id="1">
        <titulo>Libs</titulo>
        <ruta>http://algo.org</ruta>
        <hits>2546</hits>
    </descarga>
    <descarga id="2">
        <titulo>Otros</titulo>
        <ruta>http://algo.org</ruta>
        <hits>1654</hits>
    </descarga>
    <user id="1">
        <ci>123</ci>
        <fullName>Vladimir C</fullName>
        <adress>Calle 149</adress>
        <city>Cochabamba</city>
    </user>
</Root>

Como se puede apreciar el comportamiento es muy bueno cuando se tiene diversos objetos en la lista.

El proyecto final está disponible para descargar desde el siguiente enlace : El mismo esta construido como proyecto Netbeans para su fácil revisión.
Además se pueden manipular otros atributos referentes a la creacion del xml, por ejemplo la codificiación, el nombre deldocumento raiz. De la misma forma en el proyecto se cuenta con un pequeño loguer que guarda informacion en caso de haber existido algun error en la generación del XML

En este articulo podremos apreciar la forma de utilizar el archivo XML generado

Esta utilidad toma como base una similar(menor generica) publicada en este blog

Saludos cordiales en una siguiente entrada veremos el proceso de leer el XML para poblar los objetos Java.

 

¡Votalo! 3 votos
¡Compártelo!

        

&nbps;

&nbps;

vladdy

Sobre vladdy

Este usuario no ha completado su perfil.

 
Regístrate o haz login para participar.
¿Todavía no conoces debugmodeon?
debugmodeon es la red social para profesionales de la informática
descubre debugmodeon
 

7 comentarios en "Mapeando Java Objects a XML o Generar XML desde Java "

jsanca
jsanca escribió
hace 1 años

#1   

Man buen esfuerzo, sin embargo existen en Java muchas implementaciones que ya hacen ese trabajo, te doy algunos ejemplos:

En el SDK contamos con las clases:
java.beans.XMLDecoder
java.beans.XMLEncoder

También cuentas con el estandar JAXB, lo podes utilizar con anotaciones y todo.

Fuera de lo estandar tenes,

xstream.codehaus.org/
Te recomiendo ver el tutorial de 2 minutos.
Este es basado en reflexion

http://commons.apache.org/betwixt/
También basado en Reflexion, utiliza Digester para hacer el unmarshall

http://www.castor.org/xml-framework.html
Uno de los pioneros gigantes en el tema

http://xmlbeans.apache.org/
Una de apache

http://jibx.sourceforge.net/
Otro mas

En fin y se que por ahí deben haber mas...
Un saludo

 

yeradis
yeradis escribió
hace 1 años

#2   

Saludos y buen dia

Supongo que a modo didactico no esta nada mal aprenderlo de esta manera como haz hecho tu pero "a la hora de la verdad" necesitas velocida :P

Y hacerlo a mano pues dista mucho de ser la mejor opcion sobre todo cuando tienes schemas xml monumentales, donde solo el mapeo a java te llevaria meses y meses solo un schema , imaginate si tienes 20 ?

Por eso es mas recomendable utilizar librerias que ya hacen el trabajo sucio por ti y asi puedes enfocarte en lo que realmente importa y no es precisamente el mapeo de los objetos.

cuando hablo de schemas me refiero a los XSD(XML Schema Document) que son los que definen la logica de un XML asi como sus especicaciones y comportamientos y asi cuando usas una de esas librerias que menciona "jsanca" ya en el mapeo se va toda esa logica asi como las restricciones y el comportamiento

Sin mas....
Me despido

 

vladdy
vladdy escribió
hace 1 años

#3   

Cómo va jsanca y yeradis

Es cierto existen implementaciones y frameworks para realizar esta tarea, pero como dicen esto es por diversión "just for fun" así aprendo y aprendemos un poquito... me gusto hacerlo pues es una forma interesante de ver a un amigo desconocido en acción "Reflection".

Probablemente en entornos mediano grandes esta utilidad es totalmente insuficiente, realmente no le he dedicado tiempo a optimizarlo ni mejorarlo pues cumple con lo que especificamente necesitaba :) (perdón por el egoismo)

Por que en mi desarrollo no uso un framework o una especificación... es un desarrollo pequeño y portable para aplicacción de escritorio, no necesito o no quiero utilizar algo que me infle la app un framework el de xstream es muy grande por ejemplo.

Por su lado Xerces tb tiene lo suyo en peso pero lo utilicé por que es lo que tenía más a la mano en realidad esa es la parte en la que trabajo ahora en minimizar este recurso de modo que no tenga que utilizar toda la libreria xerces sino más bien una mínima parte. Es decir pasar esto nuevamente a clases sueltas para minimizar su contenido.

Frente a otras (ojo que apenas vi un par de alternativas) utilidades o frameworks una gran ventaja es que cuando tenga el asunto optimizado intentaré hacer que funcione sobre aplicaciones móviles que tengan la implementación de Dalvik (La máquina virtual que tiene Android) donde otros frameworks no pueden llegar.

Saludos y gracias por los comentarios... y gracias también por los enlaces complementan muy bien el post... y probablemente sería útil poner en el título que esto es más bien educativo

PD: Notaron que no se pueden cambiar los títulos de los artículos :p

 

jsanca
jsanca escribió
hace 1 años

#4   

Cobra mas sentido. Debo decirte que he utilizado reflexión intensivamente en mis aplicaciones y te recomiendo utilizar BeanUtil de apache Commons, facilita mucho el trabajo.
http://commons.apache.org/beanutils/

Según veo usas un enfoque DOM en vez de SAX, te recomiendo que le heches un ojo a KXML, esta biblioteca es una implementación XmlPull, la cual son como 3 interfaces, una para leer un dom muy simple y otra para escribirlo, etc. La biblioteca es super pequeña y la he utilizado en ambientes JME.
http://kxml.sourceforge.net/

 

Oscar
Oscar escribió
hace 1 años

#5   

Holas, solo para comentarte que me gusto el articulo y que el link de descarga del proyecto en netbeans no funciona.

Saludos.
:]

 

kendall
kendall escribió
hace 5 meses

#6   

Buenas mi pana, queria saber si puedes poner un ejemplo en un .rar para descargarlo ya que asi no lo entiendo muy bien :(

 

kendall
kendall escribió
hace 5 meses

#7   

Buenas mi pana, queria saber si puedes poner un ejemplo en un .rar para descargarlo ya que asi no lo entiendo muy bien :(

 
 
 
 

© Copyright 2008-2009 debug_mode=ON | Aviso legal | Contacto | FAQ | ¿Quiénes somos? |