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.
Este usuario no ha completado su perfil.
jsanca escribió
hace 1 años
yeradis escribió
hace 1 años
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 escribió
hace 1 años
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 escribió
hace 1 años
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 escribió
hace 1 años
Holas, solo para comentarte que me gusto el articulo y que el link de descarga del proyecto en netbeans no funciona.
Saludos.
:]
kendall escribió
hace 5 meses
Buenas mi pana, queria saber si puedes poner un ejemplo en un .rar para descargarlo ya que asi no lo entiendo muy bien :(
kendall escribió
hace 5 meses
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? |
#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