Este cap�tulo explica c�mo usar las clases que generamos en el cap�tulo anterior para:
- Despempaquetar un documento XML en un �rbol de contenido.
- Ejemplarizar las clases para construir un �rbol de contenido.
- Validar nuestro �rbol de contenido contra el DTD.
- Empaquetar un �rbol de contenido en un nuevo documento XML.
- A�adir un arbol de contenido a otro �rbol de contenido.
�El Ejemplar de Documento XML:march.xml
El documento march.xml es v�lido contra checkbook.dtd. Recordamos del cap�tulo Antes de Empezar: Fundamentos de XML que un documento XML debe tener un elemento ra�z que incluya el resto de los elementos del documento. El elemento ra�z del documento march.xml es el elemento transactions porque march.xml representa el conjunto de las transacciones para el mes de Marzo. Seg�n lo mostrado aqu� en march.xml, s�lo ten�amos un dep�sito, un cheque, y una transacci�n de reintegro en el mes de marzo:
<?xml version="1.0" encoding="US-ASCII"?> <;transactions> <;deposit category=salary > <;date>03-14-2001<;/date> <;name>Me<;/name> <;amount>3000.00<;/amount> <;/deposit> <;check number="2" category="groceries"> <;date>03-15-2001<;/date> <;name>Conglomerate Foods<;/name> <;amount>34.95<;/amount> <;pending/> <;memo>food<;/memo> <;/check> <;withdrawal> <;date>03-16-2001<;/date> <;amount>20.00<;/amount> <;/withdrawal> <;/transactions>
�Configurar Nuestra Aplicaci�n
Antes de poder usar JAXB para construir representaciones de datos o trabajar con los datos, primero necesitamos cear una aplicaci�n Java que realice estas funciones. Para configurar nuestra aplicaci�n JAXB:
- Creamos un fichero llamado CheckbookApp.java
- Importamos estos paquetes:
import java.io.*; import java.util.*; import javax.xml.bind.*; import javax.xml.marshal.*;
Los dos �ltimos paquetes son parte del marco de trabajo de uni�n, que define los m�todos unmarshal, marshal, y validate.
- Declaramos la clase CheckbookApp :
public class CheckbookApp { }
- Inicializamos dos objetos Transactions:
public static Transactions marchTrans = new Transactions(); public static Transactions aprilTrans = new Transactions();
Necesitaremos reutilizar estos objetos en nuestra aplicaci�n.
- Dentro de CheckbookApp, creamos nuestro m�todo main:
public class CheckbookApp { public static void main(String args[]) throws Exception { } }
El fichero CheckbookApp.java est� localizado en el directorio examples/checkbook de la descarga.
�Construir un �rbol de Contenido
JAXB nos permite construir un �rbol de contenido de una de estas dos formas: despempaquetando un documento XML o ejemplarizando las clases generadas.
�Desempaquetar
Una vez que hayamos generado las clases del DTD que especifica un documento XML, podemos desempaquetar el documento en un �rbol de contenido. En el directorio /examples/checkbook, se encuentra el fichero llamado march.xml, que contiene las transacciones escritas en el mes de marzo. Para desempaquetar este documento XML en un �rbol de contenido en el fichero CheckbookApp.java:
- Creamos un metodo llamado buildTrees:
public static void buildTrees() throws Exception { }
- En nuestro nuevo m�todo leemos el fichero XML en un FileInputStream:
File march = new File("march.xml"); FileInputStream fIn = new FileInputStream(march);
- Llamamos al m�todo unmarshal de Transactions,
que es la clase que representa el elemento ra�z transactions del
checkbook.dtd:
try { marchTrans = marchTrans.unmarshal(fIn); } finally { fIn.close(); }
- Llamamos al m�todo buildTrees desde nuestro m�todo main:
buildTrees();
En este punto, CheckbookApp genera un �rbol de contenido desde march.xml. La secci�n Acceder al Contenido mostrar� c�mo manipular el contenido del �rbol. La secci�n siguiente muestra c�mo construir un �rbol de contenido ejemplarizando las clases generadas.
�Ejemplarizaci�n
Si tenemos un DTD XML pero ningun ejemplar de documento XML v�lido especificado por el DTD, podemos crear un documento XML v�lido construyendo un �rbol de contenido desde las clases derivadas y empaquetando el �rbol en un documento XML. Supongamos que deseamos crear un �rbol de contenido que representa una lista de transacciones para el mes de abril. Para construir este �rbol de contenido con ejemplarizaci�n:
- En el m�todo buildTrees, despu�s de la llamada para desempaquetar el fichero
march.xml, obtenemos la lista de entradas del objeto aprilTrans,
creamos un nuevo objeto Check, representando el cheque para el alquiler del mes de abril:
List aprilEntries = aprilTrans.getEntries(); Check aprilRentCheck = new Check(); CheckCategory aprilRent = CheckCategory.RENT; aprilRentCheck.setCategory(aprilRent);
- Seleccionamos el nombre de la entidad que recibe el cheque:
aprilRentCheck.setName(Gilchrest Gardens Manor);
- Seleccionamos el n�mero de cheque:
aprilRentCheck.setNumber(51);
Podemos pasar un int al m�todo setNumber porque especificamos en el esquema de uni�n que la propiedad number acepta y devuelve un int.
- Seleccionamos la fecha para el cheque:
aprilRentCheck.setDate(TransDate.parseDate(04-12-2001));
Usamos el m�todo parseDate de la clase TransDate que proporcionamos en el Cap�tulo anterior porque especificamos nuestro propio formato de fechas, que es:MM-dd-yyyy.
- Seleccionamos la cuant�a del cheque:
aprilRentCheck.setAmount(new java.math.BigDecimal(1500.00));
Podemos pasar un java.math.BigDecimal al m�todo setAmount porque especificamos en el esquema de uni�n que la propiedad amout acepta y devuelve un java.math.BigDecimal. Cuando comencemos a calcular el balance para el libro de cheques en el siguiente cap�tulo, veremos la ventaja de realizar estas conversiones de tipos.
- Seleccionamos el estado del cheque a pendiente:
Pending pending = new Pending(); aprilRentCheck.setPendVoidClrd(pending);
- a�adimos el cheque a la lista de entradas del �rbol de contenidos aprilTrans:
aprilEntries.add(aprilRentCheck);
El objeto Entry representa una lista de transacciones, que incluye cualquier n�mero de dep�sitos, de cheques, y de reintegros. Las clases Deposit, Check, y Witdrawal implementan Entry, que representa las funciones comunes de estas tres clases. Despu�s de que creemos un cheque, un dep�sito, o un reintegro, lo agregamos a la lista de entradas. Puesto que la lista es modificable, las transacciones que le agregamos se a�aden autom�ticamente al �rbol de contenido.
Ahora tenemos dos �rboles de contenido: uno para las transaciones de Marzo, y otro para las transaciones de Abril. La siguiente secci�n explica como acceder al contenido de estos �rboles.
�Acceder al Contenido
Tanto si construimos un �rbol de contenido desempaquetando un documento de XML o ejemplarizando sus clases, tenemos acceso al contenido de la misma forma. Esta secci�n demostrar� el acceso al contenido de los �rboles de contenidos que creamos en la secci�n anterior. En el fichero march.xml, tenemos un cheque de la tienda de comestibles para "Conglomerate Fodds". Ahora nos hemos dado cuenta de que compramos en "Mom and Pop Foods" en su lugar. Necesitamos cambiar el nombre del receptor del cheque de la tienda de comestibles a "Mom and Pop Foods"
- Creamos un nuevo m�todo llamado accessContent:
public static void accessContent() {}
- En nuestro m�todo accessContent, llamamos a getEntries
sobre el objeto marchTrans:
List entryList = marchTrans.getEntries();
El entryList contiene todas las transaciones contenidas en el �rbol de contenido que representa los datos de march.xml.
- Iteramos a trav�s de la lista para encontrar las transaciones check:
for(ListIterator i = entryList.listIterator(); i.hasNext(); ) { Entry entry = (Entry)i.next(); if ( entry instanceof Check ){
- Obtenemos la categor�a e cada entrada check que encontramos para determinar
si el cheque de la categor�a groceries:
CheckCategory category = ((Check) entry).getCategory(); if(category.equals(CheckCategory.GROCERIES)){
- Si el cheque pertenece a la catergor�a groceries, seleccionamos el nombre del
receptor a "Mom and Pop Foods" y a�adimos los corchetes de cierre:
((Check)entry).setName(Mom and Pop Foods); break; } } }
- Llamamos al m�todo accessContent desde el m�todo main:
accessContent();
Despu�s de haber creado el �rbol de contenido para las transacciones de Abril, nuestro casero nos informa de que ha aumentado el alquiler a $2000. As� pues, necesitamos cambiar la cantidad del cheque del alquiler en el �rbol de contenido que representa las transacciones para el mes de Abril.
Para cambiar la cuant�a del cheque del alquiler:
- En el m�todo accessContent, obtenemos la lista de entrada, pero esta vez llamamos a
getEntries sobre el objeto aprilTrans:
List aprilEntries = aprilTrans.getEntries();
- Iteramos sobre la lista para encontrar el cheque del alquiler, y seleccionamos su cuant�a a $2000:
for(ListIterator i = aprilEntries.listIterator(); i.hasNext(); ) { Entry entry = (Entry)i.next(); if ( entry instanceof Check ){ CheckCategory category = ((Check) entry).getCategory(); if(category.equals(CheckCategory.RENT)){ entry.setAmount(new java.math.BigDecimal(2000.00)); } } }
Observa en el �ltimo paso que no hemos tenido que forzar Entry a un Check para fijar la cuant�a del cheque. Esto es porque especificamos en el esquema de uni�n que la cantidad es uno de los miembros del interface Entry porque es un elemento que comparten Check, deposit, y Withdrawal. As� pues, cualquier ejemplar de Entry tendr� una cuant�a. En el paso 4 del primer conjunto de pasos, tuvimos que forzar la entry a un Check para fijar el nombre porque el nombre no es uno de los miembros del interface Entry. La raz�n por la que no especificamos Entry para contener un nombre es porque withdrawal no incluye name como uno de sus elementos.
Como hemos hecho cambios en los �rboles de contenido, deber�amos asegurarnos de que nuestro �rbol es v�lido antes de empaquetarlo. La siguiente secci�n explica c�mo validar los �rboles de contenido.
�Validaci�n
Antes de empaquetar un �rbol de contenido a un documento XML, debemos asegurarsnos de que el �rbol de contenido es v�lido con respecto al DTD. Si utilizamos desempaquetamiento en vez de ejemplarizaci�n para construir el �rbol de contenido, y no hemos modificado el �rbol, no necesitamos validar antes de empaquetar porque el proceso de desempaquetamiento incorpora la validaci�n. Si utilizamos la ejemplarizaci�n para construir el �rbol, siempre necesitamos realizar expl�citamente la validaci�n antes de empaquetar. Hemos modificado ambos �rboles de contenido en la secci�n anterior, y as� que debemos validarlos antes de empaquetarlos.
Para validad �mbos �rboles de contenido:
- Creamos un m�todo llamado validateTrees:
public static void validateTrees() throws Exception {}
- Dentro del m�todo, llamamos a validate sobre marchTrans
y aprilTrans :
marchTrans.validate(); aprilTrans.validate();
- Llamamos a validateTrees desde el m�todo main:
validateTrees();
�Empaquetar
Despu�s de validar los �rboles de contenido, estamos listos para empaquetarlos en nuevos documentos XML. Tanto si constru�mos un �rbol de contenido usando desempaquetamiento o ejemplarizaci�n, empaquetamos un �rbol de la misma forma. Para empaquetar los �rboles de contenido:
- Creamos un nuevo m�todo llamado marshalTrees:
public static void marshalTrees() throws Exception {}
- En el nuevo m�todo, creamos nuevos ficheros, para contener los contenidos actualizados de �mbos �rboles:
File march_new = new File(march_new.xml); File april_new = new File(april_new.xml);
- Creamos el obejto OutputStream para enviarlo al m�todo marshal:
FileOutputStream fMOut = new FileOutputStream(march_new); FileOutputStream fAOut = new FileOutputStream(april_new);
- Llamamos al m�todo marshal sobre cada �rbol:
try { marchTrans.marshal(fMOut); aprilTrans.marshal(fAOut); } finally { fMOut.close(); fAOut.close(); }
- Llamamos a marshalTrees desde el m�todo main:
marshalTrees();
Despu�s de que recompilemos las clases y ejecutemos CheckbookApp, veremos los ficheros march_new.xml y april_new.xml en el directorio. Si comparamos march.xml con march_new.xml, encontraremos que la �nica diferencia entre los dos ficheros es el nombre del cheque de la tienda de comestibles, que modificamos. JAXB preserva la equivalencia entre un documento XML y el mismo documento XML formados desde su �rbol de contenido. La siguiente secci�n muestra c�mo agregar el contenido del �rbol que representa las transacciones de Abril al �rbol de contenido que representa las transacciones de Marzo.
�A�adir �rboles de Contenido
Puesto que un objeto en un �rbol de contenido puede tener m�s de un padre, podemos a�adir �rboles de contenido juntos. Podemos emplear esta t�cnica para a�adir las transacciones de Abril a las transacciones de Marzo antes de a�adir las transacciones al libro de cheques como se mostrar� en el siguiente cap�tulo. Para a�adir AprilTrans a Trans:
- Creamos un nuevo m�todo llamado appendTrees:
public static void appendTrees() {}
- En el nuevo m�todo, obtenemos la lista de entradas de cada objeto Transactions:
List mEntries = marchTrans.getEntries(); List aEntries = aprilTrans.getEntries();
- Usamos el m�todo addAll de List, para a�adir la
lista completa de las transaciones de Abril a la lista de las transaciones de Marzo:
mEntries.addAll(aEntries);
- Llamamos a appendTrees desde el m�todo main:
appendTrees();
El siguiente cap�tulo muestra c�mo ampliar la clase Checkbook para proporcionar funcionalidades para a�adir nuestras transaciones de Marzo y Abril a nuestro libro de cheques y hacer el balance.