Download Parte IV. CREANDO UNA APLICACIÓN JAXB

Document related concepts
no text concepts found
Transcript
Parte I. INTRODUCCIÓN
1.1 ¿Qué es JAXB?
El Lenguaje de Marcado Extensible (XML) y la tecnología Java son
compañeros o socios de trabajo en la ayuda a los desarrolladores para
intercambiar datos y programas a través de Internet.
JAXB simplifica el acceso a un documento XML de un programa Java
representando el documento XML en un programa en formato Java, esto es,
provee a los desarrolladores de aplicaciones Java, una forma rápida y
conveniente para enlazar o vincular esquemas XML a representaciones java.
JAXB provee de métodos para desorganizar (unmarshal) documentos
instancias XML en árboles de contenido (generados en código Java), para
después utilizar los mismos y generar mediante el método organizar (marshal)
instancias XML de las que fueron generados.
Esto nos proporciona la flexibilidad de manejar datos XML en una plataforma
“neutral” además de no requerir tratar o conocer las técnicas de
programación de XML al ocultar ciertos detalles complejos de sus relaciones.
JAXB proporciona potencia sin tener las desventajas de que el procesamiento
de las aplicaciones sea pesado y/o complejo como ocurre con SAX o DOM.
Las clases generadas JAXB describen solo relación real definida en los
esquemas fuentes. El resultado de lo anterior son datos xml altamente
portables que unido a un código java portable puede ser usado para crear
flexibles y ligeras aplicaciones y servicios web.
1.2 Características de JAXB
Al usar una aplicación JAXB obtenemos diversos beneficios, además
contamos con una flexibilidad mucho mayor que otras aplicaciones nos dan,
las características más importantes por las cuales nos conviene utilizar JAXB
son las siguientes:
1







JAXB usa Tecnología Java y XML
Garantiza Datos Válidos
Es Rápida
Es Fácil de Usar
Puede Restringir Datos
Es Personalizable
Es Extensible
Para comprender a detalle los beneficios de utilizar JAXB se da una
explicación a continuación sobre cada una de estas características.
1.2.1 Las aplicaciones JAXB usan Tecnología Java y XML
Una de las cualidades más importantes de las aplicaciones de JAXB es que
están escritas en el lenguaje de programación Java y pueden procesar datos
XML. Para poder entender las implicaciones de estas características es
necesario primeramente comprender porque es tan importante la tecnología
Java y el lenguaje XML, además de cómo es su implementación.
El lenguaje XML es una forma, estándar industrial e independiente del
sistema, de representar datos. Los datos que se representan usando XML se
pueden publicar en múltiples medios porque XML describe la estructura de
los datos, no su formato, al contrario que el HTML, Los datos de XML se
pueden pasar entre aplicaciones porque la estructura de los datos se puede
especificar en un esquema, lo que permite que un analizador de sintaxis valide
y procese los datos que siguen el esquema.
El lenguaje XML no proporciona etiquetas, como lo hace HTML, se hace uso
de un esquema para definir nuestras propias etiquetas, y estas a su vez
describen nuestros datos.
Los datos XML son fáciles de trabajar porque están escritos en un formato de
texto simple, legible por los seres humanos y el software de edición de texto.
Por estas razones, XML se está convirtiendo rápidamente en un método
común para el intercambio de datos entre aplicaciones, especialmente
aplicaciones de empresa de negocio-a-negocio.
Las aplicaciones escritas en el lenguaje de programación de Java son
portables: ya que cualquier sistema con una máquina virtual Java puede
ejecutar los bytecode producidos compilando una aplicación Java. Con el
2
código portable que la tecnología de Java proporciona, XML es aún más útil
en el contexto de compartir datos entre las aplicaciones.
Las aplicaciones, especialmente aplicaciones basadas en Web, necesitan la
ayuda de la tecnología de Java para analizar y procesar los datos de una
manera independiente de la plataforma. Asimismo, las aplicaciones Java
necesitan el formato de datos independiente de la plataforma que XML
proporciona para comunicar y compartir información.
Podríamos decir que JAXB proporciona un puente entre estas dos tecnologías
complementarias. Ya que JAXB incluye un compilador que asocia un
esquema a un conjunto de clases Java. Una vez que tengamos nuestras clases,
podremos construir las representaciones de objetos Java de los datos XML que
siguen las reglas que el esquema define.
Al igual que un documento XML es un ejemplar de un esquema, un objeto
Java es un ejemplar de una clase. Así, JAXB permite que creemos los objetos
Java en el mismo nivel conceptual que los datos XML. La representación de
nuestros datos de esta manera permite que los manipulemos de manera
semejante como manipularíamos objetos de Java, haciendo más fácil la
creación de aplicaciones para procesar datos XML. Una vez que tengamos
nuestros datos en la forma de objetos Java, es fácil acceder a ellos. Además,
después de trabajar con los datos, podemos escribir los objetos Java en un
nuevo documento XML. Con el acceso fácil a los datos XML que proporciona
JAXB, solamente necesitamos escribir aplicaciones que realmente utilizarán
los datos, en vez gastar el tiempo en escribir código para formatear los datos.
1.2.2 Las Aplicaciones JAXB son Rápidas
Dos APIs de uso general para analizar XML son SAX (API simple para XML)
y DOM (modelo del objeto del documento). Un analizador de sintaxis de
SAX es un analizador de sintaxis dirigido por eventos, lo que significa que
reacciona a los pedazos del documento mientras lo está analizando; no salva
ninguna parte del documento en memoria. Un analizador de sintaxis de DOM
construye una estructura de datos del documento en la memoria cuyo
contenido puede ser manipulado, pero es mucho más lento que un analizador
de sintaxis SAX. Una aplicación JAXB, por otra parte, tiene la velocidad de
un analizador de sintaxis SAX y de la capacidad de almacenaje de datos de un
analizador de sintaxis DOM. Aunque los analizadores de sintaxis SAX son
rápidos, los primeros prototipos de JAXB han demostrado que JAXB puede
ser más rápido que los analizadores de sintaxis SAX. JAXB hace más
3
rápidamente el análisis porque las clases generadas están precompiladas y
contienen la lógica del esquema, de tal modo que evitan la interpretación
dinámica que un analizador de sintaxis SAX debe realizar.
Una aplicación JAXB puede construir una estructura de datos en memoria
como un analizador de sintaxis DOM. Sin embargo, al contrario que DOM, no
incluye muchas de las funciones adicionales para la manipulación del árbol.
Al contrario que una aplicación DOM, una aplicación JAXB es específica de
un esquema: No podemos utilizarla para procesar los documentos de XML
que se basan en otro esquema. Por estas razones, una aplicación JAXB utiliza
mucho más eficientemente la memoria que DOM.
1.2.3 Las Aplicaciones JAXB son Fáciles de Crear y de Usar
Puesto que todo el código de proceso se genera por nosotros, JAXB es más
fácil de utilizar que la mayoría de los analizadores de sintaxis XML: Con sólo
un stream de entrada podemos tener acceso al contenido. Además, la mayoría
de los analizadores de sintaxis XML se limitan al tipado de datos ofrecido por
un DTD. Un DTD es un tipo de lenguaje de esquema de XML. Todavía
necesitamos proporcionar al código de conversión, que puede ser propenso a
errores y difícil de mantener. JAXB genera automáticamente el código que
podemos personalizar para que realice la conversión de contenidos por
nosotros.
Si sabemos cómo programar en el lenguaje Java y tenemos un mínimo
conocimiento de XML, podremos empezar a usar JAXB. Además, como las
clases generadas cumplen las convenciones del API Java, es incluso más fácil
empezar a trabajar con JAXB.
1.2.4 Las Aplicaciones JAXB Pueden Convertir Datos
Aunque un documento de XML está especificado para un esquema, en este
momento, un esquema está limitado en cómo puede especificar firmemente el
contenido de un documento de XML. Las aplicaciones de intercambio de
datos necesitan tipado de datos formal. XML 1,0 no proporciona
explícitamente a tipado de datos más allá de expresar tipos como valores del
atributo; estos valores del atributo deben entonces ser interpretados analizando
el código proporcionado. Es decir podemos incorporar cualquier tipo de datos
que deseemos entre dos etiquetas, tales como números enteros o cadenas,
4
mientras la estructura del documento esté conforme con la especificación del
DTD. Pero lo que desearemos con frecuencia es poder convertir los datos, por
ejemplo, para especificar que solamente un número entero se puede contener
entre dos etiquetas <quantity>. JAXB proporciona capacidades tanto para la
estructura como para la validación del contenido en el código generado, que
podemos personalizar. Más importante, puesto que JAXB genera el código
Java, podemos asignar tipos exclusivos del lenguaje de programación Java, tal
como Date o BigDecimal, a nuestros elementos.
1.2.5 Las Aplicaciones JAXB Pueden Personalizarse
Antes de generar las clases Java de desde nuestro DTD, escribimos lo que se
llama un esquema de unión, que contiene instrucciones de cómo generar las
clases. El esquema de unión se escribe en un lenguaje de unión basado en
XML, cuyas construcciones utilizamos para escribir al esquema de unión de
modo que podamos especificar cómo se generan las clases. Una de las
personalizaciones más útiles son las conversiones de tipos de datos. Por
ejemplo, como se mencionó en secciones anteriores, podemos especificar en el
esquema de unión que el elemento quantity sólo debe contener números
enteros. Además de las conversiones de tipos de datos, podemos utilizar el
esquema de unión para controlar los nombres de las clases, los paquetes, y los
tipos; y podemos generar constructores, interfaces, y enumeraciones
personalizadas.
El esquema de unión también permite que manejemos la evolución del
esquema. Si nos anticipamos la cambio de nuestro esquema, el esquema de
unión proporcionará constructores especiales que definen uniones flojas que
permitan más flexibilidad. Cuando el esquema se desarrolle, todo lo que
necesitamos hacer es editar el esquema de unión y ejecutar el compilador del
esquema otra vez para crear las clases que reflejan los cambios. Si
intentáramos cambiar las clases en lugar del esquema, una vez que
ejecutáramos el compilador del esquema otra vez, los cambios serían
sobrescritos. Porque las instrucciones de unión se especifican en el esquema
de unión a parte del esquema y el código cuando se desarrolle el esquema, lo
tendremos mucho más fácil para mantener la aplicación.
5
1.2.6 Las Aplicaciones JAXB son Extensibles
Una vez que hayamos generado las clases Java, podremos utilizarlas sin
modificaciones, o subclasificarlas para proporcionar funcionalidades
adicionales. Los desarrolladores de JAXB diseñaron el proceso de unión para
hacer que la derivación de subclases sea sencillo.
1.3 Arquitectura de JAXB
Como se muestra en la figura anterior, una implementación JAXB incluye los
siguientes componentes principales:
Componente
Descripción
Esquema XML
Un Esquema XML usa la sintaxis XML para describir las
relaciones entre los elementos, atributos y entidades en un
documento XML. El esquema XML define un patrón de
documentos XML al que deben adherirse con una estructura
definida por reglas y restricciones de datos especificadas en el
esquema.
Por default, el compilador vinculante JAXB une las clases java y
los paquetes a un esquema fuente XML basado en las reglas
definidas en la especificación JAXB en lo que se conoce como un
Personalizaciones esquema de unión o vinculación. Puede ser que algunas veces las
reglas por default de vinculación no sean suficientes para lo que
Binding
necesitas. JAXB soporta personalizaciones y sobrescribe las
reglas de vinculación por default por el las personalizaciones de
vinculación.
6
Compilador
vinculante
El compilador vinculante JAXB es el núcleo del modelo de
procesamiento JAXB. Su función es transformar, o vincular, un
esquema XML fuente a un conjunto de clases contenido JAXB en
el lenguaje de programación Java. Básicamente, corres el
compilador JAXB usando un esquema XML (opcionalmente con
declaraciones de vinculación) como entrada, y el compilador
vinculante genera clases java con las restricciones en el esquema
fuente XML.
Implementación
de
javax.xml.bind
La implementación del framework de JAXB vinculante es una
API de tiempo de ejecución que provee de interfaces para
desorganizar, organizar y validar contenido XML en una
aplicación Java. El framework vinculante comprende las
interfaces definidas en el paquete javax.xml.bind.
Clases derivadas
del esquema
Aplicación java
Documento de
entrada XML
Salidas de
documentos xml
Estas son clases derivadas del esquema generadas por el
compilador JAXB. Las clases específicas variaran dependiendo
del esquema de entrada.
En el contexto de JAXB, una aplicación java es una aplicación
cliente que usa el marco para desorganizar datos XML, validar y
modificar el contenido de objetos java, y organizar el contenido de
regreso a datos XML. Típicamente, el marco de JAXB es envuelto
en una aplicación java grande que puede proveer características
UI, funciones de transformación XML, datos procesados, o lo que
sea que sea deseado
El contenido que es desorganizado como entrada para el
framework JAXB, eso es, una instancia documento XML, de la
cual es generada una representación java en forma de contenido
de árbol. En la practica, el termino documento puede no tener el
significado convencional, como una instancia documento XML,
puede en su lugar, tomar la forma de flujos de datos pasados entre
aplicaciones, o conjuntos de campos de bases de datos, o de
infosets XML.
En JAXB, el proceso de desorganización soporta la validación de
una entrada documento XML contra las restricciones definidas en
el esquema fuente. Este proceso de validación es opcional.
El contenido XML es organizado fuera de un documento XML.
En JAXB, organizar incluye parsear un objeto árbol de XML y
escribirlo en un documento XML que es una representación
precisa del documento original XML, y es válido con respecto al
esquema fuente. JAXB puede organizar datos XML en
documentos XML, manejadores de contenido SAX, y nodos
DOM
7
1.4 El proceso de vinculación de JAXB
La siguiente figura muestra lo que ocurre durante el proceso de vinculación
JAXB
Típicamente para generar una aplicación JAXB, hay una fase de desarrollo de
aplicación en la cual las clases JAXB son generadas y compiladas, y una
implementación vinculante es construida, seguida por una fase de utilización
en la cual las clases JAXB generadas son usadas para procesar contenido
XML en una continuo “vivir” en un escenario de producción.
1. Vincular el esquema.
 El primer paso del proceso es enlazar el esquema XML fuente en un
conjunto de clases Java que representen ese esquema. Para realizar lo
anterior un esquema XML es usado como entrada para el compilador
vinculante de JAXB para generar clases JAXB que lo representen.
Todas los proveedores de JAXB proveen una herramienta llamada
compilador enlazante para vincular un esquema (la manera en que el
compilador es invocado puede ser específica de la implementación).
Ya que las clases son una implementación específica, las clases
generadas por otro compilador enlazante en una implementación
JAXB probablemente no funcionarán con otra implementación
JAXB. Por lo tanto si cambias a otra implementación JAXB, deberías
revincular el esquema con el compilador enlazante suministrado por
esa aplicación.
8
 Compilar las clases generadas. Todas las clases, interfaces,
archivos fuentes, y código generado debe ser compilado.
2. Crear la aplicación JAXB que utilice las clases y demás archivos
generados por el compilador enlazante y compilarla. Una vez hecho lo
anterior, estas listo para convertir documentos xml a clases java o
viceversa; esto lo podemos realizar mediante:
 Desorganizar y generación de árbol de contenido. Los documentos
XML escritos de acuerdo a las restricciones en el esquema fuente son
desorganizados por el framework vinculante JAXB. Note que JAXB
también soporta desorganización de datos de otras fuentes que
archivos/documentos, tales como nodos DOM, buffers de cadenas,
fuentes SAX, y cosas así. Generar el árbol de contenido. El proceso
de desorganización genera un árbol de contenido de objetos de datos
instanciados de la clase generada JAXB; este árbol de contenido
representa la estructura y contenido de los documentos fuentes XML.
 Validación (Opcional). El proceso de desorganización
opcionalmente incluye la validación de los documentos fuentes XML
antes de generar el árbol de contenido. Si modifica el árbol de
contenido puede también usar la operación de validar JAXB para
validar los cambios antes de organizar el contenido al documento
XML que previamente se había desorganizado.
 Procesos de contenido. La aplicación cliente puede modificar los
datos XML representados por el árbol de contenido Java por el uso
de interfaces generadas por el compilador vinculante.
 Marshalling que es la operación contraria a unmarshalling, con el
cual conviertes objetos Java en una representación documento XML.
9
1.5 Framework vinculante JAXB
El framework vinculante de JAXB es implementado en tres paquetes java:
 El paquete javax.xml.bind, contiene clases e interfaces para la
realización de operaciones tales como desorganización, organización y
validación.
 El paquete javax.xml.bind.util contiene clases de utilidad que pueden
ser usadas por una aplicación cliente para manejar los eventos de
organización, desorganización y validación.
 El paquete de javax.xml.bind.helper provee una implementación parcial
por default para algunas de las interfaces javax.xml.bind. Las
implementaciones JAXB pueden extender estas clases e implementar
los métodos abstractos. Este paquete está designado para los
proveedores de implementaciones JAXB.
1.5.1 El paquete javax.xml.bind
El paquete javax.xml.bind es el paquete principal del framework que define
clases abstractas e interfaces que son usadas directamente con clases
contenido. Define las clases Unmarshaller, Validator, y Marshaller, los cuales
son objetos auxiliares para proveer sus operaciones respectivas.
Además, define una herencia de eventos de validación y clases de excepciones
para usar cuando ocurren errores de organización o desorganización.
Las tres funciones principales proveídas por este paquete son organización,
desorganización, y validación.
Define también la clase JAXBContent la cual es el punto de entrada para una
aplicación java dentro del marco de JAXB. La clase JAXBContext provee una
10
abstracción para administrar la información de vinculación XML/JAVA
necesaria para implementar las operaciones de desorganizar, organizar y
validar.
Una aplicación cliente obtiene nuevas instancias de esta clase por el uso del
método newInstance(contextPath); por ejemplo:
JAXBContext jc= JAXBContext.newInstance(“com.acme.foo:com.acme.bar”);
El parámetro contexPath contiene una lista de los nombres de paquetes java
que contienen las interfaces derivadas de un esquema—particularmente las
interfaces generadas por el compilador enlazante JAXB. El valor de este
parámetro inicializa el objeto JAXBContext para permitir la manipulación de
las interfaces derivadas del esquema. Para este termino, la implementación
proveedora de JAXB debe suministrar una clase implementación conteniendo
un método con la siguiente declaración:
Public static JAXBContext createContext(String contextPath, ClassLoader classLoader)
Throws JAXBException;
1.5.1.1 Desorganización
La clase Unmarshaller en el paquete javax.xml.bind suministra a la aplicación
cliente la habilidad para convertir datos XML en un árbol de contenido de
objetos Java. El método unmarshal para un esquema (dentro de un nombre de
espacios) permite para cualquier elemento global XML declarado en el
esquema para ser desorganizado como la raíz de un documento instancia. Una
aplicación cliente es capaz de desorganizar documentos XML que son
instancias de cualquiera de los esquemas listados en la ContextPath; por
ejemplo:
JAXBContext jc = JAXBContext.newInstance("com.acme.foo:com.acme.bar");
Unmarshaller u = jc.createUnmarshaller();
FooObject fooObj =(FooObject)u.unmarshal( new File( "foo.xml" )); // ok
BarObject barObj =(BarObject)u.unmarshal( new File( "bar.xml" )); // ok
BazObject bazObj =(BazObject)u.unmarshal( new File( "baz.xml" )); // error,
"com.acme.baz" not in contextPath
Una aplicación cliente puede también generar árboles de contenido
explícitamente en lugar de desorganizar datos XML existentes.
11
ObjectFactory objFactory = new ObjectFactory();
com.acme.foo.PurchaseOrder po = objFactory.createPurchaseOrder();
Una vez que la aplicación cliente tiene una instancia de un objeto derivado del
esquema, este puede usar los métodos el transformador de métodos para
establecer contenido en este punto
1.5.1.2 La Organización
La clase Marchaller dentro del paquete jabax.xml.bind provee a la aplicación
cliente la habilidad para convertir una árbol de contenido java de regreso a
datos XML. No hay diferencia entre organizar un árbol de contenido que es
creado manualmente usando los métodos de fábrica y organizar a un árbol de
contenido que es el resultado de una operación de desorganización. El proceso
de organización puede alternativamente producir flujos de eventos SAX2 para
un registrado ContentHandler o producir un Nodo objeto DOM.
Un simple ejemplo que desorganiza un documento xml y luego lo organiza de
regreso fuera es como sigue
JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" );
// unmarshal from foo.xml
Unmarshaller u = jc.createUnmarshaller();
FooObject fooObj =
(FooObject)u.unmarshal( new File( "foo.xml" ) );
// marshal to System.out
Marshaller m = jc.createMarshaller();
m.marshal( fooObj, System.out );
1.5.1.3 La Validación
La clase Validador en el paquete javax.xml.bind es responsable del control de
la validación del árbol contenido durante el tiempo de ejecución. Cuando el
proceso de desorganización incorpora validación y esta fue completada
exitosamente sin algún error de validación, ambos el documento de entrada y
el árbol de contenido resultante están garantizados de ser validos. Por el
contrario, el proceso de organización en realidad no realiza validación.
12
En general, si una implementación JAXB no puede inequívocamente
completar la desorganización u organización, esta terminara el procesamiento
con una excepción.
Un cliente JAXB pude realizar dos tipos de validación:
 Validación al tiempo de desorganizar permite a una aplicación cliente
recibir información acerca de los errores y advertencias detectadas
durante la desorganización de datos XML dentro de un árbol de
contenido, y es completamente ortogonal a los otros tipos de validación.
Para
habilitar
o
deshabilitar
esto
usa
el
método
Unmarshaller.setValidating. Todos los proveedores JAXB son
requeridos para soportar esta operación.
 Validación por demanda permite a una aplicación cliente recibir
información acerca de errores de validación y advertencias detectadas
en el árbol de contenido. A cualquier punto, las aplicaciones cliente
pueden llamar al método Validator.validate en el árbol de contenido (o
cualquier subárbol de este). Todos los proveedores están obligados a
soportar esta operación
1.6 Versiones
Como es natural, JAXB ha tenido hasta la fecha varias versiones, que
corresponden a características o soportes nuevos entre cada versión.
El lenguaje de esquema W3C no es el único lenguaje de esquema, sino que es
el único al que se ha hecho referencia aquí. Sin embargo, la especificación
XML describe DTD como la forma de expresar un esquema. Versiones
preliberadas de implementaciones JAXB solo trabajaban con DTD’s. Sin
embargo en la actualidad, en las últimas versiones de JAXB, se da soporte
también al esquema XML. El esquema XML
permite mayores
potencialidades que los DTD como se verá un poco mas adelante.
13
Parte II. DOCUMENTOS XML
2.1 ¿Qué es XML?
XML, sigla en inglés de eXtensible Markup Language (Lenguaje de Marcas
Extensible), es un metalenguaje extensible de etiquetas desarrollado por el
World Wide Web Consortium (W3C). XML es clasificado como un lenguaje
extensible debido a que permite a sus usuarios definir sus propias etiquetas.
Es una simplificación y adaptación del lenguaje SGML y permite definir la
gramática de lenguajes específicos (de la misma manera que HTML es a su
vez un lenguaje definido por SGML). Por lo tanto XML no es realmente un
lenguaje en particular, sino una manera de definir lenguajes para diferentes
necesidades. Algunos de estos lenguajes que usan XML para su definición son
XHTML, SVG, MathML.
XML no ha nacido sólo para su aplicación en Internet, sino que se propone
como un estándar para el intercambio de información estructurada entre
diferentes plataformas. Se puede usar en bases de datos, editores de texto,
hojas de cálculo y casi cualquier cosa imaginable.
XML es una tecnología sencilla que tiene a su alrededor otras que la
complementan y la hacen mucho más grande y con unas posibilidades mucho
mayores. Tiene un papel muy importante en la actualidad ya que permite la
compatibilidad entre sistemas para compartir la información de una manera
segura, fiable y fácil.
XML fue desarrollado por el Grupo de Trabajo XML (XML Working Group),
originalmente conocido como SMGL Editorial Review Borrad), formado bajo
el auspicio de la W3C en 1996.
Las metas diseñadas para XML son:
 XML debe buscar la usabilidad sobre Internet.
 XML debe soportar una amplia variedad de aplicaciones.
 XML debe ser compatible con SGML.
 Debe ser fácil escribir programas que procesen documentos XML.
14
 El número de características opcionales en XML debe mantenerse al
mínimo absoluto, idealmente ninguno.
 Los documentos XML deben ser legibles para personas y ser
razonablemente claros.
 El diseño XML debe ser preparado rápidamente.
 El diseño de XML debe ser formal y conciso.
 Los documentos XML deben ser fáciles de crear.
 La brevedad en el etiquetado XML es de mínima importancia.
2.2 Definición de Tipo de Documento (DTD)
Un DTD modela un documento:
 Definiendo un conjunto de elementos que pueden aparecer en un
documento XML.
 Definiendo el modelo del contenido de cada elemento. Un modelo del
contenido describe lo que un elemento puede contener en términos de
cualquier subelementos y datos.
 Definiendo un conjunto de atributos opcionales u obligatorios para cada
elemento. La definición de atributos incluye el nombre del atributo, el
valor por defecto y el tipo de dato.
Como el resto de un documento XML, un DTD es simplemente una sección
especial de texto. Sin embargo, debe aparecer al principio de un documento
XML para que una aplicación que reconozca XML pueda validar el
documento. Un DTD puede ser externo o interno a un documento XML. Un
documento DTD externo reside en otro archivo, a veces en otra computadora.
Un DTD interno reside en el mismo archivo que el documento XML. Esto es
conocido algunas veces como DTD privado porque define el modelo de datos
que un documento XML específico utiliza. En contraste, un DTD externo
usualmente define un modelo de datos para un conjunto de documentos XML
relacionados. Como resultado, un DTD externo a veces es referido como DTD
público o compartido.
Ya sea interno o externo, un DTD siempre aparece al inicio de un documento
XML, inmediatamente después de la declaración de XML.
15
2.2.1 Declaración de Tipo de Documento
Un DTD inicia con la declaración del tipo de documento, que contiene una
referencia a un DTD externo o declara un DTD interno.
La declaración de tipo de documento inicia con <!DOCTYPE, que debe estar
todo en mayúsculas como se muestra en número 1. Si planea declarar un DTD
interno, debe proveer el nombre del elemento raíz como se muestra en el
número 2.
Como se mencionó previamente, un DTD externo a veces es llamado como
público o compartido porque reside en un archivo separado. Sin embargo,
puede declarar un DTD externo como privado usando la declaración del
número 3. Puede declarar un DTD compartido y públicamente accesible
usando la sintaxis mostrada en el número 4.
El número 5 representa una declaración DTD interna (lo de “…declaration…”
no es parte del DTD). Este tipo de declaración es para el uso exclusivo del
documento XML en el que la declaración aparece. DTDs internos son
convenientes porque son fáciles de mantener y transportar, pero no son
considerados para ser reutilizables.
Aquí hay algunos ejemplos de varias declaraciones de tipo de documento.
<!DOCTYPE people>
<!DOCTYPE people SYSTEM “…/people.dtd”>
16
<!DOCTYPE book PUBLIC “-//OASIS//DTD DocBook XML V4.1.2//EN”
http://www.oasis.open.org/docbook/xml/4.0/docbook.dtd>
<!DOCTYPE employees SYSTEM “employees.dtd” […]>
2.2.2 Declaración de Elementos
La declaración de un elemento inicia con el delimitador <! (número 1 en la
figura) inmediatamente seguido por ELEMENT en mayúsculas (número 2 en
la figura). El nombre del elemento (número 3) especifica qué nombre tendrá el
elemento. El modelo de contenido (número 4) le permite declarar los cuatro
tipos de elementos que puede crear usando XML:




Elementos vacíos (no contienen datos)
Elementos con sólo elementos (contiene solamente otros elementos)
Elementos mezclados (contiene texto y otros elementos)
Elementos any (pueden contener cualquier contenido permitido)
2.2.2.1 Elementos vacíos
Los elementos vacíos no contienen ningún contenido y típicamente usan
atributos para llevar datos e información. El siguiente ejemplo declara un
elemento vacío:
<!ELEMENT lineBreak EMPTY>
Así es como el elemento previo puede aparecer como parte de un documento
XML:
<lineBreak/> <!—versión corta 1 -->
17
<lineBreak /> <!-- versión corta 2 -->
<lineBreak></lineBreak> <!-- versión larga -->
Esto muestra dos notaciones abreviadas. Ambas usan la secuencia de
caracteres />, pero la diferencia es el espacio entre el nombre del elemento y la
secuencia de caracteres de cierre. La versión larga no es deseable a
comparación de las dos primeras formas. Las primeras dos dejan más claro
que el elemento está vacío mientras que la versión larga no.
2.2.2.2 Elementos con sólo elementos
Elementos con sólo elementos no contienen datos pero contienen otros
elementos. La declaración de un elemento con sólo elemento describe el
nombre del elemento junto con el contenido que puede contener. La forma
general de la declaración de un elemento con sólo elementos es
<!ELEMENT nombre contenido>
El nombre representa el nombre del elemento como aparece en el documento
XML, y el contenido representa lo que el elemento puede contener. Una
declaración de sólo elementos puede contener




Una lista ordenada de elementos
Un elemento de una lista de elementos válidos
Un conjunto repetido de elementos
Una mezcla de todas las anteriores
La lista ordenada de elementos es la más sencilla de entender de los tres tipos
de contenidos. Asumiendo que está modelando un documento XML que
contiene información acerca de algunos libros, y quiere asegurarse de que
contenga información básica acerca de cada libro, como la editorial, fecha de
publicación, ISBN, título, subtítulo, autor y un comentario, en ese orden.
Puede expresar una lista ordenada de elementos usando la siguiente sintaxis:
<!ELEMENT nombreElemento(elemento1,elemento2,elemento3,...,elementoN)>
La declaración especifica el nombre del elemento, el cuál contiene los
subelementos ordenados. Las comas indican que el listado es una lista
ordenada. Como resultado, los subelementos deben aparecer en el orden
especificado en el listado entre paréntesis.
18
Con el ejemplo de los libros quedaría así:
<!DOCTYPE libros
[
<!ELEMENT libros (libro)>
<!ELEMENT libro (editorial, fechaLanzamiento, isbn, titulo, subtitulo, autor,
comentario)>
…
]>
No muestra el DTD completo, porque lo que ve aquí está incompleto porque
el DTD no especifica qué contenido tienen los elementos autor, isbn y los
otros. Asumiendo que los subelementos no contienen ningún dato (son
elementos vacíos), el DTD completo se verá como esto:
<!ELEMENT libros (editorial, fechaLanzamiento, isbn, titulo, subtitulo, autor,
comentario)>
<!ELEMENT editorial EMPTY>
<!ELEMENT fechaLanzamiento EMPTY>
<!ELEMENT isbn EMPTY>
<!ELEMENT titulo EMPTY>
<!ELEMENT subtitulo EMPTY>
<!ELEMENT autor EMPTY>
<!ELEMENT comentario EMPTY>
El siguiente documento sería válido usando el DTD previo:
<?xml version=”1.0”?>
<libros>
<editorial/>
<fechaLanzamiento/>
<isbn/>
<titulo/>
<subtitulo/>
<autor/>
<comentario/>
</libros>
Si quiere incluir el DTD junto con el documento XML, quedaría así:
<?xml version=”1.0”?>
<!DOCTYPE libros [
<!ELEMENT libros (editorial, fechaLanzamiento, isbn, titulo, subtitulo, autor,
comentario)>
<!ELEMENT editorial EMPTY>
<!ELEMENT fechaLanzamiento EMPTY>
19
<!ELEMENT isbn EMPTY>
<!ELEMENT titulo EMPTY>
<!ELEMENT subtitulo EMPTY>
<!ELEMENT autor EMPTY>
<!ELEMENT comentario EMPTY>
]>
<libros>
<editorial/>
<fechaLanzamiento/>
<isbn/>
<titulo/>
<subtitulo/>
<autor/>
<comentario/>
</libros>
En contraste con una lista ordenada de elementos, una selección de elemento
lista una serie de elementos que un elemento puede contener. Sin embargo, el
elemento puede contener sólo uno de los elementos en la lista. Supongamos
que está modelando un documento de inventario que contiene el precio de
venta y el precio de compra, pero no quiere que los dos precios aparezcan para
un ítem dado. Quiere que aparezca un precio, pero sólo el precio de venta o el
precio de compra. El siguiente DTD modela el documento del inventario:
<!ELEMENT ítems (item+)>
<!ELEMENT item (precioVenta | precioCompra)>
<!ELEMENT precioVenta EMPTY>
<!ELEMENT precioCompra EMPTY>
Si queremos incluir el DTD al inicio del documento XML, debemos ponerlo
con la declaración DOCTYPE:
<?xml version=”1.0”?>
<!DOCTYPE ítems [
<!ELEMENT items (item+)>
<!ELEMENT item (precioVenta | precioCompra)>
<!ELEMENT precioVenta EMPTY>
<!ELEMENT precioCompra EMPTY>
]>
<items>
<item>
<precioVenta/>
</item>
<item>
<precioCompra/>
</item>
20
<item>
<precioVenta/>
</item>
</items>
Esto introduce un conjunto de elementos repetidos. Aquí hay un vistazo más
cercano del elemento que lo declara:
<!ELEMENT ítems (item+)>
La declaración del elemento se ve muy similar a una lista ordenada que
contiene sólo un elemento, excepto que un signo más sigue a la palabra item.
Esto indica que el nombre del elemento que lo precede debe aparecer al menos
una vez y puede aparecer cualquier número de veces. Puede usar varios
símbolos para restringir el número de veces que los subelementos pueden
aparecer, como se muestra en la siguiente tabla:
Tabla de símbolos en declaraciones de elementos
(sin
(sin símbolo)
símbolo)
?
Signo de
interrogación
*
Asterisco
+
Símbolo más
()
Paréntesis
|
Pipe
,
Coma
Indica que el elemento debe aparecer exactamente una
sola vez.
Indica que el elemento es opcional, puede aparecer una
vez o ninguna.
Indica que el elemento puede aparecer cero o más veces.
Indica que un elemento puede aparecer una o más veces.
Agrupa una lista de secuencia o de elección.
Usado como parte de una lista de opciones, puede
seleccionar un ítem de la lista.
Usada como parte de una secuencia, puede usar los
elementos en la secuencia basado en sus restricciones
individuales.
Estos símbolos pueden ser útiles para que el DTD sea más complejo. Por
ejemplo, los libros usualmente tienen una dedicatoria, prefacio, tabla de
contenidos y uno o más capítulos. Cada capítulo en un libro tiene al menos un
encabezado y un párrafo, el cuál puede contener texto, una figura, una tabla o
una lista. En lugar de imponer esta estructura, puede agregar flexibilidad
usando la siguiente declaración:
<!ELEMENT libro ((dedicatoria?), prefacio, tdc, (capitulo+))>
<!ELEMENT capitulo (encabezado, (parrafo+))>
<!ELEMENT parrafo (#PCDATA | figura | tabla | lista)*>
21
Este fragmento de DTD indica que la dedicatoria es opcional, indicado por el
símbolo ¿, pero que debe haber un prefacio, una tabla de contenidos (tdc), y al
menos un capítulo. Cada capítulo tiene un encabezado y uno o más párrafos
que pueden contener texto (#PCDATA), una figura, una tabla o una lista.
Notemos que el elemento párrafo, además de los subelementos que contiene,
también contiene texto. Este tipo de elemento es referido como elemento de
contenido mixto.
2.2.2.3 Elementos de Contenido Mixto
Un elemento mixto puede contener datos y elementos. Este modelo es una
extensión de los elementos que contienen sólo elementos que también permite
datos de texto. El siguiente código declara algunos elementos mixtos:
<!DOCTYPE paises
[
<!ELEMENT paises (pais)>
<!ELEMENT pais (#PCDATA | ubicacion | poblacion)>
<!ELEMENT poblacion (#PCDATA | unidades)>
<!ELEMENT ubicacion (#PCDATA | region | #PCDATA)>
<!ELEMENT comentario (#PCDATA)>
]>
Esto declara un documento que contiene una colección de países. Cada país
está hecho de texto (#PCDATA), y elementos de ubicación y población.
#PCDATA puede aparecer más de una vez en la declaración de un elemento,
como se mostró en el elemento ubicación. Puede declarar un elemento de sólo
texto usando la forma mostrada en el elemento comentario.
2.2.2.4 Elementos ANY
Un elemento ANY puede contener cualquier contenido. Declare el elemento
así:
<!ELEMENT nombre ANY>
22
El elemento ANY no tiene ninguna estructura. Como resultado, debe evitar
usarlo en sus propios DTDs. Su principal rol es actuar como comodín hasta
que decida qué tipo de elemento debe contener.
2.2.3 Declaración de Atributos
Los atributos permiten añadir información adicional a los elementos de un
documento. La principal diferencia entre los elementos y los atributos, es que
los atributos no pueden contener subatributos. Se usan para añadir
información corta, sencilla y desestructurada.
<mensaje prioridad="urgente">
<de>Alfredo Reino</de>
<a>Hans van Parijs</a>
<texto idioma="holandés">
Hallo Hans, hoe gaat het?
...
</texto>
</mensaje>
Otra diferencia entre los atributos y los elementos, es que cada uno de los
atributos sólo se puede especificar una vez, y en cualquier orden.
En el ejemplo anterior, para declarar la lista de atributo de los elementos
<mensaje> y <texto> haríamos lo siguiente:
<!ELEMENT mensaje (de, a, texto)>
<!ATTLIST mensaje prioridad (normal | urgente) normal>
<!ELEMENT texto (#PCDATA)>
<!ATTLIST texto idioma CDATA #REQUIRED>
Las declaraciones de los atributos empiezan con "<!ATTLIST", y a
continuación del espacio en blanco viene el identificador del elemento al que
se aplica el atributo. Después viene el nombre del atributo, su tipo y su valor
por defecto. En el ejemplo anterior, el atributo "prioridad" puede estar en el
elemento <mensaje> y puede tener el valor "normal" o "urgente", siendo
"normal" el valor por defecto si no especificamos el atributo.
El atributo "idioma", pertenece al atributo texto, y puede contener datos de
carácter CDATA. Es más, la palabra #REQUIRED significa que no tiene
valor por defecto, ya que es obligatoria especificar este atributo.
23
A menudo interesa que se pueda omitir un atributo, sin que se adopte
automáticamente un valor por defecto. Para esto se usa la condición
"#IMPLIED". Por ejemplo, en una supuesta DTD que define la etiqueta
<IMG> de HTML:
<!ATTLIST IMG URL CDATA #REQUIRED>
<!ALT CDATE #IMPLIED>
Es decir, el atributo "URL" es obligatorio, mientras que el "ALT" es opcional
(y si se omite, no toma ningún elemento por defecto).
2.2.3.1 Atributos CDATA y NMTOKEN
Los atributos CDATA (Character DATA) son los más sencillos, y pueden
contener casi cualquier cosa. Los atributos NMTOKEN (NaMe TOKEN) son
parecidos, pero sólo aceptan los caracteres válidos para nombrar cosas (letras,
números, puntos, guiones, subrayados y los dos puntos).
<!ATTLIST mensaje fecha CDATA #REQUIRED>
<mensaje fecha="15 de Diciembre de 1999">
<!ATTLIST mensaje fecha NMTOKEN #REQUIRED>
<mensaje fecha="15-12-1999">
2.2.3.2 Atributos enumerados y notaciones
Los atributos enumerados son aquellos que sólo pueden contener un valor de
entre un número reducido de opciones.
<!ATTLIST mensaje prioridad (normal | urgente) normal>
Existe otro tipo de atributo parecido, llamado de notación (NOTATION). Este
tipo de atributo permite al autor declarar que su valor se ajusta a una notación
declarada.
<!ATTLIST mensaje fecha NOTATION (ISO-DATE | EUROPEAN-DATE)
#REQUIRED>
Para declarar las notaciones, se utiliza "<!NOTATION" con una definición
externa de la notación. La definición externa puede ser pública o un
24
identificador del sistema para la documentación de la notación, una
especificación formal o un asistente de la aplicación que contenga objetos
representados en la notación
<!NOTATION HTML SYSTEM "http://www.w3.org/Markup">
<!NOTATION HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
2.2.3.3 Atributos ID e IDREF
El tipo ID permite que un tipo determinado tenga un nombre único que podrá
ser referenciado por un atributo de otro elemento que sea de tipo IDREF. Por
ejemplo, para implementar un sencillo sistema de hipervínculos en un
documento:
<!ELEMENT enlace EMPTY>
<!ATTLIST enlace destino IDREF #REQUIRED>
<!ELEMENT capitulo (parrafo)*>
<!ATTLIST capitulo referencia ID #IMPLIED>
En este caso, una etiqueta <enlace destino="seccion-3"> haría referencia a un
<capitulo referencia="seccion-3">, de forma que el procesador XML lo podría
convertir en un hipervínculo, u otra cosa.
2.3 XML Schema
XML Schema es un lenguaje de esquema escrito en XML, basado en la
gramática y pensado para proporcionar una mayor potencia expresiva que la
DTD, más limitado en la descripción de los documentos a nivel formal.
Los documentos esquema (usualmente con extensión .xsd de XML Schema
Definition (XSD)) se concibieron como una alternativa a las DTD, más
compleja, intentando superar sus puntos débiles y buscar nuevas capacidades a
la hora de definir estructuras para documentos XML. La principal aportación
de XML Schema es el gran número de los tipos de datos que incorpora. De
esta manera, XML Schema aumenta las posibilidades y funcionalidades de
aplicaciones de procesado de datos, incluyendo tipos de datos complejos como
fechas, números y strings.
25
"XML Schema" (Esquema XML) es el nombre oficial otorgado a la
recomendación del W3C, que elaboró el primer lenguaje de esquema separado
de XML (la definición de tipo de documentos (DTD) forma parte de XML).
XML Schema supera muchas de las limitaciones y debilidades de las DTDs.
Fue diseñado completamente alrededor de namespaces y soporta tipos de
datos típicos de los lenguajes de programación, como también tipos
personalizados simples y complejos. Un esquema se define pensando en su
uso final.
Los esquemas se construyen a partir de diferentes tipos de componentes:








Elemento (element)
Atributo (attribute)
Tipo simple (simple type)
Tipo complejo (complex type)
Notación (notation)
Grupo modelo nombrado (named model group)
Grupo de atributos (attribute group)
Restricción identidad (identity constraint)
Estos componentes ofrecen la posibilidad de combinar características de alto o
bajo nivel:
 Alto nivel: Se encargan de ofrecer un significado semántico del
contenido del documento. Analizan el contenido y extraen de él un
significado. Éste puede estar predefinido en la declaración del esquema
o se puede extraer de la misma estructura.
 Bajo nivel: Son características más concretas del documento que están
incluidos en los diferentes campos del esquema y se accede a ellas de
manera directa. Son los que se comparan directamente con el criterio de
búsqueda definido y halla palabras concretas en la definición de los
esquemas.
2.3.1 Estructura Mínima de un Esquema
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="0.1"
xml:lang="es">
26
</xsd:schema>
La programación en Schema XML se basa en Namespaces. Podemos
encontrar una analogía entre éstos y los llamados packages en Java. Cada
Namespace contiene elementos y atributos que están estrechamente
relacionados con el Namespace. Así, a la hora de definir un elemento o un
atributo de un Namespace, siempre se creará una conexión entre los diferentes
campos de éste. Además, esta forma de trabajar nos permite relacionar
elementos que no están en el mismo Namespace.
Después de escribir un Schema XML se puede confirmar la correcta
realización mediante la validación de esquemas XML: Validación XML.
2.3.2 Tipos de Datos
Los tipos de datos en XML Schema pueden ser simples o complejos:
Tipos simples: son aquellos que no tienen ni elementos hijos ni atributos.
Son tipos simples:
 Tipos predefinidos de XML: string, double, boolean, etc.
 List (lista de datos separados por espacios).
 Union (tipo de dato derivado de la unión de tipos predefinidos).
Tipos complejos: Son tipos complejos aquellos que tienen elementos hijos
y/o atributos.
Pueden tener nombre o ser anónimos. Si tienen nombre pueden ser
reutilizados dentro del mismo XML Schema o por otros XML Schemas.
Es posible "mezclar" o combinar elementos y texto.
27
2.3.3 Diagrama de los Tipos de Datos que manejan los Schemas
2.4 Documento XML
Suponiendo que tuvieramos un documento xml de esta forma:
<?xml version="1.0"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
Para hacer referencia a un dtd escribimos:
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "http://www.w3schools.com/dtd/note.dtd">
<note>
<to>Tove</to>
<from>Jani</from>
28
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
Mientras que para hacer referencia a un schema escribimos:
<?xml version="1.0"?>
<note
xmlns="http://www.w3schools.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3schools.com note.xsd">
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
2.4.1 Ejemplo: Diferencias entre DTD y Schemas
Utilizando el documento xml anterior, podriamos definir sus elementos con un
DTD de esta manera:
<!ELEMENT note (to, from, heading, body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
Utilizando un schema nos quedaria de esta forma:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3schools.com"
xmlns="http://www.w3schools.com"
elementFormDefault="qualified">
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="to" type="xs:string"/>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
</xs:complexType>
29
</xs:element>
</xs:schema>
30
Parte III. ACCESO A UN DOCUMENTO XML
3.1 Construcción de una aplicación JAXB
Antes de construir una aplicación JAXB primeramente necesitamos tener un
esquema XML. En la versión 1.0 de JAXB, se requiere que el esquema
utilizado sea un DTD, según lo establecido en la especificación XML 1.0. No
obstante en las versiones posteriores a la 1.0, podemos utilizar el Schema
XML.
Después de tener el Schema o DTD, seguimos los siguientes pasos para poder
construir y usar nuestra aplicación JAXB.
1. Escribir el esquema de Unión: es un documento XML que contiene
instrucciones de cómo unir un esquema a las clases. Estas indicaciones
pueden ser por ejemplo, el tipo primitivo al que se debe unir un valor de
atributo en la clase generada.
2. Generar los ficheros fuente de Java: para esto usamos el compilador de
esquema, ya que este toma al schema o DTD y al esquema de unión
como entrada de información. Cuando ya se haya compilado el código
fuente, podemos escribir una aplicación basada en las clases que
resulten.
3. Construir el árbol de objetos Java: con nuestra aplicación, construimos
el árbol de objetos java, también llamado árbol de contenido, este
representara los datos XML que son validos con el schema o DTD.
Hay 2 maneras de hacer esto:
 Ejemplarizando las clases generadas.
 Invocando al método unmarshal de una clase generada y pasarlo
en el documento.
El Método unmarshal toma un documento XML válido y construye una
representación de árbol de objetos.
4. Acceder al árbol de contenido usando nuestra aplicación: con nuestra
aplicación podemos acceder al árbol de contenido y modificar sus datos.
31
5. Generar un documento XML desde el árbol de contenido: para poder
hacerlo tenemos que invocar al método marshal sobre el objeto raíz del
árbol.
3.2 Creación del Esquema de Unión
Para unir un schema o DTD a las clases, utilizamos el lenguaje de unión y el
compilador de esquema, ambos incluidos con JAXB. El lenguaje de unión es
un lenguaje basado en XML que utilizamos para escribir al esquema de unión.
El esquema de unión contiene las instrucciones para unir el DTD a las clases,
y lo utilizamos para controlar el código que genera el compilador de esquema.
Por esto es importante comprender como interpreta el compilador de esquema
a las declaraciones que hacemos en el esquema de unión y lo que asume dicho
compilador si no proporcionamos declaraciones de unión para una declaración
del schema o DTD.
Al escribir el esquema de unión, no es necesario que proporcionemos
declaraciones particulares de unión para cada uno de los componentes del
schema o DTD, ya que cuando las omitimos, el compilador de esquema asume
declaraciones de uniones por defecto. Sin embargo, si no nos satisfacen las
uniones por defecto, podemos escribir en el esquema de unión las
declaraciones de unión que necesitamos para generar las clases deseadas. Por
ejemplo, el compilador de esquema utiliza un algoritmo general de mapeo de
nombres para unir nombres XML a nombres que son aceptables en el lenguaje
de programación Java. En este caso, podemos utilizar el esquema de unión
para hacer que el compilador de esquema genere nombres diferentes.
Para crear el esquema de unión mínimo requerido seguimos los siguientes
pasos:
1. Creamos un nuevo archivo de texto con extensión .xjs.
2. Para identificar al archivo como un esquema de unión, escribimos la
etiqueta:
<xml-java-binding-schema version=”1.0ea”>
3. Los esquemas de unión deben declarar al menos un elemento raíz. Para
declararlo escribimos:
32
<element name=”nombre_elemento_raiz” type=”class” root=true/>
Al declarar los elementos raíz, utilizamos la declaración de unión del
elemento para unir un tipo de elemento a una clase. El valor del atributo
name, debe ser el nombre del elemento tal como aparece en el schema o
DTD. El valor del tipo de atributo class indica que los elementos raíz se
limitan a las clases. Finalmente el valor del atributo root debe ser igual
a true para que en la estructura de los documentos XML podamos
declarar como elementos raíz al elemento o elementos que declaramos
como tal en el esquema de unión.
4. Introducimos la etiqueta de cierre para el elemento xml-java-bindingschema :
</xml-java-binding-schema>
Ahora ya tenemos el esquema de unión desde el cual el compilador de
esquema puede generar clases. Recordemos que el compilador de esquema
hará declaraciones de uniones por defecto, para las otras declaraciones del
schema o DTD a las que no les hayamos proporcionado una declaración de
unión.
3.2.1 Declaración de Unión de Elementos
El compilador de esquema asume las diversas declaraciones de unión para los
elementos dependiendo del tipo de contenido que tienen y sus atributos si es
que los hay. Para los elementos simples, es decir, los que no tienen atributos y
solo tienen contenido de tipo carácter, el compilador de esquema asumirá que
los elementos están unidos a las propiedades dentro de la clase de su elemento
padre. Para esto el compilador generara el siguiente código de declaración de
unión por defecto:
<element name=”nombre_elemento_simple” type=”value”/>
El nombre de los atributos debe ser el nombre del elemento tal y como aparece
en el schema o DTD. El tipo del atributo es value porque estos elementos
están unidos a propiedades y no a clases. Las propiedades que generará el
compilador de esquema con estas declaraciones de unión serán:
String getNombre_elemento_simple();
void setNombre_elemento_simple(String x);
33
Si los elementos contienen cualquier cosa distinta de contenido de tipo
carácter o si tienen atributos, el compilador de esquema asumirá que están
unidos a clases. Por lo que las uniones por defecto de estos elementos serán:
<element name=”nombre_elemento” type=”class”>
Podemos observar que en esta declaración no se especifica el atributo root
como lo hicimos en la sección 3.2 Creación del esquema de Unión, esto es
debido a que el compilador de esquema asume que el valor de este atributo es
false. Por lo que solo necesitamos especificar el valor de este atributo como
true cuando queramos que dicho elemento pueda ser usado como elemento
raíz.
Los elementos con contenido EMPTY también estarán unidos a clases, y su
declaración de unión por defecto será:
<element name=”nombre_elemento_vacio” type=”class”/>
A menos que lo especifiquemos de otra manera en nuestro esquema de unión,
el compilador de esquema generará una clase para cada elemento cuyo
contenido contenga otros elementos.
De la declaración de unión de los elementos que tienen elementos como
contenido y/o atributos, el compilador de esquema generará la siguiente
definición de clase y constructor:
public class Nombre_elemento extends MarshallableObject {
public void Nombre_elemento();
3.2.2 Declaración de Unión de Atributos
En los elementos que tienen atributos, dichos atributos toman valores
atómicos en vez de valores compuestos, por lo que el compilador de esquema
asume que están unidos a propiedades String, como se especifica en la
siguiente declaración por defecto:
<element name=”nombre_elemento” type=”class”>
<attribute name=”nombre_atributo”/>
34
Dentro de la definición de clase del elemento, el compilador de esquema
generará la siguiente propiedad para representar al atributo:
void setNombre_atributo(String x);
String getNombre_atributo();
Podemos observar en esta propiedad, que se acepta y devuelve un String, más
adelante en la sección 3.2.5 Especificando Tipos veremos como modificar el
esquema para requisitos de uniones particulares de manera que el compilador
de esquema genere una propiedad que acepte y devuelva otros tipos de datos.
Así como también veremos en la sección 3.2.6 Creación de Tipos de Datos
Enumerados, como generar tipos de datos enumerados para la propiedad que
representa al atributo.
3.2.3 Declaración de Unión de Contenido
La declaración de unión de contenido es lo más complicado, debido a que hay
infinitas maneras de especificar el contenido XML, sin embargo JAXB nos lo
facilita. El tipo más común de modelo de contenido es una secuencia simple
no repetitiva por ejemplo: (a, b, c, d). si utilizamos este modelo de contenido,
es muy probable que no tengamos que especificar una declaración de unión
para él, ya que el compilador de esquema generará una propiedad separada
para cada elemento de la secuencia. Por lo que para los elementos con
contenido secuencial simple y no repetitivo (ya sea la raíz u otro elemento), el
compilador de esquema asumirá las siguientes declaraciones de unión
mostradas en negritas:
<element name=”nombre_elemento_raíz” type=”class” root=true>
<content>
<element-ref name=”nombre_elemento1”/>
<element-ref name=”nombre_elemento2”/>
</content>
</element>
<element name=”nombre_elemento” type=”class”>
<attribute name=”nombre_atributo”/>
<content>
<element-ref name=”nombre_elemento1”/>
<element-ref name=”nombre_elemento2”/>
</content>
</element>
La declaración de unión element-ref se utiliza para unir un ejemplar de un
elemento del modelo de contenido, a una propiedad en la clase del elemento
35
padre. Por defecto, el compilador de esquema genera propiedades String desde
todas las declaraciones de uniones element-ref que se refieran a elementos
simples. Por lo que la propiedad generada para estos elementos será:
public class Nombre_elemento {
...
String getNombre_elemento1();
void setNombre_elemento1(String x);
Si un elemento contiene algo distinto a una secuencia simple no repetitiva, el
compilador de esquema asumirá la declaración de unión de la propiedad
general-content, por lo que su declaración será:
<element name=”nombre_elemento_raíz” type=”class” root=true>
<content property=”content”/>
</element>
...
<element name=”nombre_elemento” type=”class”>
<attribute name=”nombre_atributo”/>
<content property=”content”/>
</element>
Usamos la declaración general-content para unir un modelo de grupo
completo (incluyendo modelos de grupos anidados), a una propiedad. Sin
embargo, esta declaración no es útil cuando deseamos acceder a los elementos
individuales del modelo de contenido. No obstante, puede ser útil para definir
uniones mas flexibles si anticipamos que nuestro schema o DTD cambiará en
el futuro.
Desde estas declaraciones de unión el compilador de esquema genera la
siguiente propiedad:
List getContent();
void emptyContent();
void deleteContent();
El método getContent devuelve una lista modificable que contiene el valor
actual de las propiedades. El método emptyContent descarta los valores de la
lista y crea una nueva lista vacía. El método deleteContent borra la lista.
Ahora que ya entendemos las declaraciones de unión que el compilador del
esquema asumirá basándose en el schema o DTD y el esquema de unión
36
mínimo, podemos escribir fácilmente el esquema de unión. Lo único que
necesitamos hacer es escribir las declaraciones de uniones que no son
asumidas por el compilador de esquema.
3.2.4 Ejemplo: Esquema de Unión para book.dtd.
Como un ejemplo de unir un esquema a las clases, consideremos este DTD:
<!ELEMENT book (title, author, chapter+)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT chapter (#PCDATA)>
En muchos casos, el compilador de esquema puede generar una unión
apropiada incluso cuando el esquema de unión no incluye una instrucción de
unión para una declaración determinada del DTD. De hecho, para generar las
clases del DTD book, todo lo que necesitamos en nuestro esquema de unión
es:
<xml-java-binding-schema>
<element name="book" type="class" root="true" />
</xml-java-binding-schema>
Para estos DTD y esquema de unión, el compilador de esquema genera una
clase Book con este constructor y estas propiedades:
public Book();
public String getTitle();
public void setTitle(String x);
public String getAuthor();
public void setAuthor(String x);
public List getChapter();
public void deleteChapter();
public void emptyChapter();
Recuerda que el elemento chapter en el modelo de contenido book tenía un +
como indicador de ocurrencia:
<!ELEMENT book (title, author, chapter+)>
La lista que devuelve getChapter es una lista de valores String, cada uno de
los cuales representa un ejemplar distinto del elemento chapter. Observa
37
también que el esquema de unión no hizo referencia al indicador de ocurrencia
después del ejemplar del elemento chapter. Éste es un ejemplo de cómo el
compilador de esquema considera las especificaciones del DTD así como las
instrucciones de unión del esquema de unión al generar las clases.
3.2.5 Especificando Tipos
Por defecto, el compilador de esquema genera métodos get que devuelven un
String y métodos set que aceptan un String, para todos los elementos y
atributos simples. Por ejemplo consideremos las siguientes declaraciones de
unión por defecto para el elemento amount:
<element-ref name=”amount”/>
...
<element name=”amount” type=”value”/>
Desde estas declaraciones, el compilador de esquema generará estos dos
métodos:
public String getAmount();
public void setAmount(String amount);
En caso de que deseáramos hacer cálculos con la variable amount tendríamos
que convertirla de un String a algún otro tipo de dato que nos lo permita. Para
cálculos que implican valores de moneda podemos utilizar el tipo BigDecimal,
ya que este tipo representa números decimales con signo y precisión arbitraria.
Para especificar un tipo, lo único que tenemos que hacer es utilizar la
declaración de conversión para definir la conversión y el atributo convert de la
declaración del elemento o del atributo, dependiendo de si queremos convertir
el tipo de una propiedad de elemento o de atributo, para referenciar la
declaración de conversión.
3.2.5.1 Especificar Tipos No Primitivos
Para definir una conversión de String a BigDecimal debemos seguir los
siguientes pasos:
38
1. Añadimos en el nivel superior de nuestro esquema de unión, entre las
etiquetas <xml-java-binding-schema version=”1.0ea”> y después de la
declaración de unión del elemento raíz, la siguiente declaración de
conversión:
<conversion name=BigDecimal type=java.math.BigDecimal/>
Cualquier declaración de unión de elemento o de atributo que quiera
utilizar esta conversión se referirá a ella por el nombre BigDecimal,
según lo especificado por el nombre del atributo. El valor del tipo de
atributo es el tipo real al cual se convierte una propiedad.
2. Para decirle al compilador de esquema que genere una propiedad de un
elemento con un tipo BigDecimal tenemos que:
 Añadir una declaración de unión de elemento para el elemento que
queramos convertir en la parte superior de nuestro esquema de
unión, como ejemplo utilizaremos al elemento amount de la sección
anterior:
<element name=amount type=value />
 Añadimos un atributo convert a la unión del elemento amount y le
asignamos el valor BigDecimal:
<element name=amount type=value convert=BigDecimal/>
Estas declaraciones de unión producirán las siguientes firmas de
métodos:
<public java.math.BigDecimal getAmount();
public void setAmount(java.math.BigDecimal amount);
Declarar por separado la conversión de una unión de elemento nos
permite reutilizar una conversión para otras uniones de elemento.
También podemos convertir el tipo de la propiedad de un elemento llamado
date a un java.util.Date. Como una fecha puede escribirse de diferentes
maneras, debemos especificar como se debe de analizar la fecha cuando se
desempaquete y como se debe imprimir cuando se empaquete. Para hacer esta
declaración de conversión se requieren los atributos parse y print.
39
Para convertir el elemento date a un java.util.Date, seguimos los siguientes
pasos:
1. Añadimos la siguiente declaración de conversión al esquema de unión:
<conversión name=TransDate type=java.util.Date
parse= TransDate.parseDate print=TransDate.printDate/>
El nombre TransDate se refiere a una clase Java que necesitamos
proporcionar. Esta clase contiene un método estático parseDate que
especifica cómo analizar la fecha y un método estático printDate que
especifica cómo imprimir la fecha.
2. Para decirle al compilador de esquema que genere una propiedad date
con la clase TransDate, añadimos un atributo convert a la declaración
de unión del elemento date y le asignamos el valor de TransDate:
<element name=date type=value convert=TransDate/>
Estas declaraciones de unión producirán las siguientes firmas de
métodos:
public java.util.Date getDate();
public void setDate(java.util.Date x);
En la conversión a BigDecimal, no necesitamos especificar un método de
análisis o de impresión ya que la clase java.math.BigDecimal especifica un
constructor que acepta un String y devuelve un BigDecimal y un método
toString que acepta un BigDecimal y devuelve un String. Para aplicar la
conversión, el compilador de esquema genera código para invocar al
constructor y al método toString.
3.2.5.2 Especificar Tipos Primitivos
Para especificar tipos primitivos, como int, no necesitamos proporcionar una
declaración de unión de conversión separada, simplemente añadimos el
atributo convert a la declaración de unión del elemento o del atributo y
asignamos el valor al tipo primitivo. Por ejemplo, dentro de la declaración de
unión de un elemento llamado check, añadimos una declaración de unión de
atributo para el atributo number y especificamos un tipo int para su propiedad:
40
<element name=check type=class >
<attribute name=number convert=int />
</element>
3.2.6 Creación de Tipos de Datos Enumerados
También podemos utilizar al atributo convert para especificar un tipo de dato
enumerado. En el lenguaje de programación Java, representamos tipos
enumerados con un tipo seguro enum, que es una clase cuyos elementos
representan un conjunto fijo de valores.
Un atributo cuyo valor sólo se pueda fijar a uno de un conjunto fijo de valores
es un buen candidato para un tipo enumerado. Para generar los tipos para estos
atributos tenemos que:
1. Introducir una etiqueta enumeration para cada conversión que queramos
realizar, en el nivel superior del esquema de unión, después de la
declaración de conversión de TransDate, esto quedaría así:
<conversion name=TransDate ...
<enumeration/>
2. Dentro de la etiqueta enumeration escribimos el atributo name este
nombre debe ser único, debido a que podrían existir mas enumeraciones
que estén al mismo nivel en el esquema de unión.
<enumeration name=”Categorias1”/>
<enumeration name=”Categorias2”/>
Estos nombres serán los nombres de las clases para representar los tipos
seguros enums.
3. Añadimos el atributo members a cada declaración de enumeración, y le
asignamos los posibles valores de cada atributo:
<enumeration name=”Categorias1” members=val1 val2 val3/>
<enumeration name=”Categorias2” members=val1 val2 val3/>
41
4. Añadimos las declaraciones de unión de los atributos dentro de las
declaraciones de unión de los elementos y asignamos el nombre de la
declaración de enumeración apropiada a cada atributo convert en la
declaración de unión del atributo:
<element name=”elemento1” type=”class”>
<attribute name=”nombre_atributo” convert=Categorias1/>
...
<element name=”elemento2” type=”class”>
<attribute name=”nombre_atributo” convert=Categorias2/>
5. Desde la declaración de unión del atributo del elemento2, el compilador
de esquema generará la siguiente clase:
public final class Categorias2 {
public final static Categorias2 VAL1;
public final static Categorias2 VAL2;
public final static Categorias2 VAL3;
public static Categorias2 parse(String x);
public String toString();
}
3.2.7 Creación de interfaces
Cuando tenemos un grupo de clases que proporcionan funciones similares y
tienen algún comportamiento y propiedades comunes, podemos utilizar un
interface para capturar las semejanzas entre las clases.
Para que el compilador de esquema genere un inteface lo que tenemos que
hacer es:
1. En cualquier lugar del nivel más alto de nuestro esquema de unión,
quizás después de las declaraciones de enumeración, introducimos la
siguiente declaración de interface:
<interface name=Entry members=clase1 clase2 clase3
properties=elemento_comun_amount elemento_comun_date />
El atributo members representa todas las clases que implementan la
interface. El atributo properties representa el contenido común
compartido por los miembros de la interface.
42
2. Ahora, suponiendo que los elementos clase1, clase2, clase3 ocurren en
el modelo de contenido de la raíz como un grupo de elección,
necesitamos referenciar Entry desde la unión del grupo de elección.
Previamente asignamos el nombre de la interface al atributo de la
propiedad, el valor list al atributo collection y asignamos el nombre de
la interface al atributo supertype:
<element name= elemento_raiz type=class class= Elemento_raiz>
<content>
<choice property=entries collection=list supertype=Entry/>
</content>
</element>
El atributo supertype indica una clase o interface declarada en el
esquema de unión, que cada clase de elemento incluida en la propiedad
choice implementa.
3. Estas declaraciones de unión producirán una interface llamada Entry,
que
incluirá
las
propiedades
elemento_comun_amount
y
elemento_comun_date:
public interface Entry {
...
public int getElemento_comun_amount();
public void setElemento_comun_amount(int x);
public Date getElemento_comun_date();
public void setElemento_comun_date(Date d);
3.3 Generación de los Ficheros Fuente de Java
Ya que tenemos el esquema de unión, podemos ejecutar al compilador de
esquema para generar un conjunto de ficheros fuente Java desde el schema o
DTD basándose en las instrucciones que proporcionamos en el esquema de
unión. Después de que se generen los ficheros fuente, podemos compilarlos
usando el compilador de Java como lo haríamos con cualquier aplicación Java.
Para esto seguimos los siguientes pasos:
1. Ejecutamos el compilador de esquema con el archivo del schema o
DTD y el esquema de unión que hemos creado:
xjc fichero.dtd fichero.xjs
43
Ahora deberíamos ver los ficheros con extensión .java (fichero.java y
Entry.java) en nuestro directorio actual.
2. Compilamos los ficheros fuente en clases java con:
javac *.java
Un elemento raíz del schema o DTD, está unido a la clase con el mismo
nombre del elemento y su firma es:
public class nombre_elemento extends MarshallableRootElement implements
RootElement
Como este elemento es un elemento raíz, la clase extiende
MarshallableRootElement, que es la clase que representa objetos elemento
raíz que pueden ser empaquetados y desempaquetados, e implementa
RootElement.
Aunque MarshallableRootElement define métodos marshal, que la clase del
elemento raíz usa por extensión, no define ningún método unmarshal. Por lo
que, el compilador de esquema genera estos métodos unmarshal estáticos
dentro de la clase:
public static Nombre_elemento unmarshal(InputStream in)
public static Nombre_elemento unmarshal(XMLScanner xs)
public static Nombre_elemento unmarshal(XMLScanner xs, Dispatcher d)
Cuando desempaquetamos un documento XML, podemos invocar a
unmarshal (InputStream) o a unmarshal (XMLScanner) en los que
InputStream o XMLScanner representan nuestro documento XML.
Aunque el desempaquetamiento realiza la validación por nosotros,
necesitamos validar después de editar el árbol de contenido y antes de
empaquetarlo en un documento XML. Para este propósito, el compilador de
esquema genera estos métodos:
public void validateThis();
public void validate();
Después de editar una parte del árbol de contenido, podemos usar validateThis
para validar el objeto editado. Antes de empaquetar el árbol de contenido a un
documento XML, debemos usar validate para validar todo el árbol de
contenido.
44
3.4 Configuración de la aplicación JAXB
Ahora antes de poder usar JAXB para construir representaciones de datos o
trabajar con los datos, lo primero que necesitamos es crear una aplicación Java
que realice estas funciones. Para configurar nuestra aplicación JAXB hacemos
lo siguiente:
1. Creamos un fichero con extensión .java, ficheroapp.java.
2. Importamos los siguientes paquetes:




import java.io.*;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.marshal.*;
Estos dos últimos paquetes son parte del marco de trabajo de unión, que
define los métodos unmarshal, marshal, y validate.
3. Declaramos la clase ficheroapp de la siguiente manera:
public class ficheroapp {
}
4. Inicializamos los objetos del elemento raíz:
public static elemento_raíz obj1 = new elemento_raíz ();
public static elemento_raíz obj2 = new elemento_raíz ();
5. Finalmente dentro de la clase ficheroapp creamos nuestro método main:
public class ficheroapp {
public static void main(String args[]) throws Exception {
}
}
3.5 Construcción de Representaciones de Datos
Las clases Java que genera el compilador de esquema implementan y
extienden las clases e interfaces del marco de trabajo de unión. Este marco de
45
trabajo es el API de tiempo de ejecución que usan las clases generadas para
soportar tres operaciones primarias:
 Desempaquetar: el proceso de producir un árbol de contenidos desde
un documento XML.
 Validación: el proceso de verificar que la representación de objetos
Java está conforme a las reglas especificadas en el DTD.
 Empaquetar: el proceso de producir un documento XML desde objetos
Java.
Para realizar estas operaciones, cada clase generada contiene métodos para
empaquetar datos, validar contenidos, y extienden métodos del marco de
trabajo de unión que realizan el empaquetamiento.
Sin embargo, a lo que nos centraremos en este tema es a Crear Objetos de Java
a partir de Esquemas XML.
3.5.1 Desempaquetar (Construcción del árbol de Contenido)
Con los métodos unmarshal, podemos construir un árbol objetos Java desde
documentos XML que son ejemplares del esquema usado para generar las
clases. El árbol de objetos construido con JAXB se llama un árbol de
contenido. Cada objeto del árbol corresponde a un elemento del documento
46
XML. De forma semejante, cada objeto del árbol es un ejemplar de una clase
del conjunto de clases generadas.
También podemos construir un árbol de contenido ejemplarizando objetos de
las clases porque el árbol de contenido une el documento y las clases.
Consideremos un fichero llamado march.xml, que contiene transacciones
escritas en el mes de marzo. Para desempaquetar este documento XML en un
árbol de contenido en el fichero CheckbookApp.java, tenemos que hacer lo
siguiente:
1. Creamos un metodo llamado buildTrees:
public static void buildTrees() throws Exception {
}
2. En nuestro nuevo método leemos el fichero XML en un
FileInputStream:
File march = new File("march.xml");
FileInputStream fIn = new FileInputStream(march);
3. 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();
}
.
4. Llamamos al método buildTrees desde nuestro método main:
buildTrees();
En este punto, CheckbookApp genera un árbol de contenido desde march.xml.
3.5.1.1 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
47
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
tenemos que:
1. 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);
2. Seleccionamos el nombre de la entidad que recibe el cheque:
aprilRentCheck.setName(Gilchrest Gardens Manor);
3. 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.
4. 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 la
seccion 3.2.5.1 Métodos no Primitivos porque especificamos nuestro propio
formato de fechas, que es:MM-dd-yyyy.
5. 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.
6. Seleccionamos el estado del cheque a pendiente:
Pending pending = new Pending();
aprilRentCheck.setPendVoidClrd(pending);
48
7. 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 que representan
funciones comunes, implementan Entry. 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.
3.5.2 Validación
El proceso de desempaquetar realiza validación mientras está construyendo el
árbol de contenido, por eso es imposible desempaquetar un documento XML a
un árbol de contenido que es inválido con respecto al DTD. Podemos realizar
validación en cualquier momento después de haber construido el árbol de
contenido usando los métodos validate o validateThis en cada clase generada.
El método validate valida completamente el subárbol enraizado en el objeto
raíz sobre el que le hemos llamado; el método validateThis sólo valida un
objeto del árbol.
3.5.3 Trabajar con Datos (Acceso al árbol de Contenido)
Podemos trabajar con los objetos del árbol de contenido igual que lo haríamos
con cualquier objeto Java. De esta forma, JAXB proporciona un interfaz de
programación Java de datos XML, que podemos utilizar para integrar datos
XML en las aplicaciones Java para tener acceso al contenido del árbol,
utilizando las propiedades de las clases generadas.
Para proporcionar funcionalidades específicas de la aplicación, podemos
extender las clases en vez de sólo utilizarlas directamente. Por ejemplo,
además de acceder a un trozo de datos, también podríamos querer realizar
algún cálculo con los datos, para hacerlo podemos proporcionar estas
funcionalidades en una subclase de una clase derivada.
49
A continuación mostraremos cómo utilizar las clases para construir
representaciones de datos desde documentos XML y trabajar con los datos.
3.6 Creación de Objetos de Java a partir de Esquemas XML
Esta sección describe como JAXB representa el contenido de XML como
objetos en Java. Específicamente, trataremos la Unión de esquemas XML a
Identificadores Java.
Después de la lectura de esta sección, deberíamos sentirnos bastante cómodos
con JAXB ya que podremos generar clases Java JAXB de un esquema XML.
3.6.1 La Representación Java de Esquema XML
JAXB apoya la agrupación de clases generadas e interfaces en paquetes Java.
Un paquete comprende:
 Un nombre, que es sacado directamente del XML en el espacio de
nombre URI, o especificado por una personalización obligatoria del
XML .
 Un juego de interfaces Java que representan el contenido de los modelos
dentro del esquema.
 Un Juego de interfaces de elementos Java que representan declaraciones
de elemento que ocurren dentro del esquema.
 La claseAnObjectFactory contiene:
 Una instancia de métodos de caso para cada interfaz Java contenido
en el interfaz e interfaces de elementos Java dentro del paquete; por
ejemplo, considerando un contenido de interfaz Java llamado Foo,
el método derivado sería:
public Foo createFoo() throws JAXBException;
 Atributario de fábrica de caso Dinámico; crea una instancia del
interfaz especificado en el contenido del interfaz de java; por
ejemplo:
public Object newInstance(Class javaContentInterface)
throws JAXBException;
50
 getProperty y setProperty APIs que permite la manipulación de
propiedades proveer-especificaciones.
 Un Juego de typesafe enumerado de clases contiene paquetes javadoc.
3.6.2 Archivos Básicos
Cada directorio de ejemplo contiene varios archivos básicos:
 po.xsd es el esquema XML que usaremos como entrada al JAXB el
compilador obligatorio, y del cual derivara el esquema JAXB del que
las clases Java serán generadas.
 po.xml es el archivo que contiene el simple contenido XML.
 Main.java es la clase principal Java para cada ejemplo.
 build.xml es un archivo de proyecto Ant proveído para su conveniencia.
Ant se emplea para generar, compilar, y correr el esquema de clases
JAXB automáticamente.
 El archivo build.xml varía a través de los ejemplos.
 MyDatatypeConverter.java puede ser una clase Java usada para
proporcionar el acostumbrado tipo de dato para conversión.
 binding.xjb son un archivo de declaraciones externo obligatorio que es
pasado al compilador de uniones JAXB para personalizar la unión por
default JAXB.
 example.xsd es un archivo de esquema corto que contiene conflictos de
nombramiento deliberados.
3.6.3 Escribir un esquema de unión
Como vimos anteriormente, el esquema de unión contiene las instrucciones de
cómo unir un DTD a las clases. La Descripción de cómo realizar el esquema
de unión fue vista en la sección 3.2 Creación del esquema de unión.
3.6.4 Ejecutar el compilador de esquema
Enseguida debemos ejecutar el compilador de esquema con el DTD y el
esquema de unión como entradas, para generar el código fuente.
51
3.6.4.1 La configuración y la ejecución
El archivo build.xml incluido en cada directorio de ejemplo es un archivo del
proyecto
que, cuando corre, automáticamente realiza los siguientes pasos:
1. Actualiza su CLASSPATH para incluir lo necesario por esquema JAXB
que deriva las clases.
2. Corre la unión del compilador JAXB para generar clases java JAXB del
esquema fuente XML, po.xsd, y pone las clases en un paquete llamado
primer.po.
3. Genera la documentación API del sacado por esquema JAXB derivando
las clases que usan el instrumento Javadoc.
4. Compila las clases derivadas por el esquema JAXB.
5. Corre el Main para el ejemplo.
3.6.4.2 Opciones de la compilación de JAXB
El esquema JAXB del compilador de unión es localizado en el directorio
<JWSDP_HOME>/jaxb/bin. Hay dos escrituras en este directorio: xjc.sh
(Solaris/Linux) y xjc.bat (Windows).
Tanto xjc.sh como xjc.bat toman las mismas opciones de línea de mando.
Podemos mostrar instrucciones de uso rápidas invocando las escrituras sin
cualquier opción, o con el interruptor de ayuda. La sintaxis es como sigue:.
xjc [-options ...] <schema>
// <schema> uno o mas archivos de esquemas para compilar
52
3.6.4.3 Acerca de los esquemas de unión para Java en la compilación
Cuando usted corre el compilador de unión JAXB contra el po.xsd el esquema
XML usado en los ejemplos básicos, el compilador de unión JAXB genera un
paquete Java llamado primer.po conteniendo once clases, fabricación de un
total de doce clases en cada uno de los ejemplos básicos:
Estas clases y sus uniones específicas a la fuente XML el esquema para los
ejemplos básicos son descritas enseguida:
53
3.6.5 Ejemplo: Generar Clases desde un DTD
Como ejemplo de generación de clases desde un DTD, consideremos el
siguiente DTD, que se llama "priceList.dtd".
<!ELEMENT priceList (coffee)+ >
<!ELEMENT coffee (name, price)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT price (#PCDATA)>
El compilador de esquema JAXB es suficientemente poderoso como para
hacer asunciones razonables desde el DTD y el esquema de unión que
especifica sólo el elemento raíz del documento. Todo lo que necesitamos
especificar en el esquema de unión es que el elemento price es convertido a
una propiedad que devuelve y acepta un BigDecimal:
...
<element name="priceList" type="class" class="PriceList" root="true"/>
<element name="price" type="value" convert="BigDecimal"/>
<conversion name="BigDecimal" type="java.math.BigDecimal"/>
54
...
Desde este DTD y este esquema de unión, el compilador de esquema genera
una clase PriceList y una clase Coffee. La clase PriceList incluye un
constructor y una lista de propiedades, a las que está unida el elemento coffee.
La clase Coffee contiene un constructor y una propiedad para representar el
nombre del café y una propiedad para representar el precio. Los métodos para
acceder al precio son:
BigDecimal getPrice();
void setPrice(BigDecimal x);
Las dos clases también contienen métodos para desempaquetar, validar y
empaquetar. Recordemos que, Desempaquetar es el proceso de construir una
representación objeto del dato XML. La validación es el proceso de chequear
si el objeto está conforme a las especificaciones del DTD. Y Empaquetar es el
proceso de generar datos XML desde una representación objeto.
3.6.5.1 Construir Representaciones Objeto de Datos XML
Después de generar nuestras clases, podemos escribir aplicaciones Java que
las usen para construir representaciones objeto del documento XML que sean
válidos con respecto al DTD. Cada objeto corresponde a un elemento del
documento XML. De forma similar, cada objeto es un ejemplar de una clase
del conjunto de clases generadas. Como los objetos se mapean tanto al
documento como a las clases, tenemos dos formas diferentes de construir el
árbol de objetos Java: desempaquetando un documento XML válido, o
ejemplarizando objetos desde las clases. De esta forma, JAXB nos permite
procesar documentos XML existentes y crear nuevos datos XML
ejemplarizando las clases generadas.
Supongamos que tenemos este documento XML:
<priceList>
<coffee>
<name>Arabica</name>
<price>13.50</price>
</coffee>
<coffee>
<name>Mocha Java</name>
<price>11.95</price>
55
</coffee>
<coffee>
<name>Sumatra</name>
<price>12.50</price>
</coffee>
</priceList>
Para desempaquetar este documento XML, creamos un stream de entrada
desde él y llamamos al método unmarshal de la clase PriceList:
FileInputStream fis = new FileInputStream("priceList.xml");
PriceList myPrices = PriceList.unmarshal(fis);
Ahora tenemos un árbol de objetos Java con el objeto myPrices como la raíz
del árbol.
Supongamos que queremos crear nuestra propia lista de precios de cafés como
un documento XML. Primero creamos el árbol de objetos por ejemplarización
y luego empaquetamos el árbol en un documento XML. Para crear un árbol de
objetos usando ejemplarización, creamos un objeto PriceList, obtenemos la
lista de objetos Coffee desde él, creamos un nuevo objeto Coffee, y lo
añadimos a la lista:
PriceList myNewPrices = new PriceList();
List listOfCoffees = myNewPrices.getCoffees();
Coffee zCoffee = new Coffee();
zCoffee.setName("Zapoteca");
zCoffee.setPrice("15.00");
listOfCoffees.add(zCoffee);
Una vez que tenemos el dato XML en forma de un árbol de objetos, podemos
trabajar con los datos como con cualquier otro objeto Java. De esta forma,
JAXB proporciona un interface de programación Java para XML y nos
permite la integración de datos XML dentro de aplicaciones Java.
3.7 Creación de Esquemas XML a partir de Objetos de Java.
Como vimos en la sección 3.5 Construccion de Representaciones de Datos, al
proceso de producir un documento XML desde objetos java, se le llama
Empaquetar.
56
Tanto si construímos el árbol de contenido usando desempaquetamietno o
ejemplarización, podemos empaquetar el árbol a un nuevo documento XML
usando lo método marshal. Esto significa que JAXB también permite que
creemos nuevos documentos XML que son válidos con respecto al DTD
fuente. El proceso de empaquetado comprueba si el árbol de contenido se ha
validado antes de empaquetarlo en caso de que hayamos realizado cambios a
los objetos del árbol. Así pues, igual que es imposible desempaquetar un
documento inválido, es imposible empaquetar un árbol de contenido inválido.
La Figura siguiente ilustra dos formas para construir representaciones de
datos:
3.7.1 Validación del árbol de Contenido
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.
Utilicemos el ejemplo de la sección 3.5.1 Desempaquetar (Construcción del
árbol de Contenido)
Para validad ámbos árboles de contenido tenemos que:
57
1. Creamos un método llamado validateTrees:
public static void validateTrees() throws Exception {}
2. Dentro del método, llamamos a validate sobre marchTrans y
aprilTrans:
marchTrans.validate();
aprilTrans.validate();
3. Llamamos a validateTrees desde el método main:
validateTrees();
3.7.2 Empaquetar el árbol de Contenido a Documentos XML
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:
1. Creamos un nuevo método llamado marshalTrees:
public static void marshalTrees() throws Exception {}
2. 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);
3. Creamos el objeto OutputStream para enviarlo al método marshal:
FileOutputStream fMOut = new FileOutputStream(march_new);
FileOutputStream fAOut = new FileOutputStream(april_new);
4. Llamamos al método marshal sobre cada árbol:
try {
marchTrans.marshal(fMOut);
aprilTrans.marshal(fAOut);
}
finally {
fMOut.close();
fAOut.close();
58
}
5. 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.
59
Parte IV. CREANDO UNA APLICACIÓN JAXB
4.1 Consideraciones Previas
Primero que nada, debemos mencionar que software estamos utilizando y los
requerimientos para el desarrollo de los siguientes ejemplos.




Netbeans 5.5.1 (entorno IDE)
JAXB 2.0
Java Application Platform SDK
Máquina Virtual de Java (Jdk 1.6)
Advertencia: los ejemplos siguientes se recomienda ejecutarlos sobre estos
paquetes, si se implementan sobre otras versiones pueden no funcionar. Ya
que en nuestra recopilación de información tuvimos desagradables y
frustrantes experiencias por no mencionar lo anterior.
Además se recomienda no utilizar espacios en los nombres de los proyectos,
archivos o rutas a utilizar para evitar problemas.
4.2 EJEMPLO 1: Utilizando la operación unmarshal
Para el desarrollo de una aplicación java utilizando JAXB se requiere hacer
los siguientes pasos generales:




Crear un proyecto Aplicación Java en NetBeans.
Definir el esquema fuente.
Crear un documento XML que se valide con el esquema fuente.
Compilar el esquema con la aplicación del compilador JAXB (xjc.bat
en nuestro caso), el cual generará una carpeta conteniendo los archivos
.java por default en la ruta donde se encuentre el archivo xjc.bat.
 Añadir el paquete de los archivos generados por el compilador JAXB.
 Añadir los archivos .jar .
 Redefinir el método main para manipular las clases generadas
anteriormente
A continuación se describe detalladamente el proceso de creación,
compilación e implementación JAXB.
60
1. Creamos una aplicación java en NetBeans (menú File, New Proyect,
carpeta general, Java Aplication) y le ponemos el nombre prueba. No se
nos olvide cambiar la ruta de ubicación del proyecto a la unidad C, si no
eres un experto y quieres evitarte posibles complicaciones.
2. Ahora creamos un esquema el cual definirá dos tipos de listas principales:
una de negocios y otra de personas. Si no comprendes el esquema
consulta la sección 2.3 Xml Schema. Menu file, new_file, carpeta xml,
xml eschema.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xml.netbeans.org/schema/schema"
xmlns:tns="http://xml.netbeans.org/schema/schema"
elementFormDefault="qualified">
<xsd:element name="Root" type="tns:TipoRoot"/>
<xsd:complexType name="TipoRoot">
<xsd:sequence>
<xsd:element name="ListaPersona" type="tns:TipoListaPersona"/>
<xsd:element name="ListaNegocio" type="tns:TipoListaNegocio"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TipoListaPersona">
<xsd:sequence>
<xsd:element name="Persona" type="tns:TipoPersona" minOccurs="1"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TipoPersona">
<xsd:sequence>
<xsd:element name="nombre" type="xsd:string"/>
<xsd:element name="apellido" type="xsd:string"/>
<xsd:element name="fechaNacimiento" type="xsd:date"/>
<xsd:element name="id" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TipoListaNegocio">
<xsd:sequence>
<xsd:element name="Negocio" type="tns:TipoNegocio" minOccurs="1"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TipoNegocio">
<xsd:sequence>
61
<xsd:element name="nombre" type="xsd:string"/>
<xsd:element name="codigo" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
3. Creamos un documento xml (file, new file, carpeta xml, documento xml),
next (escribimos el nombre platillos), next (elegir la opcion xml-schemaconstrained-document), next (en schema url elegimos la direccion donde
se encuentra el eschema creado en el paso anterior en la opcion root
element) y por utimo escribimos el siguiente documento.
<?xml version="1.0" encoding="UTF-8"?>
<!-Document : f.xml
Created on : 7 de noviembre de 2007, 03:47 PM
Author : francisco
Description:
Purpose of the document follows.
-->
<Root xmlns='http://xml.netbeans.org/schema/schema'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation='http://xml.netbeans.org/schema/schema
file:/C:/Documents%20and%20Settings/francisco/prueba/src/f.xsd'>
<ListaPersona>
<Persona>
<nombre>Antonia</nombre>
<apellido>Lopez</apellido>
<fechaNacimiento>1887-10-12</fechaNacimiento>
<id>1</id>
</Persona>
<Persona>
<nombre>Poncho</nombre>
<apellido>Rojas</apellido>
<fechaNacimiento>1986-12-12</fechaNacimiento>
<id>1</id>
</Persona>
</ListaPersona>
<ListaNegocio>
<Negocio>
<nombre>Microsoft</nombre>
62
<codigo>0</codigo>
</Negocio>
<Negocio>
<nombre></nombre>
<codigo>IBM</codigo>
</Negocio>
</ListaNegocio>
</Root>
4. Ahora vamos a compilar el esquema anterior con el compilador de JAXB
para generar las clases .JAVA para empezar iniciamos la línea de
comandos cmd.exe, (inicio, ejecutar, y tecleamos cmd), una vez ahí,
cambiarse al directorio donde se encuentra instalada java plataforma
Application que en nuestro caso se encuentra en la ruta c:\Sun\SDK\bin\ .
una vez estando en esta carpeta ejecutamos la siguiente sentencia
(dependiendo de la ruta donde esté nuestro esquema). Para evitarnos
complicaciones, hemos copiamos el esquema fuente al directorio raíz, por
lo que la sentencia quedaría así:
xjc c:\f.xsd
Lo ejecutamos:
Algo que debemos mencionar es que el compilador enlazante permite o acepta
ciertas opciones adicionales al momento de generar las clases para nuestro
esquema; en específico, podemos observar la existencia de un parámetro “de
más”, -p ejemplo, donde -p nos ayuda a redefinir el paquete donde se van a
generar nuestras clases. El formato general de la instrucción xjc es:
xjc [-options ...] <schema>
Donde las opciones más comunes pueden ser:
63
Argumento opción
<schema>
-nv
Descripción
Uno o más archivos de esquemas a compilar
No realiza una validación estricta en el esquema de entrada.
Por default xjc realiza una validación esetricta de el esquema
fuente antes de procesarlo.Simplemente hace un poco menos
de validación
-extension
Por default, xjc estrictamente fuerza las reglas obtenidas de la
compatibilidad de la especificación de JAXB; usando el
cambio de extension puedes activar Extensiones de
vendedores.
-b <file>
Especifica uno o más archivos vinculantes externos para
procesar (cada archivo debe tener su propio –b switch).
Puedes tener un único archivo vinculante que contiene las
personalizaciones de múltiples esquemas, o puedes romper
las personalizaciones en múltiples archivos vinculantes.
Por default, xjc genera las clases de contenido en el directorio
actual. Usa esta opción para especificar un directorio
alternativo. El directorio debe de existir; xjc no creará el
directorio por ti.
Especifica donde encontrar los archivos de una clase
aplicación del cliente usadas por las personalizaciones
<jxb:javaType> y <xjc:superClass> .
-d <dir>
-classpath <arg>
-xml schema
-dtd
-help
Trata el esquema de entrada como un Schema W3C
XML(por default)
Trata el esquema de entrada como un XML DTD
Muestra este mensaje de ayuda
5. Como se muestra en la pantalla el compilador de JAXB ( xjc.bat ) genera
automáticamente los archivos .java los cuales se crearon en la carpeta
donde se encuentra el archivo de xjc, dentro de una carpeta de nombre
ejemplo. Continuando, vamos a anexar al proyecto los archivos generados
.java; para realizar esto existen varias formas, una de las más sencillas es
simplemente copiar la carpeta generada por la ejecución del comando xjc,
y pegarla en la ruta donde se creó nuestro proyecto en NetBeans, en la
carpeta scr.
64
6. Una vez agregados los .java vamos agregar los .jar, click derecho en la
carpeta librería elejimos la opcion ADD JAR\Folder nos vamos a la ruta
donde tenemos instalado el JDK 6.0 y agregamos los archivos .jar
mostrados a continuación :
7. Ahora viene lo interesante, utilizar las clases java generadas y realizar las
operaciones de unmarshall para este ejemplo (la página fuente se
encuentra en :).
package prueba;
import java.io.FileInputStream;
import java.util.Iterator;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
65
import ejemplo.TipoListaNegocio;
import ejemplo.TipoListaPersona;
import ejemplo.TipoNegocio;
import ejemplo.TipoPersona;
import ejemplo.TipoRoot;
public class Main {
/** Creates a new instance of Main */
public Main(){
try {
//"org.nextbeans.xml.schema.schema" -> Nombre del paquete donde
encontrar las clases generadas con el
//compilador de JAXB (xjc)
Unmarshaller
unmarshaller
=
JAXBContext.newInstance("ejemplo").createUnmarshaller();
//Es necesario el cast a JAXBElement y luego la aplicacion del metodo
getValue() porque el unmarshal no retorna el objeto de la clase TipoRoot.
//"xml/myFile.xml" archivo xml donde se encuentran los datos
TipoRoot root = (TipoRoot)((JAXBElement)unmarshaller.unmarshal( new
FileInputStream("src/f.xml"))).getValue();
TipoListaPersona tipoListaP = root.getListaPersona();
Iterator<TipoPersona> it = tipoListaP.getPersona().iterator();
System.out.println("*********Lista Persona*********");
while ( it.hasNext() ){
TipoPersona tp = it.next();
System.out.println("El nombre es == " + tp.getNombre());
System.out.println("El apellido es == " +tp.getApellido());
System.out.println("La fecha de nacimiento es ==
tp.getFechaNacimiento().toString() );
System.out.println("El id es == " + tp.getId());
}
System.out.println("********Lista Negocio**********");
TipoListaNegocio listaNegocio = root.getListaNegocio();
Iterator<TipoNegocio> itNg = listaNegocio.getNegocio().iterator();
while ( itNg.hasNext() ){
TipoNegocio tn = itNg.next();
System.out.println("El nombre es == " + tn.getNombre());
System.out.println("El codigo es == " + tn.getCodigo());
}
"
+
} catch (Exception ex) {
ex.printStackTrace();
}
66
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Main m = new Main();
}
}
8. Ejecutamos nuestra aplicación. Si todo se hizo correctamente debería de
aparecerte algo como lo que se muestra a continuación en la ventana
inferior del IDE NetBeans (ventana de salida).
init:
deps-jar:
Compiling 1 source file to C:\Documents and
Settings\francisco\prueba\build\classes
compile:
*********Lista Persona*********
El nombre es == Antonia
El apellido es == Lopez
La fecha de nacimiento es == 1887-10-12
El id es == 1
El nombre es == Poncho
El apellido es == Rojas
La fecha de nacimiento es == 1986-12-12
El id es == 1
********Lista Negocio**********
El nombre es == Microsoft
El codigo es == 0
El nombre es == IBM
El codigo es == 1
debug:
BUILD SUCCESSFUL (total time: 2 seconds)
4.3 EJEMPLO 2: Utilizando la operación marshal
Una vez que tenemos el resultado de los pasos mencionados
previamente para el ejemplo anterior, procedemos a utilizar el objeto
Marshal para poder realizar la operación de empaquetación u
organización de un árbol de contenido Java en una salida XML.
67
Para hacer lo anterior solo modificamos el constructor Main(), y
hacemos que asemeje a lo siguiente:
//Además de las sentencias import que ya tenemos agregamos las siguientes
import ejemplo.ObjectFactory;
import javax.xml.bind.Marshaller;
//........ lo que ya estaba
public Main(){
try {
//"org.nextbeans.xml.schema.schema" -> Nombre del paquete donde
//encontrar las clases generadas con el
//compilador de JAXB (xjc)
Unmarshaller
unmarshaller
=
JAXBContext.newInstance("ejemplo").createUnmarshaller();
//Es necesario el cast a JAXBElement y luego la aplicacion del metodo
getValue() porque el unmarshal no retorna el objeto de la clase TipoRoot.
//"xml/myFile.xml" archivo xml donde se encuentran los datos
TipoRoot root = (TipoRoot)((JAXBElement)unmarshaller.unmarshal( new
FileInputStream("src/f.xml"))).getValue();
//Comenzamos con la operación de unmarshal
JAXBContext jaxbContext = JAXBContext.newInstance("ejemplo");
Marshaller marshaller = jaxbContext.createMarshaller();
ObjectFactory factory = new ObjectFactory();
JAXBElement<TipoRoot> er = factory.createRoot(root);
marshaller.setProperty("jaxb.formatted.output",Boolean.TRUE);
marshaller.marshal(er, System.out);
} catch (Exception ex) {
ex.printStackTrace();
}
}
Si lo hiciste correctamente y si no hay algún otro detalle, al ejecutar el
proyecto te debería de aparecer en la ventana de salida lo siguiente:
init:
deps-jar:
Compiling 1 source file to C:\Documents and
Settings\francisco\prueba\build\classes
compile:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root xmlns="http://xml.netbeans.org/schema/schema">
68
<ListaPersona>
<Persona>
<nombre>Antonia</nombre>
<apellido>Lopez</apellido>
<fechaNacimiento>1887-10-12</fechaNacimiento>
<id>1</id>
</Persona>
<Persona>
<nombre>Poncho</nombre>
<apellido>Rojas</apellido>
<fechaNacimiento>1986-12-12</fechaNacimiento>
<id>1</id>
</Persona>
</ListaPersona>
<ListaNegocio>
<Negocio>
<nombre>Microsoft</nombre>
<codigo>0</codigo>
</Negocio>
<Negocio>
<nombre>IBM</nombre>
<codigo>1</codigo>
</Negocio>
</ListaNegocio>
</Root>
debug:
BUILD SUCCESSFUL (total time: 2 seconds)
4.4 EJEMPLO 3: Definiendo un árbol de contenido y
transformarlo en formato XML
En este sencillo ejemplo vamos a seguir trabajando con el proyecto creado
anteriormente. Vamos a utilizar las clases generadas por el compilador JAXB
para poder construir manualmente un árbol de contenido y posteriormente
transformar este árbol en formato XML y visualizarlo en la salida
estándar(generalmente la pantalla).
Abrimos nuestro proyecto prueba, y nos posicionamos en el constructor de la
clase Main().
Luego modificamos el código de tal forma que quede similar al siguiente:
public Main(){
69
try {
//Creamos un objeto JAXBContext
JAXBContext jaxbContext = JAXBContext.newInstance("ejemplo");
//Creamos un objeto de la clase Marshaller y ObjectFactory para poder
//crear los elementos individuales del árbol java
Marshaller marshaller = jaxbContext.createMarshaller();
ObjectFactory factory = new ObjectFactory();
//Definimos las variables que contendrán los datos de una persona y un negocio
TipoNegocio tn = factory.createTipoNegocio();
TipoPersona tp = factory.createTipoPersona();
//Definimos los datos de el negocio
tn.setNombre("ALICA");
tn.setCodigo(3);
//Definimos los datos de la persona
tp.setNombre("CINTHIA");
tp.setId(5);
tp.setApellido("MATA");
//Creamos una Lista de personas y una lista de negocios
TipoListaNegocio tln = factory.createTipoListaNegocio();
TipoListaPersona tlp = factory.createTipoListaPersona();
//Agregamos a las persona y al negocio antes especificado a sus correspondientes
// listas
tln.getNegocio().add(tn);
tlp.getPersona().add(tp);
//Creamos una instancia del elemento TipoRoot
TipoRoot r= factory.createTipoRoot();
//Agregamos al árbol de contenido las listas de negocios y personas
r.setListaNegocio(tln);
r.setListaPersona(tlp);
//Creamos un elemento JAXB para poder transformar el árbol de contenido ya
//generado
JAXBElement<TipoRoot> er = factory.createRoot(r);
//Establecemos el formato de salida y realizamos la operación de marshal
marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
marshaller.marshal(er, System.out);
} catch (Exception ex) {
ex.printStackTrace();
70
}
}
El resultado de la ejecución del proyecto:
4.5 EJEMPLO 4: Generando un esquema XML a partir de
clases java
JAXB 2.0 soporta las transformaciones bidireccionales de los documentos
XML y árboles de contenido Java. Además, dentro de la carpeta bin (donde se
encuentra el archivo del comando, xjc.bat) existe un archivo el cual nos puede
ser de gran utilidad, ya que puede generar, a la inversa del xjc, esquemas XML
a partir de clases java. El archivo-comando que hace posible esto es el
schemagen.bat, el cual recibe como parámetro de entrada la ruta de la clase
raíz java, de la cual generará el esquema.
71
Recordemos que anteriormente generamos el conjunto de clases java a partir
de un esquema, ahora vamos a hacer lo inverso con el comando
schemagen.bat, pasándole como argumento la ruta del archivo TipoRoot.java:
Una vez hecho lo anterior checamos que nos haya creado el esquema en la
ruta donde tenemos el archivo schemagen.bat. Obtenemos un archivo
denominado shcema1.xsd que contiene lo siguiente:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="TipoRoot">
<xs:sequence>
<xs:element name="ListaPersona" type="TipoListaPersona"/>
<xs:element name="ListaNegocio" type="TipoListaNegocio"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TipoListaPersona">
<xs:sequence>
<xs:element name="Persona" type="TipoPersona" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TipoPersona">
<xs:sequence>
<xs:element name="nombre" type="xs:string"/>
<xs:element name="apellido" type="xs:string"/>
<xs:element name="fechaNacimiento" type="xs:anySimpleType"/>
<xs:element name="id" type="xs:int"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TipoListaNegocio">
<xs:sequence>
<xs:element name="Negocio" type="TipoNegocio" maxOccurs="unbounded"/>
</xs:sequence>
72
</xs:complexType>
<xs:complexType name="TipoNegocio">
<xs:sequence>
<xs:element name="nombre" type="xs:string"/>
<xs:element name="codigo" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
73
ANEXOS
Proceso de Instalación de JAXB 2.0
Los ejemplos de esta obra son para trabajar JAXB 2.0 junto con
5.5.1
NetBeans
Software necesario para instalar el JAXB




Plataforma jdk1.6.0_02
jwsdp-2_0-windows-i586 paquete WSDP
java_app_platform_sdk-5_02-windows-nojdk
tomcat 5.0 solo funciona con esta versión no se instala se
descomprime en c:\.
Una ves que se cuente con los anteriores software lo que hay que hacer es
seguir los pasos.
1. Instalar primero la plataforma jdk1.6.0_02 una vez instalada instalar el
java_app_platform_sdk-5_02-windows-nojdk ambas instalaciones no
tienen ninguna complicación
Nota: si ya tienes instalado el netbeans ya tienes instalada la plataforma
jdk-.
2. Ejecuta el paquete Jwsdp-2_0.
74
3. Aparece el asistente de la instalación presione siguiente (next).
4. En la siguiente ventana acepta la licencia de uso y presiona siguiente
para continuar.
5. En la cuarta ventana elige la maquina virtual sobre la cual el WSDP
ejecutara la busca por default. En caso de no tenerla no se podrá seguir
con la instalación.
6. Antes de continuar con la instalación debemos descomprimir el archivo
tomcat 5.0 en la unidad c:\ para evitar complicaciones.
75
7. En la ventana de instalación click en browse seleccionar la ruta de la
carpeta de tomcat 5.0 y click siguiente.
8. En tipo de instalación seleccionar instalación typical.
9. Definimos el usuario tomcat.
76
Nota: este usuario debe estar definido en un archivo de tomcat de
nombre manager el cual esta dentro de la carpeta server:
<tomcat-users>
<user name="tomcat" password="tomcat" roles="tomcat" />
10. En este paso hay que crear la siguiente ruta
c:\archivo de programas\java\jdk1.6.0_02\jre\lib\endorsed y en esta
ubicación hay que copiar los archivos que se encuentran en esta otra
ubicación c:\sun\jwsdp-2.0\jaxp\lib\endorsed.
11. En la instalación click en siguiente y por último finalizar.
77
INDICE
PARTE I. INTRODUCCIÓN
1
1.1 ¿Qué es JAXB?
1
1.2 Características de JAXB
1.2.1 Las aplicaciones JAXB usan Tecnología Java y XML
1.2.2 Las Aplicaciones JAXB son Rápidas
1.2.3 Las Aplicaciones JAXB son Fáciles de Crear y de Usar
1.2.4 Las Aplicaciones JAXB Pueden Convertir Datos
1.2.5 Las Aplicaciones JAXB Pueden Personalizarse
1.2.6 Las Aplicaciones JAXB son Extensibles
1
2
3
4
4
5
6
1.3 Arquitectura de JAXB
6
1.4 El proceso de vinculación de JAXB
8
1.5 Framework vinculante JAXB
1.5.1 El paquete javax.xml.bind
1.5.1.1 Desorganización
1.5.1.2 La Organización
1.5.1.3 La Validación
10
10
11
12
12
1.6 Versiones
13
PARTE II. DOCUMENTOS XML
14
2.1 ¿Qué es XML?
14
2.2 Definición de Tipo de Documento (DTD)
2.2.1 Declaración de Tipo de Documento
2.2.2 Declaración de Elementos
2.2.2.1 Elementos vacíos
2.2.2.2 Elementos con sólo elementos
2.2.2.3 Elementos de Contenido Mixto
2.2.2.4 Elementos ANY
2.2.3 Declaración de Atributos
2.2.3.1 Atributos CDATA y NMTOKEN
2.2.3.2 Atributos enumerados y notaciones
2.2.3.3 Atributos ID e IDREF
15
16
17
17
18
22
22
23
24
24
25
2.3 XML Schema
2.3.1 Estructura Mínima de un Esquema
2.3.2 Tipos de Datos
2.3.3 Diagrama de los Tipos de Datos que manejan los Schemas
25
26
27
28
2.4 Documento XML
2.4.1 Ejemplo: Diferencias entre DTD y Schemas
28
29
PARTE III. ACCESO A UN DOCUMENTO XML
3.1 Construcción de una aplicación JAXB
31
31
78
3.2 Creación del Esquema de Unión
3.2.1 Declaración de Unión de Elementos
3.2.2 Declaración de Unión de Atributos
3.2.3 Declaración de Unión de Contenido
3.2.4 Ejemplo: Esquema de Unión para book.dtd.
3.2.5 Especificando Tipos
3.2.5.1 Especificar Tipos No Primitivos
3.2.5.2 Especificar Tipos Primitivos
3.2.6 Creación de Tipos de Datos Enumerados
3.2.7 Creación de interfaces
32
33
34
35
37
38
38
40
41
42
3.3 Generación de los Ficheros Fuente de Java
43
3.4 Configuración de la aplicación JAXB
45
3.5 Construcción de Representaciones de Datos
3.5.1 Desempaquetar (Construcción del árbol de Contenido)
3.5.1.1 Ejemplarización
3.5.2 Validación
3.5.3 Trabajar con Datos (Acceso al árbol de Contenido)
45
46
47
49
49
3.6 Creación de Objetos de Java a partir de Esquemas XML
3.6.1 La Representación Java de Esquema XML
3.6.2 Archivos Básicos
3.6.3 Escribir un esquema de unión
3.6.4 Ejecutar el compilador de esquema
3.6.4.1 La configuración y la ejecución
3.6.4.2 Opciones de la compilación de JAXB
3.6.4.3 Acerca de los esquemas de unión para Java en la compilación
3.6.5 Ejemplo: Generar Clases desde un DTD
3.6.5.1 Construir Representaciones Objeto de Datos XML
50
50
51
51
51
52
52
53
54
55
3.7 Creación de Esquemas XML a partir de Objetos de Java.
3.7.1 Validación del árbol de Contenido
3.7.2 Empaquetar el árbol de Contenido a Documentos XML
56
57
58
PARTE IV. CREANDO UNA APLICACIÓN JAXB
60
4.1 Consideraciones Previas
60
4.2 EJEMPLO 1: Utilizando la operación unmarshal
60
4.3 EJEMPLO 2: Utilizando la operación marshal
67
4.4 EJEMPLO 3: Definiendo un árbol de contenido y transformarlo en formato XML
69
4.5 EJEMPLO 4: Generando un esquema XML a partir de clases java
71
ANEXOS
Proceso de Instalación de JAXB 2.0
74
74
79