Apuntes de XML

83
Apuntes de XML Autor: Diego Arranz Hernando Introducción o Motivación HTML y XML ¿Para qué sirve XML? Principales usos o Terminología o Cuadro del XML y alcance del curso Creación de documentos XML o Sintaxis Un ejemplo completo Reglas básicas Otras construcciones Espacios de nombres Cabecera Terminología o Reglas de diseño Restringir documentos XML o ¿Por qué restringir los datos? o DTD's Un ejemplo de DTD Elementos Atributos Declaración DOCTYPE Entidades o Esquemas XML Esquemas XML vs DTDs Un primer ejemplo Características Espacios de nombres Uso desde un documento Más estructuras Tipos Atributos Importar esquemas Un ejemplo completo Otras formas de construir esquemas XML Presentación y transformación de documentos XML o Hojas de estilo CSS CSS con XML Un ejemplo o Lenguaje XSLT Introducción a XSLT Ventajas y desventajas Formas de uso Un ejemplo de hoja Características XPath Crear elementos Ordenaciones Manipulación de XML desde programas Java o Analizar XML con SAX Introducción a SAX El analizador SAX Un primer ejemplo

Transcript of Apuntes de XML

Page 1: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Introducción o Motivación

HTML y XML ¿Para qué sirve XML? Principales usos

o Terminología o Cuadro del XML y alcance del curso

Creación de documentos XML o Sintaxis

Un ejemplo completo Reglas básicas Otras construcciones Espacios de nombres Cabecera Terminología

o Reglas de diseño Restringir documentos XML

o ¿Por qué restringir los datos? o DTD's

Un ejemplo de DTD Elementos Atributos Declaración DOCTYPE Entidades

o Esquemas XML Esquemas XML vs DTDs Un primer ejemplo Características Espacios de nombres Uso desde un documento Más estructuras Tipos Atributos Importar esquemas Un ejemplo completo Otras formas de construir esquemas XML

Presentación y transformación de documentos XML o Hojas de estilo CSS

CSS con XML Un ejemplo

o Lenguaje XSLT Introducción a XSLT Ventajas y desventajas Formas de uso Un ejemplo de hoja Características XPath Crear elementos Ordenaciones

Manipulación de XML desde programas Java o Analizar XML con SAX

Introducción a SAX El analizador SAX Un primer ejemplo El manejador de contenido Los métodos del manejador Código portable Validación Otro ejemplo

o Manipular XML con DOM Introducción a DOM El analizador DOM Un primer ejemplo

Page 2: Apuntes de XML

Manipulación del árbol Código portable Otro ejemplo Más formas de manipular el árbol Crear documentos Imprimir documentos Un ejemplo Modificar documentos

XML y las bases de datos o Generar XML a partir de consultas o Transferir datos desde documentos XML o Herramientas o XML como almacén de datos

Otros temas de interés o XLink o JDOM

Otra API más Ventajas y desventajas Una API en desarrollo

o Marcos de publicación web El problema Soluciones con tecnología conocida Contenido y presentación La solución: marcos de publicación web Ventajas Un ejemplo de marco de publicación: Cocoon

Servicios web o Introducción o Terminología

Tecnologías estándar APIs Java

o JAXR Registros Introducción a JAXR Un cliente JAXR

o JAXM Mensajes SOAP Introducción a JAXM Ejemplos

o JAX-RPC Introducción Un ejemplo

Bibliografía recomendada o En inglés o En castellano

Enlaces recomendados o Generales o Introducción o Creación de documentos XML o Restricción de documentos XML o Presentación y transformación de documentos XML o Manipulación de XML desde programas Java o XML y las bases de datos o Otros temas de interés o Servicios web

Material utilizado o Bibliografía o Enlaces o Herramientas

Ejercicios o Creación de documentos XML

Enunciado Solución

Page 3: Apuntes de XML

o DTDs Enunciado Solución

o Esquemas XML Enunciado Solución

o XSLT Enunciado Solución

o SAX Enunciado Solución

o DOM Enunciado Solución

o DOM (otro) Enunciado Solución

Page 4: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Introducción o Motivación

HTML y XML ¿Para qué sirve XML? Principales usos

o Terminologíao Cuadro del XML y alcance del curso

Introducción

 Motivación

 HTML y XML

Una buena forma de entender en un primer vistazo qué es el lenguaje XML es compararlo con el sobradamente conocido lenguaje HTML.

Veamos primero un trozo de código HTML:

<h1> Comedor</h1><ul> <li> <b>Mesa redonda de madera de arce</b>. El fabricante es <i>Muebles Albacete</i> y su precio 40000. </li> <li> <b>Dos sillas de madera de arce</b>, de excelente calidad, con un coj&iacute;n azul cada una. </li> <li> <b>3 sillas de madera de roble</b>. </li></ul>

Y ahora un trozo de código XML equivalente:

<comedor> <mesa tipo="redonda" madera="arce"> <fabricante>Muebles Albacete</fabricante> <precio>40000</precio> </mesa> <silla madera="arce"> <cantidad>2</cantidad> <calidad>excelente</calidad> <cojin incluido="sí"> <color>azul</color> </cojin> </silla> <silla madera="roble"> <cantidad>3</cantidad> <calidad>normal</calidad> </silla></comedor> Lo fundamental:

o HTML: orientado a la presentación de datos. o XML: orientado a los datos en sí mismos. o La principal ventaja de XML es que cualquier programa informático trabajará mejor

con datos en XML.

Page 5: Apuntes de XML

HTML es un lenguaje de presentación. Define un conjunto de etiquetas y atributos válidos, una utilización válida de estos elementos y un significado visual para cada elemento del lenguaje.

XML no define las etiquetas ni cómo se utilizan, sólo define unas pocas reglas sintácticas para crear documentos. Por eso XML es un metalenguaje (un lenguaje para definir otros lenguajes).

¿Sustituye XML a HTML? No, pues sirven para cosas distintas: HTML para presentar información en páginas web y XML para representar e intercambiar datos, independientemente de su presentación. XML y HTML son complementarios.

 ¿Para qué sirve XML? Principales usos

XML aplicado a los sitios web: permite separar contenido y presentación, y que los mismos datos se puedan mostrar de varias formas distintas sin demasiado esfuerzo.

XML para la comunicación entre aplicaciones: representación de los datos muy simple, fácil de transmitir por la red, estándar. En los últimos tiempos este uso se está haciendo muy popular con el surgimiento de los Servicios web.

XML para la configuración de programas: representación de los datos simple y estándar, en contraposición con los crípticos formatos propietarios.

 Terminología

XML: Es sólo el metalenguaje sobre el que se construye todo. Por sí mismo tiene un valor limitado. Cuando se habla de XML, normalmente no se refiere sólo al lenguaje XML, sino también a todos los lenguajes y herramientas relacionadas.

DTD: Lenguaje para establecer restricciones en los documentos XML. Esquema XML: Otro lenguaje para restringir los documentos XML, que soluciona diversos

problemas de las DTDs. XSLT: Lenguaje para transformar documentos de un formato XML a otro formato (HTML, otro

vocabulario XML, texto plano, PDF, etc.) SAX: API que permite recorrer secuencialmente un documento XML, y responder a una serie de

eventos. DOM: API que proporciona una representación de los documentos XML en forma de árbol,

permitiendo el recorrido y manipulación de los datos. XHTML: Reformulación del HTML como formato de datos XML. SOAP: Lenguaje que especifica la forma de enviar contenido XML a través de Internet. XML-RPC: Mecanismo para invocación remota de procedimientos (métodos) utilizando XML

como forma de comunicación. Servicios web: Aplicaciones que se publican en la web y pueden ser accedidas de forma

estándar desde cualquier lugar de Internet.

 Cuadro del XML y alcance del curso

Núcleo: Se tratará en detalle el lenguaje XML. Se verán los aspectos más importantes de los lenguajes DTD, esquemas XML y XSLT. Se introducirá XLink.

APIs Básicas: Se verá en detalle cómo trabajar con SAX y DOM, utilizando como lenguaje Java. Servicios web: Se explicará el por qué de su importancia y se detallarán las tecnologías

asociadas con ellos. APIs para servicios web: Se realizará una introducción a una serie de APIs para trabajar con

servicios web desde Java (JAXR, JAXM, JAX-RPC). Otras aplicaciones y tecnologías: Se verán por encima algunos otros temas relacionados con

XML: o Aplicación de hojas CSS a documentos XML o Relación de XML con las bases de datos o Alternativa a la API DOM para Java: JDOM o Marcos de publicación web

Al final de este documento se recoge una bibliografía recomendada y numerosos enlaces de Internet para poder profundizar en cualquiera de los temas tratados en el curso.

Apuntes de XMLAutor: Diego Arranz Hernando

Creación de documentos XML o Sintaxis

Un ejemplo completo

Page 6: Apuntes de XML

Reglas básicas Otras construcciones Espacios de nombres Cabecera Terminología

o Reglas de diseño

Creación de documentos XML

 Sintaxis

 Un ejemplo completo

Ejemplo completo de documento XML:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?><?xml-stylesheet href="librohtml.xsl" type="text/xsl"?><?xml-stylesheet href="librowml.xsl" type="text/xsl" media="wap"?><?cocoon-process type="xslt"?>

<!-- Referencia la DTD --><!DOCTYPE Libro SYSTEM "libro.dtd">

<!-- Comienza el contenido --><Libro xmlns="http://www.mislibros.com/libros/javaxml"

xmlns:Catalogo="http://www.mislibros.com/catalogo">

<Titulo>Java y XML</Titulo> <Catalogo:Seccion>Programación</Catalogo:Seccion> <Catalogo:SubSeccion>XML</Catalogo:SubSeccion> <Contenido>

<Capitulo materia="XML"> <Tema>Introducción</Tema> <subcapitulo1 apartados="7">Qué es</subcapitulo1> <subcapitulo1 apartados="3">Cómo se usa</subcapitulo1> </Capitulo>

<Capitulo materia="XML"> <Tema>Creando XML</Tema> <subcapitulo1 apartados="0">Un documento XML</subcapitulo1> <subcapitulo1 apartados="2">La cabecera</subcapitulo1> <subcapitulo1 apartados="6">El contenido</subcapitulo1> </Capitulo>

<Capitulo materia="Java"> <Tema>Analizando XML</Tema> <subcapitulo1 apartados="3">Preparación</subcapitulo1> <subcapitulo1 apartados="3" dificil="si">SAX</subcapitulo1> <subcapitulo1 apartados="9" dificil="si">Manejadores</subcapitulo1> <subcapitulo1 apartados="0">Una forma mejor de cargar el analizador</subcapitulo1> </Capitulo>

<Separacion/>

<Capitulo materia="Java"> <Tema>JDOM</Tema> <subcapitulo1 apartados="2">Introducción</subcapitulo1> <subcapitulo1 apartados="4" dificil="si">DOM&amp;JDOM</subcapitulo1> </Capitulo> </Contenido>

<Compra> <![CDATA[

Page 7: Apuntes de XML

<Paso 1>Encontrar una librería. <Paso 2>Encontrar el libro. <Paso 3>Comprar el libro. ]]> </Compra> <Copyright>&OReillyCopyright;</Copyright> </Libro>

 Reglas básicas

Hay dos tipos de construcciones: el marcado (entre <...> ó &...; ) y los datos de carácter (todo lo demás).

Todo documento XML se compone de elementos. Cada elemento está delimitado por una etiqueta de comienzo y otra de fin, a no ser que sea vacío. Los elementos vacíos constan de una única etiqueta. Los nombres de las etiquetas son arbitrarios y no pueden contener espacios.

Siempre hay un elemento raíz, cuya etiqueta de inicio ha de ser la primera de todas y la de cierre la última de todas.

Cada elemento puede contener datos de carácter, elementos, ambas cosas a la vez o puede estar vacío.

No se puede mezclar la anidación de las etiquetas: los elementos deben abrirse y cerrarse por orden.

Los elementos pueden tener atributos (propiedades) que nos ofrecen información sobre ellos. Los valores de los atributos deben ir entrecomillados. Tanto atributos como valores son arbitrarios.

Mayúsculas y minúsculas no son intercambiables. El espacio en blanco es libre, se puede utilizar para leer mejor el documento.

 Otras construcciones

Se pueden utilizar comentarios, que el analizador no tratará, en cualquier sitio excepto dentro de las declaraciones, etiquetas y otros comentarios.

Las secciones CDATA sirven para introducir texto que el analizador tendrá en cuenta como datos de carácter, sin interpretarlo como XML.

Las entidades predefinidas permiten incluir ciertos caracteres sin que sean tomados como XML:

o &amp; para el & o &lt; para el < o &gt; para el > o &apos; para el ' o &quot; para el "

Podemos definir nuestras propias entidades, lo veremos con las DTDs.

 Espacios de nombres

Los espacios de nombres sirven para evitar las colisiones entre elementos del mismo nombre, y en general, para distinguir los distintos grupos de elementos en un mismo documento.

Cada espacio de nombres se asocia con una URL, que sólo sirve como identificador único y no tiene por qué ser válida.

 Cabecera

La cabecera, que es opcional aunque recomendable, da información sobre cómo manejar el documento a los analizadores y otras aplicaciones. Puede contener:

o Una declaración XML para el analizador, con la versión, juego de caracteres utilizado, y una indicación de si el documento es o no autónomo (si requiere o no otros documentos).

o Instrucciones de proceso para otras aplicaciones. o Una declaración DOCTYPE, que referencia a la DTD que restringe el documento.

 Terminología

Page 8: Apuntes de XML

Cuando un documento cumple con las reglas sintácticas que hemos descrito, se le denomina documento bien formado.

Un documento válido, además de ser bien formado, cumple las restricciones que le impone una DTD o un esquema XML.

 Reglas de diseño

El diseño de la estructura de un documento XML no es una tarea trivial. Depende de un buen análisis del problema concreto a resolver (cómo se va a utilizar el documento), lo cual queda fuera del alcance de este curso. No obstante, se ofrecen a continuación algunas reglas prácticas.

Siempre que sea posible, usar una DTD o esquema existente. Nos ahorramos diseñar los documentos XML y posibilita el intercambio de datos con otros que utilicen la DTD o esquema.

La principal decisión es utilizar para los datos de los elementos subelementos o atributos. Por ejemplo:

<diapositiva><título>Aquí el título...</título>

</diapositiva>

<diapositiva título="Aquí el título...">...

</diapositiva> Hay una serie de criterios:

o Si el dato contiene subestructuras: elemento. o Si el dato es de gran tamaño: elemento. o Si el dato cambia frecuentemente: elemento. o Si el dato es de pequeño tamaño, y raramente cambia: normalmente, atributo. o Si el dato sólo puede tener unos cuantos valores fijos: atributo. o Si el dato se va a mostrar a un usuario o aplicación: elemento. Si el dato guía el

procesamiento del XML pero no se va a mostrar: atributo.

Page 9: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Restringir documentos XML o ¿Por qué restringir los datos?o DTD's

Un ejemplo de DTD Elementos Atributos Declaración DOCTYPE Entidades

o Esquemas XML Esquemas XML vs DTDs Un primer ejemplo Características Espacios de nombres Uso desde un documento Más estructuras Tipos Atributos Importar esquemas Un ejemplo completo Otras formas de construir esquemas XML

Restringir documentos XML

 ¿Por qué restringir los datos?

La primera razón es que podemos realizar comprobaciones estrictas sobre los datos, para asegurarnos de que tienen un formato válido de acuerdo a lo que queremos.

Otra razón es la documentación: no siempre estará claro para cualquier persona el significado de un determinado documento XML:

<?xml version="1.0"?><pagina> <pantalla> <nombre>Compras</nombre> <color>#CC9900</color> <fuente>Arial</fuente> </pantalla> <contenido> <p>Aqui un monton de contenido</p> </contenido></pagina>

<?xml version="1.0"?><pagina> <pantalla> <nombre>Compras</nombre> <color>#CC9900</color> <fuente>Arial</fuente> </pantalla> <pantalla> <nombre>Mensajes</nombre> <color>#9900FF</color> <fuente>Arial</fuente> </pantalla> <pantalla> <nombre>Noticias</nombre> <color>#EECCEE</color> <fuente>Helvetica</fuente> </pantalla> <contenido>

Page 10: Apuntes de XML

<p>Aqui un monton de contenido</p> </contenido></pagina> Viendo el primer ejemplo podemos pensar en que describe información de una pantalla para

determinado cliente. Viendo el segundo, la interpretación cambia. En realidad, son varios enlaces a las pantallas disponibles.

Las DTDs y los esquemas XML aclaran situaciones de este tipo. Otra ventaja de los mecanismos de restricción es que no hay que cambiar el código de las

aplicaciones si las restricciones cambian (sólo las DTDs o esquemas que sean). Como desventaja, la validación supone tiempo adicional de proceso. Una solución posible

para algunos sistemas es validar en la fase de desarrollo y pruebas y quitar la validación al implantar el sistema.

 DTD's

 Un ejemplo de DTD

Para utilizar una DTD como mecanismo de restricción, se especifica lo siguiente en el documento XML:

<!DOCTYPE Libro SYSTEM "libro.dtd">

DTD para el ejemplo del libro:

<!ELEMENT Libro (Titulo, Catalogo:Seccion, Catalogo:SubSeccion, Contenido, Compra, Copyright)><!ATTLIST Libro xmlns CDATA #REQUIRED xmlns:Catalogo CDATA #REQUIRED><!ELEMENT Titulo (#PCDATA)><!ELEMENT Catalogo:Seccion (#PCDATA)><!ELEMENT Catalogo:SubSeccion (#PCDATA)><!ELEMENT Contenido ((Capitulo+)|(Capitulo+, Separacion?)+)><!ELEMENT Capitulo (Tema, Seccion+)><!ATTLIST Capitulo materia (XML|Java) "Java"><!ELEMENT Tema (#PCDATA)><!ELEMENT Seccion (#PCDATA)><!ATTLIST Seccion apartados CDATA #REQUIRED dificil (si|no) "no"><!ELEMENT Separacion EMPTY><!ELEMENT Compra (#PCDATA)><!ELEMENT Copyright (#PCDATA)><!ENTITY OReillyCopyright SYSTEM "copyright.txt">

 Elementos

Los elementos permitidos se especifican con ELEMENT, seguido del nombre y el tipo del elemento.

Los elementos que se pueden anidar dentro de otros se especifican entre paréntesis y separados por comas. Importa el orden.

El tipo menos restrictivo es ANY, que permite cualquier contenido para un elemento. Para datos de tipo texto, se usa #PCDATA. Para elementos vacíos, EMPTY. Modificadores de número de ocurrencias:

o ?: Una vez o ninguna o +: Al menos una vez o *: Cualquier número de veces o ninguna o (nada): Exactamente una vez

Para opciones alternativas: separar con |.

Page 11: Apuntes de XML

 Atributos

Los atributos permitidos para un elemento se especifican con ATTLIST y el nombre del elemento seguido de los nombres de los atributos, con un tipo y modificador obligatorios.

El tipo del atributo puede ser CDATA para cualquier valor, o una enumeración de los valores permitidos.

Otros posibles tipos son: o NMTOKEN para restringir el valor a un nombre XML válido (es decir, que empiece con

una letra o guión de subrayado y contenga sólo letras, números, guiones de subrayado, guiones y puntos, sin espacios)

o ID, además de las restricciones que impone NMTOKEN, impone que el valor sea único en todo el documento.

El modificador puede ser #REQUIRED para atributos obligatorios, #IMPLIED para opcionales, o #FIXED valor_fijo para valores fijos. También puede ser un valor por defecto.

 Declaración DOCTYPE

SYSTEM sirve para DTDs "personales". Se puede espicificar un fichero local o un fichero accesible a través de una URL.

Se puede especificar una DTD pública con PUBLIC, en la que queda reflejado el propietario de la misma, una descripción y el idioma.

<!DOCTYPE elem_raiz PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

Es posible incrustar la DTD internamente en el documento XML: <!DOCTYPE elem_raiz [ ...

]> Incluso es posible tener una DTD interna y otra externa. En caso de conflictos, prevalece

siempre la interna.

 Entidades

En la DTD también se especifica cómo resolver las entidades generales, con ENTITY. Se puede especificar:

o Directamente el contenido entre comillas. o El contenido de un fichero con SYSTEM.

En el documento XML se invocan con &...; También son útiles las entidades paramétricas, que a diferencia de las generales se utilizan más

adelante en la misma DTD en que se definen. Se invocan con %...;

<!ENTITY % Shape "(rect|circle|poly|default)">

 Esquemas XML

 Esquemas XML vs DTDs

Ventajas sobre las DTDs: o Restricciones más precisas sobre los documentos XML (tanto en estructura como en

tipos de datos). o Son documentos XML, por lo que la sintaxis es familiar y las herramientas los pueden

manejar sin técnicas especiales (no como las DTDs). o Soporte para espacios de nombres. o Permiten definir elementos globales y locales (las DTDs sólo globales).

Desventajas sobre las DTDs: o Más complejos. Esto causa:

Dificultades en su comprensión por humanos, sobre todo si están acostumbrados a las DTDs.

Herramientas más grandes y lentas.o Muchas aplicaciones funcionan ya sobre DTDs existentes (la conversión es posible

pero llevará un tiempo). o Se trata de una especificación muy reciente, por lo que el soporte por parte de muchas

herramientas aún está en proceso.

Page 12: Apuntes de XML

 Un primer ejemplo

Pasemos a esquema XML esta sencilla DTD:

<!ELEMENT Libreria (Libro)+><!ELEMENT Libro (Titulo, Autor+, Fecha, ISBN)><!ELEMENT Titulo (#PCDATA)><!ELEMENT Autor (#PCDATA)><!ELEMENT Fecha (#PCDATA)><!ELEMENT ISBN (#PCDATA)>

Un esquema XML equivalente:

<?xml version="1.0"?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.libros.org" xmlns="http://www.libros.org" elementFormDefault="qualified"> <xs:element name="Libreria" type="TipoLibreria"/> <xs:complexType name="TipoLibreria"> <xs:sequence> <xs:element name="Libro" type="TipoLibro" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:complexType name="TipoLibro"> <xs:sequence> <xs:element name="Titulo" type="xs:string"/> <xs:element name="Autor" type="xs:string" maxOccurs="3"/> <xs:element name="Fecha" type="xs:string"/> <xs:element name="ISBN" type="xs:string"/> </xs:sequence> </xs:complexType></xs:schema>

 Características

Observar que, a diferencia de la DTD, es XML. Observar cómo los elementos más generales referencian a los más concretos, hasta llegar a los

más básicos. No es la única forma de hacerlo. minOccurs y maxOccurs por defecto valen 1. Observar cómo definimos los elementos básicos como de tipo string. Los elementos vacíos se definen con un complexType sin elementos.

 Espacios de nombres

Hay múltiples espacios de nombres involucrados en un esquema: o Para los elementos del propio esquema (xmlns:xs). o Para los elementos a restringir (targetNamespace). o Para los elementos referenciados con el atributo ref (xmlns), se verá un ejemplo al

final. El atributo elementFormDefault sirve para exigir que al usar el esquema desde un documento

los elementos se asocien con el targetNamespace del esquema.

 Uso desde un documento

Este es un pequeño documento XML que utiliza el esquema:

<?xml version="1.0"?><Libreria xmlns="http://www.libros.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.libros.org libreria.xsd"> <Libro> <Titulo>My Life and Times</Titulo> <Autor>Paul McCartney</Autor> <Autor>Phil McCartney</Autor>

Page 13: Apuntes de XML

<Fecha>July, 1998</Fecha> <ISBN>94303-12021-43892</ISBN> </Libro> ...</Libreria>

 Más estructuras

Otras posibilidades de estructura, además de sequence: o choice: Para alternativas. o all: Para conjuntos de elementos en los que no importa el orden.

Las tres estructuras pueden tener maxOccurs (en all el máximo es 1) y minOccurs

 Tipos

En un esquema XML se pueden utilizar tipos para los elementos y atributos, de forma similar a cualquier lenguaje de programación.

Existen una serie de tipos predefinidos, algunos ejemplos: o string o boolean (true-false) o integer o positiveInteger (desde 1) o decimal (7.08) o time (hh:mm:ss) o date (YYYY-MM-DD) o anyURI (http://www.web.com) o ID y NMTOKEN (ver DTDs)

Es posible crear nuevos tipos de datos a partir de los existentes, imponiendo restricciones a éstos:

<xs:simpleType name="TipoColores"> <xs:restriction base="xs:string"> <xs:enumeration value="rojo"/> <xs:enumeration value="blanco"/> <xs:enumeration value="azul"/> </xs:restriction></xs:simpleType>

<xs:simpleType name="TipoEdad"> <xs:restriction base="xs:integer"> <xs:minInclusive value="18"/> <xs:maxInclusive value="65"/> </xs:restriction></xs:simpleType> enumeration, minInclusive y maxInclusive son algunos ejemplos de facetas, hay muchas

más.

 Atributos

Veamos cómo se tratan los atributos de los elementos. Dado el siguiente fragmento de DTD:

<!ELEMENT Libro (Titulo, Autor+, Fecha, ISBN)><!ATTLIST Libro Categoria (biografia | ensayo | ficcion) #REQUIREDDisponible (true | false) "false"Corrector CDATA "">

Resulta el siguiente fragmento de esquema XML:

<xs:complexType name="TipoLibro"> <xs:sequence> <xs:element name="Titulo" type="xs:string"/> <xs:element name="Autor" type="xs:string" maxOccurs="3"/>

Page 14: Apuntes de XML

<xs:element name="Fecha" type="xs:string"/> <xs:element name="ISBN" type="xs:string"/> </xs:sequence> <xs:attribute name="categoria" type="TipoCat" use="required"/> <xs:attribute name="disponible" type="xs:boolean" default="false"/> <xs:attribute name="corrector" type="xs:string" default=""/> </xs:complexType><xs:simpleType name="TipoCat"> <xs:restriction base="xs:string"> <xs:enumeration value="biografia"/> <xs:enumeration value="ensayo"/> <xs:enumeration value="ficcion"/></xs:restriction></xs:simpleType>

Si un elemento tiene contenido simple y atributos (por ejemplo: <elem atr=h4>678</elem>), se restringe así:

<xs:element name="elem"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:integer"> <xs:attribute name="atr" type="xs:string" use="required"/> </xs:extension> </xs:simpleContent> </xs:complexType></xs:element>

 Importar esquemas

Cuando se deben restringir varios espacios de nombre, cada espacio se restringe en un esquema, y desde el principal se importan los demás:

<xs:import schemaLocation="------.xsd"/>

 Un ejemplo completo

Para terminar, un ejemplo completo de un esquema XML:

<?xml version="1.0"?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.miempresa.org/pedidos" xmlns="http://www.miempresa.org/pedidos" elementFormDefault="qualified">

<xs:element name="Pedido" type="TipoPedido"/>

<xs:complexType name="TipoPedido"> <xs:sequence> <xs:element name="Destino" type="TipoDireccion"/> <xs:element name="Ordenante" type="TipoDireccion"/> <xs:element name="Observaciones" type="xs:string" minOccurs="0"/> <xs:element name="Contenido" type="TipoContenido"/> </xs:sequence> <xs:attribute name="fecha" type="xs:date" use="required"/></xs:complexType>

<xs:complexType name="TipoDireccion"> <xs:sequence> <xs:element name="Nombre" type="xs:string"/> <xs:element name="Direccion" type="xs:string"/> <xs:element name="Ciudad" type="xs:string"/> <xs:element name="CodPostal" type="TipoCodPostal"/> </xs:sequence></xs:complexType>

<xs:simpleType name="TipoCodPostal"> <xs:restriction base="xs:positiveInteger">

Page 15: Apuntes de XML

<xs:minInclusive value="1000"/> <xs:maxInclusive value="60000"/> </xs:restriction></xs:simpleType>

<xs:complexType name="TipoContenido"> <xs:sequence> <xs:element name="Producto" type="TipoProducto" maxOccurs="unbounded"/> </xs:sequence></xs:complexType>

<xs:complexType name="TipoProducto"> <xs:sequence> <xs:element name="Nombre" type="xs:string"/> <xs:element name="Cantidad" type="TipoCantidad"/> <xs:element name="Precio" type="xs:decimal"/> <xs:element name="Observaciones" type="xs:string" minOccurs="0"/> </xs:sequence> <xs:attribute name="codigo" type="TipoCodigo" use="required"/></xs:complexType>

<xs:simpleType name="TipoCantidad"> <xs:restriction base="xs:positiveInteger"> <xs:maxExclusive value="100"/> </xs:restriction></xs:simpleType>

<xs:simpleType name="TipoCodigo"> <xs:restriction base="xs:string"> <xs:pattern value="\d{3}-[A-Z]{2}"/> </xs:restriction></xs:simpleType>

</xs:schema>

Y un documento que lo utiliza:

<?xml version="1.0" encoding="ISO-8859-1"?><Pedido xmlns="http://www.miempresa.org/pedidos" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.miempresa.org/pedidos pedido.xsd" fecha="1999-10-20"><Destino> <Nombre>Alicia Abad</Nombre> <Direccion>Plaza de la Duquesa 12</Direccion> <Ciudad>Albacete</Ciudad> <CodPostal>05020</CodPostal> </Destino> <Ordenante> <Nombre>Roberto Movilla</Nombre> <Direccion>General Ricardos 56</Direccion> <Ciudad>Madrid</Ciudad> <CodPostal>28055</CodPostal> </Ordenante> <Observaciones>Es urgente, mi cesped está muy alto</Observaciones> <Contenido> <Producto codigo="872-AA"> <Nombre>Cortadora de cesped</Nombre> <Cantidad>1</Cantidad> <Precio>148.95</Precio> <Observaciones>Confirmar que es eléctrica</Observaciones> </Producto> <Producto codigo="926-FH"> <Nombre>Taladradora</Nombre> <Cantidad>3</Cantidad> <Precio>10.98</Precio> </Producto> </Contenido></Pedido>

Page 16: Apuntes de XML

 Otras formas de construir esquemas XML

Anidando los elementos:

<?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.libros.org" xmlns="http://www.libros.org"> <xsd:element name="Libreria"> <xsd:complexType> <xsd:sequence> <xsd:element name="Libro" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="Titulo" type="xsd:string"/> <xsd:element name="Autor" type="xsd:string"/> <xsd:element name="Fecha" type="xsd:string"/> <xsd:element name="ISBN" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element></xsd:schema>

Referenciando a los elementos:

<?xml version="1.0"?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"targetNamespace="http://www.libros.org" xmlns="http://www.libros.org"> <xs:element name="Libreria"> <xs:complexType> <xs:sequence> <xs:element ref="Libro" minOccurs="1" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Libro"> <xs:complexType> <xs:sequence> <xs:element ref="Titulo" minOccurs="1" maxOccurs="1"/> <xs:element ref="Autor" minOccurs="1" maxOccurs="unbounded"/> <xs:element ref="Fecha" minOccurs="1" maxOccurs="1"/> <xs:element ref="ISBN" minOccurs="1" maxOccurs="1"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Titulo" type="xs:string"/> <xs:element name="Autor" type="xs:string"/> <xs:element name="Fecha" type="xs:string"/> <xs:element name="ISBN" type="xs:string"/></xs:schema> En ambos casos se utilizan tipos complejos anónimos (sin nombre). Se puede hacer lo mismo con los tipos simples.

Page 17: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Presentación y transformación de documentos XML o Hojas de estilo CSS

CSS con XML Un ejemplo

o Lenguaje XSLT Introducción a XSLT Ventajas y desventajas Formas de uso Un ejemplo de hoja Características XPath Crear elementos Ordenaciones

Presentación y transformación de documentos XML

 Hojas de estilo CSS

 CSS con XML

CSS es un lenguaje de hojas de estilo que se utiliza normalmente para controlar la presentación de documentos HTML, pero también se puede utilizar con documentos XML. Su principal característica, en contraste con el lenguaje XSLT, es su sencillez.

Ventajas: o Fácil de aprender y utilizar. Muchos desarrolladores ya lo conocen. o Consume poca memoria y tiempo de proceso, pues no construye una representación

en arbol del documento. o Muestra el documento según se va procesando.

Desventajas: o Sólo sirve para visualizar documentos en un navegador. o No permite realizar manipulaciones sobre el documento, tales como añadir y borrar

elementos, realizar ordenaciones, etc. o Sólo permite acceder al contenido de los elementos. No a los atributos, instrucciones

de proceso, etc. o Utiliza una sintaxis diferente a la del XML.

 Un ejemplo

Ejemplo de documento XML:

<?xml version="1.0" ?><?xml-stylesheet type="text/css" href="proyectos.css" ?><BD_Proyectos> <Proyecto pid="0511-001" tipo="Web" comienzo="11/1/05"> <Nombre_Proy> Xray Mind Learners Web Site </Nombre_Proy> <Contacto tipo="primario"> <Nombre>Kell Attain</Nombre> <Direccion> Web Ravin Consulting, 661 Oakey Rd</Direccion> <Tlf> 111-555-1111 </Tlf> <Fax> 111-555-2222 </Fax> <E-Mail> [email protected] </E-Mail> </Contacto> <Contacto tipo="marketing"> <Nombre> Francis Chillington </Nombre> <Direccion> Web Ravin Consulting, 661 Oakey Rd</Direccion> <Tlf> 111-555-1112 </Tlf> <Fax> 111-555-2222 </Fax> <E-Mail> [email protected] </E-Mail>

Page 18: Apuntes de XML

</Contacto> <Contacto tipo="graficos"> <Nombre> Lara Firewalker </Nombre> <Direccion> Web Ravin Consulting, 661 Oakey Rd</Direccion> <Tlf> 111-555-1113 </Tlf> <Fax> 111-555-2222 </Fax> <E-Mail> [email protected] </E-Mail> </Contacto> <Notas> <Entrada fecha="11/03/05" contacto="kta001"> Development on the Web site has started. The primary graphics - logo | backgrounds | navigation system - should be done by 11/8/00. </Entrada> </Notas> </Proyecto> <Proyecto pid="0511-002" tipo="Database"> <Nombre_Proy> XML Database for Site Visitors </Nombre_Proy> <Contacto tipo="primario"> <Nombre> Tom Phannon </Nombre> <Direccion> Web Ravin Consulting, 661 Oakey Rd</Direccion> <Tlf> 111-555-1122 </Tlf> <Fax> 111-555-2222 </Fax> <E-Mail> [email protected] </E-Mail> </Contacto> <Notas> <Entrada fecha="11/10/05"> Database structure is complete. Ready to start propagating the data. </Entrada> </Notas> </Proyecto> <Proyecto tipo="AI"> <Nombre_Proy> House of Glass </Nombre_Proy> <Contacto tipo="primario"> <Nombre> Shamu Wagonride </Nombre> <Direccion> Web Ravin Consulting, 661 Oakey Rd</Direccion> <Tlf> 111-555-1133 </Tlf> <Fax> 111-555-2222 </Fax> <E-Mail> [email protected] </E-Mail> </Contacto> <Notas> <Entrada fecha="11/01/05"> AI logic model software has been picked out and ordered, as well as the equipment required to run it. Networking (MIS) has been notified of the machine's arrival and networking needs. </Entrada> <Entrada fecha="11/11/05"> MIS has received equipment and software and is starting the installation. Expected date for network connection is 11/15/05. </Entrada> </Notas> </Proyecto></BD_Proyectos>

Hoja de estilo para visualizar el documento en un navegador:

Proyecto {display: block; background: blue; font-family: sans-serif; margin: 1cm}

Nombre_Proy {display: block; background: #FF0000; font-size: larger; font-weight: bold; color: yellow; font-family: Arial; border: #FF0000; border-style: double}

Contacto {display: block; padding: 5pt;

Page 19: Apuntes de XML

text-indent: 1cm}

Nombre {display: block; font-variant: small-caps; font-size: medium; font-weight: bold; color: red}

Direccion {display: block; font-style: italic; font-size: smaller; color: white}

Tlf {display: block; font-weight: bold; font-size: smaller; color: white}

Fax {display: block; font-weight: bold; font-size: smaller; color: white}

E-Mail {display: block; font-weight: bold; font-style: italic; color: white}

Notas {display: block; font-style: italic; color: white; padding: 3em}

Entrada {display: block}

 Lenguaje XSLT

 Introducción a XSLT

Para aclarar terminología, XSL es un estándar que se compone de dos partes diferenciadas: o XSLT: Lenguaje para transformar documentos XML en otro formato (otro XML, HTML,

DHTML, texto plano, PDF, RTF, Word, etc.) o XSL-FO: Especificación que trata cómo deben ser los objetos de formato para convertir

XML a formatos binarios (PDF, Word, imágenes, etc.) La principal característica del lenguaje XSLT es su potencia. No es sólo un lenguaje para

visualizar documentos, sino en general para transformarlos y manipularlos. Esta manipulación la gestiona un programa especial que se llama procesador XSLT. Existen

distintos procesadores disponibles, como Xalan, del proyecto colaborativo de código abierto Apache.

 Ventajas y desventajas

Ventajas: o La salida no tiene por qué ser HTML para visualización en un navegador, sino que

puede estar en muchos formatos. o Permite manipular de muy diversas maneras un documento XML: reordenar

elementos, filtrar, añadir, borrar, etc. o Permite acceder a todo el documento XML, no sólo al contenido de los elementos. o XSLT es un lenguaje XML, por lo que no hay que aprender nada especial acerca de su

sintaxis. Desventajas:

o Su utilización es más compleja. o Consume cierta memoria y capacidad de proceso, pues se construye un árbol con el

contenido del documento.

 Formas de uso

Page 20: Apuntes de XML

Visualizar directamente en un navegador el documento XML que tiene asociada una hoja XSLT. El navegador debe tener incorporado un procesador XSLT.

Ejecutar el procesador XSLT independientemente del navegador. Se le pasan las entradas necesarias (fichero origen y hoja XSLT a utilizar) y genera la salida en un fichero, con el que podemos hacer lo que queramos.

Realizar las transformaciones dentro de un programa en el servidor y enviar a los clientes sólo el resultado de la transformación.

 Un ejemplo de hoja

Hoja de estilo XSLT para el ejemplo del libro:

<?xml version="1.0"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:Lib="http://www.mislibros.com/libros/javaxml" xmlns:Catalogo="http://www.mislibros.com/catalogo" version="1.0">

<xsl:template match="Lib:Libro"> <html> <head> <title><xsl:value-of select="Lib:Titulo" /> (<xsl:value-of select="Catalogo:Seccion" />: <xsl:value-of select="Catalogo:SubSeccion" />) </title> </head> <body> <xsl:apply-templates select="Lib:Contenido" /> <i><xsl:value-of select="Lib:Copyright" /></i> </body> </html> </xsl:template>

<xsl:template match="Lib:Contenido"> <center> <h1>Contenidos</h1> </center> <hr/> <ul> <xsl:for-each select="Lib:Capitulo"> <xsl:choose> <xsl:when test="@materia='Java'"> <li><xsl:value-of select="Lib:Tema" /> (Java)</li> </xsl:when> <xsl:otherwise> <li><xsl:value-of select="Lib:Tema" /> (No Java)</li> </xsl:otherwise> </xsl:choose> </xsl:for-each> </ul> </xsl:template>

</xsl:stylesheet>

 Características

Se puede observar que una hoja de estilo XSLT es un documento XML. El elemento raíz es stylesheet, en el que se especifican los espacios de nombre para la

propia hoja de estilo y para el documento XML que se quiere presentar. Cada elemento template se asocia con un fragmento del documento XML (que puede ser un

elemento o un conjunto de elementos) y se transforma en otro fragmento de XML, según una serie de reglas que se especifican en su interior.

El elemento value-of extrae un valor concreto del documento. El elemento apply-templates aplica las plantillas que se especifiquen e inserta la salida de

las mismas. Para iterar sobre una serie de elementos que se repiten se utiliza for-each.

Page 21: Apuntes de XML

Para realizar distintos procesamientos en función de los datos se puede utilizar el elemento choose, que se compone de un número de elementos when, cada uno con un caso distinto, y un elemento opcional otherwise que se refiere al caso por defecto.

Para procesar o no un elemento en función de una condición se utilizaría simplemente el elemento if, especificando la condición en el atributo test.

El HTML que se especifica en las plantillas debe seguir las reglas del XML (es decir, debe ser XHTML).

 XPath

Las expresiones que pueden aparecer en los atributos select, match o test de los elementos explicados siguen el lenguaje XPath, y pueden llegar a ser todo lo complejas que se requiera.

Veamos un ejemplo sobre el mismo documento del libro con algunas expresiones XPath. Este ejemplo muestra una lista con las secciones de 3 ó más apartados de capítulos cuya materia sea Java, numerándolas e indicando a qué capítulo pertenecen.

<?xml version="1.0"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:Lib="http://www.mislibros.com/libros/javaxml" version="1.0">

<xsl:template match="Lib:Libro"> <html><body> <ul> <xsl:for-each select="Lib:Contenido/Lib:Capitulo[@materia='Java'] /Lib:Seccion[@apartados>=3]"> <li> <xsl:value-of select="position()" />: <xsl:value-of select="." />, de <xsl:value-of select="preceding-sibling::Lib:Tema" /> </li> </xsl:for-each> </ul> </body></html></xsl:template></xsl:stylesheet> La especificación XPath contiene muchas complejidades que no podemos detenernos a cubrir,

pero destaquemos algunos aspectos del ejemplo: o Para descender por la jerarquía de elementos se utiliza el separador /. o Se pueden imponer restricciones al conjunto de nodos extraídos, entre corchetes. o Existen una serie de funciones predefinidas, como position(), que nos da el número

de orden de un nodo respecto al conjunto de nodos extraídos. o Se puede trabajar con los nodos relacionados con el actual (nodo padre, hijos, nodos

al mismo nivel, etc.) mediante una serie de ejes, como preceding-sibling, que nos da los nodos anteriores al actual del mismo nivel.

 Crear elementos

Con XSLT también es posible crear nuevos elementos mediante las etiquetas element y attribute. Esto sirve para crear elementos con algún atributo no conocido a priori, que debe tomarse del fichero XML.

Añadimos el siguiente fragmento de XML al final del documento del libro, a partir del cual queremos generar enlaces HTML:

<Referencias> <Referencia> <Nombre>XSL en el W3C</Nombre> <Url>http://www.w3.org/Style/XSL</Url> </Referencia> <Referencia> <Nombre>Lista XSL</Nombre> <Url>http://www.mulberrytech.com/xsl/xsl-list</Url> </Referencia></Referencias>

Page 22: Apuntes de XML

El fragmento de XSLT que genera los enlaces es:

<xsl:template match="Lib:Referencias"> <p> <center><h3>Referencias útiles</h3></center> <ol> <xsl:for-each select="Lib:Referencia"> <li> <xsl:element name="a"> <xsl:attribute name="href"> <xsl:value-of select="Lib:Url" /> </xsl:attribute> <xsl:value-of select="Lib:Nombre" /> </xsl:element> </li> </xsl:for-each> </ol> </p></xsl:template>

(Recordar aplicar la nueva plantilla:)

<xsl:apply-templates select="Lib:Contenido|Lib:Referencias" />

 Ordenaciones

Si queremos ordenar los capítulos alfabéticamente, sólo tenemos que añadir lo siguiente tras el elemento for-each:

<xsl:sort select="Lib:Tema"/> Se puede ordenar descendentemente añadiendo al elemento sort el atributo

order="descending"

Page 23: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Manipulación de XML desde programas Java o Analizar XML con SAX

Introducción a SAX El analizador SAX Un primer ejemplo El manejador de contenido Los métodos del manejador Código portable Validación Otro ejemplo

o Manipular XML con DOM Introducción a DOM El analizador DOM Un primer ejemplo Manipulación del árbol Código portable Otro ejemplo Más formas de manipular el árbol Crear documentos Imprimir documentos Un ejemplo Modificar documentos

Manipulación de XML desde programas Java

 Analizar XML con SAX

 Introducción a SAX

Hasta ahora hemos trabajado sólo con el lenguaje XML y algunos de sus lenguajes relacionados (DTD, Esquema XML ó XSLT). Siendo estrictos, todavía no hemos programado con XML, es decir, no hemos realizado programas que trabajen con XML.

La API SAX (ó API simple para XML) es el primer punto de unión del mundo de XML con el mundo de la programación en general, y en particular con Java.

Esta API consta de una serie de clases, con sus correspondientes métodos, que nos permiten trabajar con un documento XML desde un programa escrito en Java, pudiendo acceder a los datos, comprobar si está bien formado, si es válido, etc.

La principal característica de SAX es que el documento se lee secuencialmente de principio a fin, sin cargar todo el documento en memoria, lo cual tiene consecuencias positivas y negativas:

o La ventaja es la eficiencia en cuanto al tiempo y la memoria empleados en el análisis. o La desventaja es que con SAX no disponemos de la estructura en árbol de los

documentos, luego no podemos modificar ni crear documentos XML, ni recorrerlos jerárquicamente, solamente analizarlos secuencialmente.

 El analizador SAX

Para poder trabajar con documentos XML mediante SAX necesitamos un analizador SAX. El analizador realiza el trabajo sucio (detectar cuándo empieza y termina un elemento, gestionar los espacios de nombres, comprobar que el documento está bien formado, etc.), de forma que podemos concentrarnos en los aspectos específicos de nuestra aplicación.

Existen muchos analizadores en el mercado, pero no todos se pueden utilizar desde Java. Para los ejemplos de este curso utilizaremos el analizador Xerces, del proyecto colaborativo de código abierto Apache.

Para utilizar SAX desde un programa escrito en Java necesitamos conseguir las clases que componen el analizador y asegurarnos de incluir estas clases en la ruta de clases.

Page 24: Apuntes de XML

 Un primer ejemplo

Veamos un primer ejemplo muy sencillo que simplemente analiza un documento XML e imprime un mensaje si el documento está bien formado:

import java.io.IOException;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import org.apache.xerces.parsers.SAXParser;

public class SAX { public static void main(String[] args) { if (args.length != 1) { System.out.println("Debe haber un parámetro (el fichero)"); } else { String fich = args[0]; System.out.println("Analizando: " + fich + "\n"); try { XMLReader parser = new SAXParser(); parser.parse(fich); System.out.println("Fin del análisis. Todo bien\n"); } catch (IOException e) { System.out.println(e); } catch (SAXException e) { System.out.println(e); } } }} Creamos una instancia del analizador (clase SAXParser), que vamos a manejar a través de la

interfaz XMLReader. Para analizar el documento llamamos al método parse, pasándole el fichero que sea. Si hay algún problema con el análisis se genera una excepción SAXException y el análisis se

detiene.

 El manejador de contenido

Para que nuestro programa pueda hacer algo útil con los datos XML según se analizan, debemos usar un manejador de contenido.

Un manejador es una clase con una serie de métodos. Estos métodos se ejecutan cuando el analizador detecta determinados eventos que se producen al leer un documento (empieza el documento, se abre un elemento, se cierra, se encuentra una instrucción de proceso, etc.).

Añadamos al ejemplo un esqueleto de manejador. Los métodos se rellenarán con el código apropiado para el programa que estemos realizando en cada momento:

class ManejadorPrueba implements ContentHandler { private Locator loc; public void setDocumentLocator(Locator loc) { } public void startDocument() { }

public void endDocument() { } public void processingInstruction(String destino, String datos) { } public void startPrefixMapping(String prefijo, String uri) { }

public void endPrefixMapping(String prefijo) { }

Page 25: Apuntes de XML

public void startElement(String espacio, String nomLocal, String nomCompleto, Attributes atrs) { } public void endElement(String espacio, String nomLocal, String nomCompleto) { }

public void characters(char[] ch, int comienzo, int fin) { }

public void ignorableWhitespace(char[] ch, int comienzo, int fin) { }

public void skippedEntity(String nombre) { }}

Es necesario añadir algunas líneas al código anterior para utilizar el manejador:

import java.io.IOException;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import org.xml.sax.Attributes;import org.xml.sax.ContentHandler;import org.xml.sax.Locator;import org.apache.xerces.parsers.SAXParser;

public class SAX {

... XMLReader parser = new SAXParser(); ManejadorPrueba man = new ManejadorPrueba(); parser.setContentHandler(man); parser.parse(fich); System.out.println("Fin del análisis. Todo bien\n"); ...}

 Los métodos del manejador

Ahora añadiremos algo de código a los métodos del manejador para ilustrar su funcionamiento. Simplemente escribiremos mensajes por la consola cuando se detecten los eventos.

Es importante notar que estamos analizando sin validar. Más adelante realizaremos análisis con validación.

En primer lugar rellenaremos el método setDocumentLocator (que se ejecuta al principio del análisis) guardando en una variable de nuestra clase el localizador que nos llega como parámetro. Así podremos saber en qué lugar (línea y columna) del fichero ocurren los eventos.

public void setDocumentLocator(Locator l) { loc = l; System.out.println ("Localizador guardado");} El comienzo y el final de un documento implican llamadas a los métodos startDocument y

endDocument:

public void startDocument() { System.out.println ("Ahora empieza el análisis...");}

public void endDocument() { System.out.println ("...Ahora termina el análisis");} El comienzo y el final de cada elemento invocan a los métodos startElement y endElement,

dentro de los cuales tenemos información sobre el nombre del elemento, sus atributos y el espacio de nombres al que pertenece:

Page 26: Apuntes de XML

public void startElement(String espacio, String nomLocal, String nomCompleto, Attributes atrs) { System.out.print("(Línea " + loc.getLineNumber() + ") "); System.out.print("Se abre elemento: " + nomLocal); if (!espacio.equals("")) { System.out.println(" en espacio " + espacio + " (" + nomCompleto + ")"); } else { System.out.println(" sin espacio asociado"); } for (int i=0; i<atrs.getLength(); i++) { System.out.println(" Atributo: " + atrs.getLocalName(i) + "=" + atrs.getValue(i)); }}

public void endElement(String espacio, String nomLocal, String nomCompleto) { System.out.println("Se cierra elemento: " + nomLocal + "\n"); } La lectura del texto contenido en cada elemento genera una llamada al método characters,

dentro del cual disponemos del texto en un vector de caracteres acotado con una posición de comienzo y otra de fin:

public void characters(char[] ch, int comienzo, int fin) { String s = new String(ch, comienzo, fin); System.out.println("Contenido: " + s);} Algunas puntualizaciones sobre este método:

o No se puede contar con tener siempre todo el texto de un elemento en una única llamada a este método (grandes porciones de texto, texto y elementos hijos se entremezclan, caracteres especiales, distintos analizadores, etc.)

o Puede recoger los espacios en blanco al analizar sin validación (justo lo que estamos haciendo).

Las instrucciones de proceso se controlan mediante el método processingInstruction:

public void processingInstruction(String destino, String datos) { System.out.println("PI: Destino:" + destino + ", Datos:" + datos);} Los dos métodos que sirven para controlar las declaraciones de espacios de nombres son

startPrefixMapping y endPrefixMapping. El primero se ejecuta al declarar un espacio de nombres mediante el atributo xmlns, mientras que el segundo se ejecuta al cerrar el elemento en el que se declaró el espacio (normalmente el elemento raíz):

public void startPrefixMapping(String prefijo, String uri) { System.out.println("Comienza el uso del prefijo " + (prefijo.equals("")? "(vacío)": prefijo) + " correspondiente a la URI " + uri);}

public void endPrefixMapping(String prefijo) { System.out.println("Termina el uso del prefijo " + (prefijo.equals("")? "(vacío)": prefijo)); } El método ignorableWhitespace lleva control de los espacios en blanco, aunque con Xerces

y la mayoría de analizadores no funciona bien si no estamos validando el documento:

public void ignorableWhitespace(char[] ch, int comienzo, int fin) {} Por último, el método skippedEntity tiene lugar en algunos analizadores que se saltan las

entidades cuando no están validando, pero es difícil encontrar casos así:

public void skippedEntity(String nombre) {}

 Código portable

Page 27: Apuntes de XML

Hay una forma mejor de instanciar el analizador, utilizando la API JAXP, con la que podemos conseguir fácilmente que nuestros programas que usan SAX funcionen con cualquier analizador sin tener que realizar cambios en el código, consiguiendo así una completa portabilidad:

import java.io.IOException;import org.xml.sax.SAXException;import org.xml.sax.Attributes;import org.xml.sax.Locator;

import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.helpers.DefaultHandler;

public class SAXconJAXP {

public static void main(String[] args) {if (args.length != 1) {

System.out.println("Debe haber un parámetro (el fichero)");}

else {String fich = args[0];System.out.println("Analizando: " + fich + "\n");try {

SAXParser parser;SAXParserFactory factoria = SAXParserFactory.newInstance();factoria.setNamespaceAware(true);parser = factoria.newSAXParser();ManejadorPrueba man = new ManejadorPrueba();parser.parse(fich, man);System.out.println("Fin del análisis. Todo bien\n");

} catch (IOException e) {System.out.println(e);

} catch (SAXException e) {System.out.println(e);

} catch (ParserConfigurationException e) {System.out.println(e);

} }}}

class ManejadorPrueba extends DefaultHandler { private Locator loc;

public void setDocumentLocator(Locator l) { loc = l; System.out.println ("Localizador guardado"); }

public void startDocument() { System.out.println ("Ahora empieza el análisis..."); }

public void endDocument() { System.out.println ("...Ahora termina el análisis"); }

public void processingInstruction(String destino, String datos) { System.out.println("PI: Destino:" + destino + ", Datos:" + datos); }

public void startPrefixMapping(String prefijo, String uri) { System.out.println("Comienza el uso del prefijo " + (prefijo.equals("")? "(vacío)": prefijo) + " correspondiente a la URI " + uri); }

Page 28: Apuntes de XML

public void endPrefixMapping(String prefijo) { System.out.println("Termina el uso del prefijo " + (prefijo.equals("")? "(vacío)": prefijo)); }

public void startElement(String espacio, String nomLocal, String nomCompleto, Attributes atrs) {

System.out.print("(Línea " + loc.getLineNumber() + ") "); System.out.print("Se abre elemento: " + nomLocal); if (!espacio.equals("")) { System.out.println(" en espacio " + espacio + " (" + nomCompleto + ")"); } else { System.out.println(" sin espacio asociado"); } for (int i=0; i<atrs.getLength(); i++) { System.out.println(" Atributo: " + atrs.getLocalName(i) + "=" + atrs.getValue(i)); }

}

public void endElement(String espacio, String nomLocal, String nomCompleto) { System.out.println("Se cierra elemento: " + nomLocal); }

public void characters(char[] ch, int comienzo, int fin) { String s = new String(ch, comienzo, fin); System.out.println("Contenido: " + s); }

} Observar que no se hace ninguna referencia al analizador a utilizar. La independencia se

consigue a través de las clases SAXParser y SAXParserFactory, debiéndose capturar una ParserConfigurationException.

El método setNamespaceAware activa el soporte para espacios de nombres. Con esta solución, el manejador tiene que ser derivado a partir de la clase DefaultHandler,

que es una clase de conveniencia en la que se sobreescriben sólo los métodos deseados (sin tener que implementar todos como ocurría con ContentHandler). Observar que la forma de pasar el manejador al analizador cambia.

 Validación

Falta completar el código para que nuestro programa sea capaz de validar un documento XML a la vez que lo analiza:

...import org.xml.sax.helpers.DefaultHandler;import org.xml.sax.SAXParseException;

... try { SAXParser parser; SAXParserFactory factoria = SAXParserFactory.newInstance(); factoria.setNamespaceAware(true); factoria.setValidating(true); parser = factoria.newSAXParser(); ManejadorPrueba man = new ManejadorPrueba(); parser.parse(fich, man); ...

class ManejadorPrueba extends DefaultHandler { ...

public void error(SAXParseException exc) throws SAXException {

Page 29: Apuntes de XML

System.out.println("**Error**\n" + " Línea: " + exc.getLineNumber() + "\n" + " URI: " + exc.getSystemId() + "\n" + " Mensaje: " + exc.getMessage()); throw new SAXException("Se encontró error"); }

public void fatalError(SAXParseException exc) throws SAXException { System.out.println("**Error Fatal**\n" + " Línea: " + exc.getLineNumber() + "\n" + " URI: " + exc.getSystemId() + "\n" + " Mensaje: " + exc.getMessage()); throw new SAXException("Se encontró error fatal"); }

} Para informar de los errores que se detecten al validar necesitamos añadir nuevos métodos al

manejador. Los errores referentes a la validación provocan una llamada al método error, mientras que los

errores que afectan a la sintaxis XML invocan al método fatalError. Los errores de validación no tienen por qué detener el análisis, sólo lo hacen si lanzamos una

excepción desde el método error. Los errores de sintaxis siempre detienen el análisis, lancemos o no una excepción.

La validación se puede realizar mediante una DTD o un esquema XML, según lo que indique el documento XML (no hace falta cambiar nada en el código Java).

 Otro ejemplo

Para terminar, veamos el código de un manejador para el ejemplo del libro que imprime por pantalla el título del libro, las líneas del fichero en que empieza cada capítulo, el número de capítulos y las materias de las que trata el libro:

class ManejadorLibro extends DefaultHandler { private Locator l; private boolean titulo; private int numCaps; private HashSet materias;

public void setDocumentLocator(Locator l) { this.l = l; }

public void startDocument() { numCaps = 0; materias = new HashSet(); }

public void startElement(String espacio, String nomLocal, String nomCompleto, Attributes atrs) { if (nomLocal.equals("Titulo")) { titulo = true; } else if (nomLocal.equals("Capitulo")) { numCaps++; System.out.println("Capítulo en línea: " +l.getLineNumber()); materias.add(atrs.getValue(0)); } }

Page 30: Apuntes de XML

public void endElement(String espacio, String nomLocal, String nomCompleto) { if (nomLocal.equals("Titulo")) { titulo = false; } }

public void characters(char[] ch, int comienzo, int fin) { if (titulo) { String cad = new String(ch, comienzo, fin); System.out.println("El título es: " + cad); } }

public void endDocument() { System.out.println("Número de capítulos: " + numCaps); System.out.print("Materias: "); Iterator i = materias.iterator(); while (i.hasNext()) { System.out.print(i.next() + " "); } System.out.println(); }

}

 Manipular XML con DOM

 Introducción a DOM

La API DOM (ó Modelo de Objetos de Documento) constituye un paso más allá en el uso de XML desde un lenguaje de programación, y en particular desde Java.

Esta API también consta de una serie de clases y métodos, que nos permiten trabajar con los documentos XML desde nuestros programas escritos en Java.

La principal característica de DOM es que el documento con el que se trabaja se carga entero en memoria, en una estructura de árbol, por lo que la forma de trabajar con DOM es muy distinta a la de SAX:

o La ventaja es que con DOM, al disponer de la estructura del documento, podemos acceder a los datos en función de la jerarquía de elementos, así como modificar el contenido de los documentos e incluso crearlos desde cero.

o La desventaja es el coste en tiempo y memoria que conlleva construir el árbol para un documento, sobre todo si tiene cierto tamaño.

 El analizador DOM

Para poder trabajar con DOM necesitamos un analizador DOM. El analizador DOM lee un documento XML y genera una estructura en árbol para él, para lo cual se suele apoyar en un analizador SAX.

Para los ejemplos de DOM utilizaremos también el analizador Xerces (dado que ya tenemos sus clases y hemos establecido también la ruta de clases sólo tendremos que importar las clases oportunas para trabajar con DOM)

 Un primer ejemplo

Veamos un primer ejemplo sencillo que lee un documento XML y genera un árbol para él:

import org.w3c.dom.Document;import java.io.IOException;import org.xml.sax.SAXException;import org.apache.xerces.parsers.DOMParser;

public class DOM {

public static void main(String[] args) { if (args.length != 1) {

Page 31: Apuntes de XML

System.out.println("Debe haber un parámetro (el fichero)"); } else { String fich = args[0]; System.out.println("Generando árbol para: " + fich + "\n"); try { DOMParser parser = new DOMParser(); parser.parse(fich); Document doc = parser.getDocument(); System.out.println("Fin de la carga. Todo bien\n"); } catch (IOException e) { System.out.println(e); } catch (SAXException e) { System.out.println(e); } } }} Necesitamos una instancia del analizador (clase DOMParser). Veremos más adelante cómo se

consigue independencia del analizador por medio de la API JAXP. Para generar el árbol llamamos al método parse, pasándole el fichero que sea. Después, con el método getDocument obtenemos un objeto que referencia al árbol creado, y

que podemos manipular de múltiples formas. Si hay algún problema con la sintaxis del documento XML se genera una excepción

SAXException y el proceso se detiene.

 Manipulación del árbol

Para ilustrar el manejo de DOM vamos a imprimir el documento XML que se nos pase como entrada.

Para ello necesitamos realizar un procesamiento recursivo: procesamos cada nodo del árbol y después procesamos sus nodos hijos recursivamente.

Añadimos un método tratarNodo que va a ser llamado recursivamente:

import org.w3c.dom.Document;import org.w3c.dom.Node;import java.io.IOException;...

public class DOM {

public static void tratarNodo(Node nodo) { switch (nodo.getNodeType()) { case Node.DOCUMENT_NODE: break;

case Node.ELEMENT_NODE: break;

case Node.ATTRIBUTE_NODE: break; case Node.TEXT_NODE: break;

case Node.CDATA_SECTION_NODE: break;

case Node.PROCESSING_INSTRUCTION_NODE: break;

case Node.ENTITY_REFERENCE_NODE: break;

case Node.DOCUMENT_TYPE_NODE: break; }

Page 32: Apuntes de XML

}

public static void main(String[] args) { ... Document doc = parser.getDocument(); tratarNodo(doc); System.out.println("Fin de la carga. Todo bien\n"); ... }} Dentro de este método se realizarán tres tareas:

o Determinar el tipo del nodo en curso. o Imprimir por pantalla el contenido del nodo. o Tratar recursivamente los nodos hijos del nodo en curso.

La primera tarea se realiza con el método getNodeType, como puede verse en el esquema de código. Ahora completaremos cada caso para realizar las otras dos.

El primer nodo que nos encontramos representa todo el documento (tipo DOCUMENT_NODE). Aquí imprimiremos la declaración XML. Después con getDocumentElement accedemos al nodo

que representa al elemento raíz, y lo pasamos recursivamente al método tratarNodo:

case Node.DOCUMENT_NODE: System.out.println("<xml version=\"1.0\">"); Document doc = (Document)nodo; tratarNodo(doc.getDocumentElement());

break; Los elementos del documento están representados por un nodo ELEMENT_NODE. Obtenemos el nombre de cada elemento con getNodeName. Con getChildNodes obtenemos los hijos en una NodeList, que hay que recorrer para tratar

recursivamente cada hijo.

import org.w3c.dom.Document;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import java.io.IOException;...

case Node.ELEMENT_NODE: String nombre = nodo.getNodeName(); System.out.print("<" + nombre); System.out.println(">"); NodeList hijos = nodo.getChildNodes(); if (hijos != null) { for (int i=0; i<hijos.getLength(); i++) { tratarNodo(hijos.item(i)); } } System.out.println("</" + nombre + ">");

break;

Para obtener los atributos de un elemento tenemos el método getAttributes, que devuelve un NamedNodeMap, el cual procesamos para tratar los atributos recursivamente.

Cada atributo es un nodo ATTRIBUTE_NODE, cuyo nombre y valor recuperamos con getNodeName y getNodeValue:

import org.w3c.dom.Document;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.w3c.dom.NamedNodeMap;import java.io.IOException;...

case Node.ELEMENT_NODE: String nombre = nodo.getNodeName(); System.out.print("<" + nombre); NamedNodeMap ats = nodo.getAttributes(); for (int i=0; i<ats.getLength(); i++) {

Page 33: Apuntes de XML

tratarNodo(ats.item(i)); } System.out.println(">"); NodeList hijos = nodo.getChildNodes(); ... break;

case Node.ATTRIBUTE_NODE: System.out.print(" " + nodo.getNodeName() + "=\"" + nodo.getNodeValue() +

"\""); Para que la salida sea más fácil de leer colocamos un sangrado que vamos aumentando

recursivamente:

public static void tratarNodo(Node nodo, String ind) { switch (nodo.getNodeType()) {case Node.DOCUMENT_NODE: System.out.println("<xml version=\"1.0\">"); Document doc = (Document)nodo; tratarNodo(doc.getDocumentElement(), ""); break;

case Node.ELEMENT_NODE: String nombre = nodo.getNodeName(); System.out.print(ind + "<" + nombre); NamedNodeMap ats = nodo.getAttributes(); for (int i=0; i<ats.getLength(); i++) { tratarNodo(ats.item(i), ""); } System.out.println(">"); NodeList hijos = nodo.getChildNodes(); if (hijos != null) { for (int i=0; i<hijos.getLength(); i++) { tratarNodo(hijos.item(i), ind + " "); } } System.out.println(ind + "</" + nombre + ">"); break;...

public static void main(String[] args) { ... Document doc = parser.getDocument(); tratarNodo(doc, ""); System.out.println("Fin de la carga. Todo bien\n"); ...} El texto de los elementos viene recogido en nodos TEXT_NODE o CDATA_SECTION_NODE, en los

cuales sólo tenemos que hacer una llamada a getNodeValue para obtener el texto:

case Node.TEXT_NODE: String texto = nodo.getNodeValue().trim(); if (!texto.equals("")) { System.out.println(ind + texto); } break;

case Node.CDATA_SECTION_NODE: System.out.println(nodo.getNodeValue());

break; Sólo nos faltan unos últimos detalles: el código para procesar las instrucciones de proceso, la

declaración DTD y las referencias a entidades:

import org.w3c.dom.Document;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.w3c.dom.NamedNodeMap;import org.w3c.dom.DocumentType;import java.io.IOException;...

Page 34: Apuntes de XML

case Node.PROCESSING_INSTRUCTION_NODE: System.out.println("<?" + nodo.getNodeName() + " " + nodo.getNodeValue() + "?>"); break;

case Node.DOCUMENT_TYPE_NODE: DocumentType dt = (DocumentType)nodo; System.out.println("<!DOCTYPE " + dt.getName() + " SYSTEM \"" + dt.getSystemId() + "\">"); break;

case Node.ENTITY_REFERENCE_NODE: System.out.println(ind + "&" + nodo.getNodeName() + ";");

break; Y modificar el tratamiento del nodo del documento para que trate todos sus nodos hijos, ya

que las instrucciones de proceso y la declaración DTD lo son:

case Node.DOCUMENT_NODE: System.out.println("<xml version=\"1.0\">"); Document doc = (Document)nodo; tratarNodo(doc.getDocumentElement(), ""); NodeList nodos = nodo.getChildNodes(); if (nodos != null) { for (int i=0; i<nodos.getLength(); i++) { tratarNodo(nodos.item(i), ""); } }

break;

 Código portable

Podemos utilizar la API JAXP para conseguir independencia del analizador, de una forma análoga a como lo hicimos con SAX:

...

import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;

public class DOMconJAXP {

...

public static void main(String[] args) { if (args.length != 1) { System.out.println("Debe haber un parámetro (el fichero)"); } else { String fich = args[0]; System.out.println("Generando árbol para: " + fich + "\n"); try { DocumentBuilder parser; DocumentBuilderFactory factoria = DocumentBuilderFactory.newInstance(); parser = factoria.newDocumentBuilder(); Document doc = parser.parse(fich); tratarNodo(doc, ""); System.out.println("Fin de la carga. Todo bien\n"); } catch (IOException e) { System.out.println(e); } catch (SAXException e) { System.out.println(e); } catch (ParserConfigurationException e) {

Page 35: Apuntes de XML

System.out.println(e); } } }}

 Otro ejemplo

Ejemplo DOM para el documento del libro. Imprime por pantalla el título del libro, el número de capítulos y las materias de las que trata el libro:

import org.w3c.dom.Document;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.w3c.dom.NamedNodeMap;import java.io.IOException;import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;

import java.util.HashSet;import java.util.Iterator;

public class EjemploDOM {

static int numCaps = 0; static HashSet materias = new HashSet();

public static void procesar(Node nodo) {

String nombre = nodo.getNodeName(); if (nombre.equals("Libro")) { NodeList hijos = nodo.getChildNodes(); for (int i=0; i<hijos.getLength(); i++) { procesar(hijos.item(i)); } System.out.println("Num Capítulos: " + numCaps); System.out.print("Materias: "); Iterator i = materias.iterator(); while (i.hasNext()) { System.out.print(i.next() + " "); } System.out.println(); } else if (nombre.equals("Contenido")) { NodeList hijos = nodo.getChildNodes(); for (int i=0; i<hijos.getLength(); i++) { procesar(hijos.item(i)); } } else if (nombre.equals("Titulo")) { NodeList hijos = nodo.getChildNodes(); System.out.println("Título: " + hijos.item(0).getNodeValue()); } else if (nombre.equals("Capitulo")) { numCaps++; NamedNodeMap ats = nodo.getAttributes(); materias.add(ats.item(0).getNodeValue()); } } public static void main(String[] args) { if (args.length != 1) { System.out.println("Debe haber un parámetro (el fichero)"); } else {

Page 36: Apuntes de XML

String fich = args[0]; System.out.println("Generando árbol para: " + fich + "\n"); try { DocumentBuilder parser; DocumentBuilderFactory factoria = DocumentBuilderFactory.newInstance(); parser = factoria.newDocumentBuilder(); Document doc = parser.parse(fich); procesar(doc.getDocumentElement()); System.out.println("Fin. Todo bien\n"); } catch (IOException e) { System.out.println(e); } catch (SAXException e) { System.out.println(e); } catch (ParserConfigurationException e) { System.out.println(e); } } }}

 Más formas de manipular el árbol

Casi todos los métodos que hemos visto para trabajar con DOM están definidos en la interfaz Node.

Existen un par de métodos muy útiles definidos en la interfaz Element, que hereda de Node: o Para recuperar una serie de elementos por su nombre, no necesariamente hijos

directos, tenemos getElementsByTagName, que devuelve una NodeList. Este método también está definido en la interfaz Document.

o Para recuperar el valor de un atributo a partir de su nombre, tenemos getAttribute.

Más métodos útiles, éstos otra vez en la interfaz Node: o Para extraer el primer hijo de un nodo, getFirstChild. Es muy útil para conseguir el

texto de un elemento. o Para extraer el padre de un nodo, getParentNode.

Ilustraremos estos métodos con un pequeño programa ejemplo que muestra por pantalla todas las secciones de un libro, con su número de apartados y capítulo al que pertenecen:

import org.w3c.dom.Document;import org.w3c.dom.NodeList;import org.w3c.dom.Node;import org.w3c.dom.Element;import java.io.IOException;import org.xml.sax.SAXException;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;

public class PeqEjemploDOM { public static void main(String[] args) { if (args.length != 1) { System.out.println("Debe haber un parámetro (el fichero)"); } else { String fich = args[0]; System.out.println("Generando árbol para: " + fich + "\n"); try { DocumentBuilder parser; DocumentBuilderFactory factoria = DocumentBuilderFactory.newInstance(); parser = factoria.newDocumentBuilder(); Document doc = parser.parse(fich); NodeList secciones = doc.getElementsByTagName("Seccion"); for (int i=0; i<secciones.getLength(); i++) {

Page 37: Apuntes de XML

Element sec = (Element)secciones.item(i); System.out.print(sec.getFirstChild().getNodeValue()); System.out.print(" (" + sec.getAttribute("apartados") + ", "); Element padre = (Element)sec.getParentNode(); Node tema = padre.getElementsByTagName("Tema").item(0); System.out.println(tema.getFirstChild().getNodeValue() + ")"); } } catch (IOException e) { System.out.println(e); } catch (SAXException e) { System.out.println(e); } catch (ParserConfigurationException e) { System.out.println(e); } } }} Observar que realizar el mismo programa mediante SAX sería un poco engorroso.

 Crear documentos

Nos queda pendiente crear un documento desde cero con DOM. Al no estar estandarizada esta tarea, los detalles concretos dependen del analizador que se

utilice. Primeramente necesitamos instanciar una

clase concreta

que implemente el interfaz Document. En el caso de Xerces es DocumentImpl.

Los métodos más importantes para ir componiendo el documento son: o createElement crea un nodo para un elemento (Interfaz Document). o setAttribute crea un atributo para un elemento (Interfaz Element). o createTextNode crea un nodo de tipo texto (Interfaz Document). o appendChild sirve para agregar un nodo hijo a un nodo padre, al final de su lista de

nodos hijos (Interfaz Node). o Existen otros métodos definidos en Document que crean otros tipos de nodos, como

instrucciones de proceso, secciones CDATA o referencias a entidad.

 Imprimir documentos

Una vez que hemos creado el documento, podemos imprimirlo en un flujo (por pantalla, a un fichero, etc.).

Al no estar estandarizada esta tarea, los detalles concretos dependen del analizador que se utilice.

En el caso de Xerces, necesitamos instanciar la clase XMLSerializer, especificando el flujo por el que vamos a escribir y un formato. Después pasamos nuestro documento al método serialize.

 Un ejemplo

En el siguiente ejemplo crearemos un pequeño documento con los datos de una persona y lo imprimiremos por pantalla y a un fichero.

import java.io.IOException;import java.io.StringWriter;import java.io.FileWriter;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.ProcessingInstruction;

Page 38: Apuntes de XML

import org.apache.xerces.dom.DocumentImpl;import org.apache.xml.serialize.OutputFormat;import org.apache.xml.serialize.Serializer;import org.apache.xml.serialize.SerializerFactory;import org.apache.xml.serialize.XMLSerializer;

public class CrearDOM { public static void main( String[] argv ) { try { Document doc= new DocumentImpl(); Element raiz = doc.createElement("Persona"); raiz.setAttribute("DNI", "1234567"); Element elem = doc.createElement("Nombre"); elem.appendChild(doc.createTextNode("Juan Pérez")); raiz.appendChild(elem); elem = doc.createElement("Edad"); elem.appendChild(doc.createTextNode("28")); raiz.appendChild(elem); elem = doc.createElement("Altura"); elem.appendChild(doc.createTextNode("1.75")); raiz.appendChild(elem); elem = doc.createElement("Dirección"); Element elemHijo = doc.createElement("Calle"); elemHijo.appendChild(doc.createTextNode("Castellana")); elem.appendChild(elemHijo); elemHijo = doc.createElement("Número"); elemHijo.appendChild(doc.createTextNode("155")); elem.appendChild(elemHijo); raiz.appendChild(elem); ProcessingInstruction pi = doc.createProcessingInstruction("miPI", "atr=\"prueba\""); doc.appendChild(pi); doc.appendChild(raiz);

OutputFormat formato = new OutputFormat(doc, "UTF-8", true); StringWriter s = new StringWriter(); XMLSerializer ser = new XMLSerializer(s, formato); ser.serialize(doc); System.out.println(s.toString());

FileWriter f = new FileWriter("persona.xml"); ser = new XMLSerializer(f, formato); ser.serialize(doc);

} catch (IOException e) { System.out.println(e); } }}

 Modificar documentos

También podemos modificar un documento DOM por medio de los siguientes métodos definidos en Node:

o insertBefore agrega un nodo hijo a otro nodo, permitiendo especificar la posición concreta en la lista de hijos (el hijo que va a quedar detrás del nuevo).

o removeChild elimina un nodo hijo. o replaceChild reemplaza un nodo hijo por otro. o removeAttribute elimina un atributo de un nodo (este método se define en

Element).

Page 39: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

XML y las bases de datos o Generar XML a partir de consultaso Transferir datos desde documentos XMLo Herramientaso XML como almacén de datos

XML y las bases de datos

 Generar XML a partir de consultas

Para generar XML a partir de datos almacenados en una base de datos, es necesario llevar a cabo dos tareas:

o Ejecutar hacia la base de datos la consulta deseada. o Construir un documento XML a partir de los datos obtenidos por la consulta. La forma

más cómoda de hacer esto es por medio de DOM. Veamos un ejemplo que ilustra esto:

import java.io.*;import java.sql.*;import org.w3c.dom.*;import org.apache.xerces.dom.DocumentImpl;import org.apache.xml.serialize.*;

class BDToXML { public static void main(String args[]) { try{ Class.forName("com.inet.tds.TdsDriver"); String url = "jdbc:inetdae7:localhost?database=Northwind"; Connection con = DriverManager.getConnection(url,"sa",""); Statement st = con.createStatement(); String sql = "SELECT * FROM CUSTOMERS"; ResultSet res = st.executeQuery(sql); Document doc = new DocumentImpl(); Element raiz = doc.createElement("Resultado"); ResultSetMetaData rMeta = res.getMetaData(); int nCols = rMeta.getColumnCount(); while (res.next()) { Element reg = doc.createElement("Elemento"); reg.setAttribute(rMeta.getColumnName(1), res.getString(1)); for(int i=2; i<=nCols; i++) { Element campo = doc.createElement(rMeta.getColumnName(i)); campo.appendChild(doc.createTextNode(res.getString(i))); reg.appendChild(campo); } raiz.appendChild(reg); } doc.appendChild(raiz); con.close(); OutputFormat formato = new OutputFormat(doc, "UTF-8", true); StringWriter s = new StringWriter(); XMLSerializer ser = new XMLSerializer(s, formato); ser.serialize(doc); System.out.println(s.toString()); } catch(ClassNotFoundException ex){ System.out.println(ex); } catch(SQLException ex){

Page 40: Apuntes de XML

System.out.println(ex); } catch(IOException ex){ System.out.println(ex); } }} La primera parte del código ejecuta la consulta deseada y obtiene los resultados en un objeto

de la clase ResultSet. Para ello es necesario previamente cargar un controlador y especificar una URL acordes con

la BD que se desee utilizar. Estas instrucciones y otras que siguen corresponden a la API JDBC, cuyos detalles están más

allá del alcance de este curso. Después se trata de transferir los datos del objeto ResultSet a un árbol DOM. En este ejemplo concreto cada registro de los resultados se convierte en un elemento XML. El

primer campo se convierte en un atributo y el resto en subelementos. Una vez creado el árbol DOM, imprimimos el documento XML por pantalla, aunque fácilmente

se podría llevar a un fichero o realizar alguna otra acción.

 Transferir datos desde documentos XML

El paso de datos en XML a una base de datos es un poco más engorroso. Se trata de construir y ejecutar una serie de sentencias SQL de inserción a partir de los datos

contenidos en el documento XML. Veamos los detalles de esta tarea con un ejemplo:

import java.io.*;import java.sql.*;import org.w3c.dom.*;import org.xml.sax.SAXException;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;

class XMLToBD {

public static void main(String[] args) { if (args.length != 1) { System.out.println("Debe haber un parámetro (el fichero)"); } else { String fich = args[0]; System.out.println("Generando árbol para: " + fich + "\n"); try { Class.forName("com.inet.tds.TdsDriver"); String url = "jdbc:inetdae7:localhost?database=Northwind"; Connection con = DriverManager.getConnection(url,"sa",""); Statement st = con.createStatement(); DocumentBuilder parser; DocumentBuilderFactory factoria = DocumentBuilderFactory.newInstance(); parser = factoria.newDocumentBuilder(); Document doc = parser.parse(fich); Element raiz = doc.getDocumentElement(); String tabla = raiz.getNodeName(); String sqlFija = "INSERT INTO " + tabla + "("; String nombre = tabla.substring(0, tabla.length() - 1); NodeList elems = raiz.getElementsByTagName(nombre); Node primero = elems.item(0); NodeList campos = primero.getChildNodes(); for (int i=0; i<campos.getLength(); i++) { Node n = campos.item(i); if (n.getNodeType() == Node.ELEMENT_NODE) { sqlFija += ((i==1)? "" : ", ") + n.getNodeName(); } }

Page 41: Apuntes de XML

sqlFija += ") VALUES ";

for (int i=0; i<elems.getLength(); i++) { String sqlVar = "("; Node n = elems.item(i); NodeList hijos = n.getChildNodes(); for (int j=0; j<hijos.getLength(); j++) { Node hijo = hijos.item(j); if (hijo.getNodeType() == Node.ELEMENT_NODE) { sqlVar += ((j==1)? "'" : ", '") + hijo.getFirstChild().getNodeValue() + "'"; } } sqlVar += ")"; st.executeUpdate(sqlFija + sqlVar); System.out.println(sqlFija); System.out.println(sqlVar); System.out.println(); } } catch (IOException e) { System.out.println(e); } catch (SAXException e) { System.out.println(e); } catch (ParserConfigurationException e) { System.out.println(e); } catch(ClassNotFoundException ex){ System.out.println(ex); } catch(SQLException ex){ System.out.println(ex); } } }} En la primera parte se realiza la conexión con la BD y se deja preparado un objeto Statement

que nos servirá para ejecutar las sentencias de inserción. Posteriormente obtenemos el árbol DOM para el documento XML de origen. A partir del elemento raíz y el primer subelemento de éste, construímos la primera parte del

SQL necesario para realizar inserciones de registros. Esta parte será fija para todas las inserciones, y contiene el nombre de la tabla y los nombres

de sus campos. Después, para cada elemento del documento XML que cuelgue del elemento raíz completamos

la sentencia de inserción con los valores contenidos en el elemento y ejecutamos la sentencia. En este ejemplo concreto se ha supuesto que el nombre del elemento raíz coincide con la

tabla destino y que los elementos que cuelgan del raíz se nombran con el singular del elemento raíz.

 Herramientas

Hemos visto ejemplos de la programación del proceso de conversión XML BD en ambos sentidos, por medio de las APIs DOM y JDBC.

Existen APIs de más alto nivel que nos ayudan en la programación de ese proceso. También existen multitud de productos que nos proporcionan automáticamente esa conversión

mediante un interfaz visual. Cada forma de realizar la conversión tiene su punto fuerte:

o La programación nos proporciona un completo control sobre el proceso de transformación y es válida en mayor número de circunstancias, a costa de un mayor trabajo.

o Las herramientas automáticas facilitan mucho el trabajo, a costa de menos control en el proceso y menor rango de situaciones de uso.

 XML como almacén de datos

Page 42: Apuntes de XML

Hemos visto ampliamente cómo XML es un formato totalmente orientado hacia los datos. Vimos en la introducción que uno de los usos de XML es la configuración. Hay ejemplos reales

bastante importantes de este uso, como los descriptores para EJBs, o la configuración del servidor de servlets Apache Tomcat.

Lo siguiente es preguntarnos si podríamos llegar a tener como base de datos un sistema que funcione exclusivamente con XML.

Dicho sistema nos ahorraría las conversiones que hemos analizado en los apartados anteriores, ganando principalmente en rapidez.

Hay una serie de problemas que van en contra, al menos a corto plazo, de esta posibilidad: o Multitud de aplicaciones (por no decir casi todas) que utilizan actualmente algún sistema

de bases de datos relacionales (Oracle, SQL Server, Sybase, MySQL, etc.). o Tamaño de las bases de datos necesarias. o Representación en XML de datos relaciones.

De todas formas, ya existen multitud de sistemas de BBDD que funcionan exclusivamente con XML y que pueden ser válidos en determinadas circunstancias (pequeñas cantidades de datos, sistemas no heredados, etc.).

Page 43: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Otros temas de interés o XLinko JDOM

Otra API más Ventajas y desventajas Una API en desarrollo

o Marcos de publicación web El problema Soluciones con tecnología conocida Contenido y presentación La solución: marcos de publicación web Ventajas Un ejemplo de marco de publicación: Cocoon

Otros temas de interés

 XLink

Es un lenguaje XML que nos permite especificar enlaces entre documentos XML. Ofrece muchas más posibilidades de enlace que el elemento <a href=...> ... </a>

recogido en el estándar HTML. Veamos un ejemplo de código:

<environment xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="extended"> <artist xlink:type="locator" xlink:label="artist" xlink:href="modigliani.xml"/> <influence xlink:type="locator" xlink:label="inspiration" xlink:href="cezanne.xml"/> <influence xlink:type="locator" xlink:label="inspiration" xlink:href="lautrec.xml"/> <influence xlink:type="locator" xlink:label="inspiration" xlink:href="rouault.xml"/> <history xlink:type="locator" xlink:label="period" xlink:href="paris.xml"/> <history xlink:type="locator" xlink:label="period" xlink:href="kisling.xml"/> <bind xlink:type="arc" xlink:from="artist" xlink:to="inspiration"/> <bind xlink:type="arc" xlink:from="artist" xlink:to="period"/> </environment> En XLink existen dos tipos de enlaces: simples (como los elementos a ó img de HTML) y

extendidos. Los recursos y enlaces se representan con elementos, pudiendo elegir libremente el nombre

de los mismos. Para recursos externos se usa el tipo locator, para recursos internos resource. Para especificar finalmente los enlaces se usa el tipo arc. Como se puede observar, la característica más atractiva de XLink es que podemos tener

enlaces múltiples. Existe un lenguaje complementario, Xpointer (basado en Xpath), que permite realizar enlaces a

partes de un documento o incluso a elementos individuales. Para que XLink y Xpointer sean realmente útiles se deben ir implementando progresivamente en

los navegadores.

 JDOM

 Otra API más

Es otra API para manipular documentos XML, pero sólo desde programas escritos en Java. Pretende ser una alternativa a la API DOM, con las siguientes características principales:

o Más fácil de usar.

Page 44: Apuntes de XML

o Más adecuada a Java. o Más rápida. o Independiente de cualquier analizador (recordar problemas con la creación y

serialización de documentos). o Que se integre bien con SAX y DOM.

A continuación se muestra un ejemplo que extrae el título y los capítulos del documento del libro, utilizando para ello JDOM:

import java.io.File;import java.util.List;import org.jdom.input.DOMBuilder;import org.jdom.*;

public class PeqEjemplo { public static void main(String[] args) { if (args.length != 1) { System.out.println("Debe haber un parámetro (el fichero)"); } else { String fich = args[0]; System.out.println("Generando árbol para: " + fich + "\n"); try { DOMBuilder b = new DOMBuilder("org.jdom.adapters.XercesDOMAdapter"); Document doc = b.build(new File(fich)); Element raiz = doc.getRootElement(); Namespace ns = Namespace.getNamespace ("http://www.mislibros.com/libros/javaxml"); Element tit = raiz.getChild("Titulo", ns); System.out.println(tit.getText() + "\n"); Element cont = raiz.getChild("Contenido", ns); List caps = cont.getChildren("Capitulo", ns); for (int i=0; i<caps.size(); i++) { Element cap = (Element)caps.get(i); System.out.println(cap.getChildText("Tema", ns)); } } catch (JDOMException e) { System.out.println(e); } } }}

 Ventajas y desventajas

Como aspectos positivos de JDOM, a modo de ejemplo, se pueden observar los siguientes, que facilitan el trabajo con los documentos XML:

o El método getText() devuelve directamente el texto contenido en un elemento, mientras que la forma más simple de hacerlo con DOM sería getFirstChild().getNodeValue().

o Otro método muy útil es getChildText(), que devuelve el texto de un hijo. Esta misma tarea con DOM requeriría bastante más código.

o Se utilizan clases estándar del estilo List y Map, incluidas en Java desde su versión 1.2, en lugar de las clases NodeList y NamedNodeMap que vienen con DOM.

o Existen una serie de adaptadores que permiten construir un documento especificando un determinado analizador, pero sin necesidad de importar explícitamente la clase necesaria (portabilidad).

En cuanto a los aspectos negativos de JDOM, también a modo de ejemplo: o No existe un método equivalente al muy útil getElementsByTagName que con DOM

nos permitía obtener elementos de cualquier nivel por debajo del actual. o Es necesario especificar el espacio de nombres, incluso cuando se trabaja sin prefijo

alguno.

 Una API en desarrollo

Page 45: Apuntes de XML

De cualquier forma, la API JDOM todavía se encuentra en fase beta, por lo que es previsible que cambie algo hasta la finalización de la versión 1.0.

Actualmente forma parte del JCP (Java Community Process) mediante una JSR (Java Specification Request), por lo que seguramente formará parte de una versión futura del JDK.

 Marcos de publicación web

 El problema

Imaginemos un gran sitio web formado por decenas o incluso cientos de páginas HTML. Se desea permitir un acceso múltiple al contenido a través de un navegador o a través de

móviles WAP (sin descartar más formas de acceso en el futuro), e incluso que se puedan imprimir los contenidos con calidad utilizando un formato como PDF.

También es deseable que se pueda realizar sin demasiada dificultad un completo cambio de imagen en todo el sitio web.

 Soluciones con tecnología conocida

Las hojas de estilo en cascada (CSS) pueden ayudar un poco en esta tarea, pero no lo suficiente.

Con un sistema basado en Java Servlets se debería cambiar el código de éstos, e incluso añadir más servlets, con las consiguientes recompilaciones, configuraciones y riesgos para el funcionamiento del sistema.

Una solución bastante buena es el uso de páginas JSP, sobre todo si se combina con el uso de beans y librerías de etiquetas.

 Contenido y presentación

De lo que se trata en el fondo es de hallar la mejor forma de separar contenido y presentación. Por un lado tendríamos el contenido, los datos, y por otro lado distintas vistas o formas de

presentar los datos. De esta forma un cambio de imagen sólo afecta a una o varias vistas. La necesidad de mostrar

los datos en otro formato sólo implica la creación de otra vista.

 La solución: marcos de publicación web

Un marco de publicación es un sistema que sirve contenido web aplicando los principios de la separación entre contenido y presentación que hemos visto.

Para el contenido se utiliza XML y para la presentación XSL (tanto XSLT como XSL-FO). Más en detalle, un marco de publicación web XML/XSL es un sistema que:

o Admite peticiones de documentos en diversos formatos. o Obtiene la información adecuada de las posibles fuentes de datos XML. o Obtiene la información sobre las transformaciones XSL necesarias y se las aplica a

los datos. o Formatea el resultado final y lo sirve como respuesta a la petición inicial.

 Ventajas

Separación limpia entre contenido y presentación (que lleva consigo la separación clara entre distintos roles de trabajo).

Proporciona una mejora muy notable del mantenimiento: se puede realizar un cambio radical de imagen de todo un site web con tan solo modificar las hojas XSL y sin tocar ni una sola línea de código.

A partir de un solo documento XML con el contenido, se pueden obtener páginas HTML para su presentación web, páginas WML para dispositivos WAP, documentos PDF para imprimir, etc.

Aunque no hay ningún estándar que regule cómo debe ser un sistema de publicación, si que está basado en estándares con mucha fuerza en el mercado, por lo que es más sencillo pasar de usar uno a usar otro.

Es compatible con el resto de tecnologías web como servlets, JSPs...

 Un ejemplo de marco de publicación: Cocoon

Page 46: Apuntes de XML

La principal desventaja de estos sistemas es la poca madurez de la mayoría. El más maduro y reconocido en este momento es Cocoon, cuya versión 2.0 ya se encuentra

disponible, con muchas mejoras en cuanto a facilidad de uso y eficiencia sobre la serie 1.x. Veamos algunas de sus características:

o Forma parte del proyecto colaborativo de código abierto Apache. o Es altamente configurable. Por ejemplo, podemos elegir el analizador XML y el

procesador XSLT que más nos gusten. o Permite diferenciar el procesado del documento en función del dispositivo o tipo de

software que realiza la petición. o Incorpora un sistema de caché que permite un rendimiento muy elevado. o Puede trabajar como un programa en línea de comandos pero su uso normal es como

un sistema de servlets para la publicación a través de la Web. o Incorpora las páginas XSP, que son documentos XML que aparte de contenido estático

incluyen lógica para crear XML dinámicamente. Son parecidas a las páginas JSP, pero pretenden solucionar algunos problemas de éstas.

Page 47: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Servicios web o Introduccióno Terminología

Tecnologías estándar APIs Java

o JAXR Registros Introducción a JAXR Un cliente JAXR

o JAXM Mensajes SOAP Introducción a JAXM Ejemplos

o JAX-RPC Introducción Un ejemplo

Servicios web

 Introducción

Veamos una definición formal de un servicio web: "Aplicación modular, auto-contenida y auto-descriptiva que puede ser publicada, localizada e invocada a través de Internet".

Los servicios web hacen posible la comunicación entre aplicaciones en Internet, donde conviven múltiples plataformas y aplicaciones construidas en diversos lenguajes.

En los últimos años se han venido utilizando otras tecnologías como RMI, CORBA o DCOM, pero ninguna de ellas asegura una compatibilidad total.

Los servicios web hacen posible esta compatibilidad al estar basados en tecnologías estándar e independientes de plataformas y lenguajes, como HTTP, WSDL, UDDI, SOAP o XML-RPC.

 Terminología

 Tecnologías estándar

WSDL: Lenguaje para describir servicios web. UDDI: Especificación para registros de servicios web. SOAP: Lenguaje que especifica la forma de enviar mensajes XML a través de Internet. XML-RPC: Mecanismo para invocación remota de procedimientos (métodos) utilizando XML

como forma de comunicación.

 APIs Java

JAXR: Acceso a directorios de servicios. JAXM: Envío de mensajes XML. JAX-RPC: Uso de XML-RPC desde Java.

 JAXR

 Registros

Un registro es una infraestructura que facilita el descubrimiento de servicios web. Este tipo de registros se encuentran disponibles para cualquier organización, normalmente como

un servicio web más. Existen varias especificaciones para estos registros, las más importantes:

o UDDI, desarrollada por una serie de empresas.

Page 48: Apuntes de XML

o ebXML, desarrollada por las organizaciones OASIS y U.N./CEFACT

 Introducción a JAXR

Es una API para Java que permite trabajar con los registros de servicios web sin preocuparnos de los detalles de los documentos XML que intervienen en las operaciones.

Es independiente del tipo de registro concreto al que accedemos, pues se utiliza un modelo de contenido unificado.

Permite realizar las siguientes operaciones básicas: buscar servicios web disponibles, publicar servicios web, modificar los datos de un servicio, eliminar un servicio.

 Un cliente JAXR

A continuación mostramos el código de un programa que busca servicios web en un registro a partir de una cadena de caracteres de entrada.

import javax.xml.registry.*; import javax.xml.registry.infomodel.*; import java.net.*;import java.util.*;

public class JAXRQuery {

public static void main(String[] args) {

if (args.length != 1) { System.out.println("Usage: java " + "JAXRQuery <query-string>"); System.exit(1); } String queryString = new String(args[0]); System.out.println("Query string is " + queryString); JAXRQuery jq = new JAXRQuery(); jq.executeQuery(queryString); } public void executeQuery(String qString) { Connection connection = null;

// Definir propiedades de configuración Properties props = new Properties(); props.setProperty("javax.xml.registry.queryManagerURL", "http://uddi.microsoft.com:80/inquire"); props.setProperty("javax.xml.registry.factoryClass", "com.sun.xml.registry.uddi.ConnectionFactoryImpl");

try { // Crear la conexión con las propiedades definidas ConnectionFactory factory = ConnectionFactory.newInstance(); factory.setProperties(props); connection = factory.createConnection();

// Obtener gestor de consultas RegistryService rs = connection.getRegistryService(); BusinessQueryManager bqm = rs.getBusinessQueryManager(); System.out.println("Got registry service and " + "query manager");

// Definir opciones y patrón de búsqueda Collection findQualifiers = new ArrayList(); findQualifiers.add(FindQualifier.SORT_BY_NAME_DESC); Collection namePatterns = new ArrayList(); namePatterns.add("%" + qString + "%");

// Buscar organizaciones BulkResponse response =

Page 49: Apuntes de XML

bqm.findOrganizations(findQualifiers, namePatterns, null, null, null, null); Collection orgs = response.getCollection();

// Mostrar información de las organizaciones obtenidas Iterator orgIter = orgs.iterator(); while (orgIter.hasNext()) { Organization org = (Organization) orgIter.next(); System.out.println("Org name: " + getName(org)); System.out.println("Org description: " + getDescription(org)); System.out.println("Org key id: " + getKey(org));

// Información de contacto User pc = org.getPrimaryContact(); if (pc != null) { PersonName pcName = pc.getPersonName(); System.out.println(" Contact name: " + pcName.getFullName()); Collection phNums = pc.getTelephoneNumbers(pc.getType()); Iterator phIter = phNums.iterator(); while (phIter.hasNext()) { TelephoneNumber num = (TelephoneNumber) phIter.next(); System.out.println(" Phone number: " + num.getNumber()); } Collection eAddrs = pc.getEmailAddresses(); Iterator eaIter = eAddrs.iterator(); while (phIter.hasNext()) { System.out.println(" Email Address: " + (EmailAddress) eaIter.next()); } }

// Información de los servicios Collection services = org.getServices(); Iterator svcIter = services.iterator(); while (svcIter.hasNext()) { Service svc = (Service) svcIter.next(); System.out.println(" Service name: " + getName(svc)); System.out.println(" Service description: " + getDescription(svc)); Collection serviceBindings = svc.getServiceBindings(); Iterator sbIter = serviceBindings.iterator(); while (sbIter.hasNext()) { ServiceBinding sb = (ServiceBinding) sbIter.next(); System.out.println(" Binding " + "Description: " + getDescription(sb)); System.out.println(" Access URI: " + sb.getAccessURI()); } } System.out.println(" --- "); } } catch (Exception e) { e.printStackTrace(); } finally { // Cerrar conexión if (connection != null) { try { connection.close(); } catch (JAXRException je) {} } }

Page 50: Apuntes de XML

}

private String getName(RegistryObject ro) throws JAXRException { try { return ro.getName().getValue(); } catch (NullPointerException npe) { return ""; } } private String getDescription(RegistryObject ro) throws JAXRException { try { return ro.getDescription().getValue(); } catch (NullPointerException npe) { return ""; } } private String getKey(RegistryObject ro) throws JAXRException { try { return ro.getKey().getId(); } catch (NullPointerException npe) { return ""; } }}

 JAXM

 Mensajes SOAP

Un mensaje SOAP tiene la siguiente estructura: o Parte SOAP

Cabecera (opcional) Cuerpo

o Parte adjunta 1 (opcional, p. ej. texto plano) o Parte adjunta 2 (opcional, p. ej. una imagen)

 Introducción a JAXM

Es una API para Java que permite trabajar con mensajes SOAP sin preocuparnos de los detalles de los documentos XML que intervienen en las operaciones.

Permite enviar mensajes de dos formas: o Mediante una conexión punto a punto: el programa envía el mensaje directamente al

destinatario, quedando bloqueado a la espera de una respuesta. o Mediante un proveedor de mensajes: se envía el mensaje a un proveedor que será el

encargado de hacerlo llegar al destinatario, sin producirse ningún bloqueo en espera de una respuesta.

 Ejemplos

El siguiente programa construye un mensaje SOAP, en el que se pregunta por el precio de cotización de una compañía, lo envía a un servicio de información de cotizaciones, y muestra el resultado obtenido:

import javax.xml.soap.*;import javax.xml.messaging.*;import java.io.*;import java.util.*;

public class Request { public static void main(String[] args) { try { // Crear la conexión SOAPConnectionFactory scFactory =

Page 51: Apuntes de XML

SOAPConnectionFactory.newInstance(); SOAPConnection con = scFactory.createConnection(); // Crear el mensaje MessageFactory factory = MessageFactory.newInstance(); SOAPMessage message = factory.createMessage();

// Obtener componentes del mensaje SOAPPart soapPart = message.getSOAPPart(); SOAPEnvelope envelope = soapPart.getEnvelope(); SOAPHeader header = envelope.getHeader(); SOAPBody body = envelope.getBody(); // Quitar cabecera header.detachNode();

// Añadir elemento para llamada Name bodyName = envelope.createName("GetLastTradePrice", "m", "http://wombat.ztrade.com"); SOAPBodyElement gltp = body.addBodyElement(bodyName);

// Añadir elemento para dato de entrada Name name = envelope.createName("symbol"); SOAPElement symbol = gltp.addChildElement(name); symbol.addTextNode("SUNW");

// URL Destino URLEndpoint endpoint = new URLEndpoint( "http://wombat.ztrade.com/quotes"); // Envíar mensaje - bloqueo - obtener respuesta SOAPMessage response = con.call(message, endpoint);

/* Mensaje SOAP

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" <SOAP-ENV:Body> <m:GetLastTradePrice xmlns:m= "http://wombat.ztrade.com"> <symbol>SUNW</symbol> </m:GetLastTradePrice> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

*/ // Cerrar la conexión con.close();

// Obtener cuerpo del mensaje SOAPPart sp = response.getSOAPPart(); SOAPEnvelope se = sp.getEnvelope(); SOAPBody sb = se.getBody(); // Obtener respuesta Iterator it = sb.getChildElements(bodyName); SOAPBodyElement bodyElement = (SOAPBodyElement)it.next(); String lastPrice = bodyElement.getValue();

// Imprimir respuesta System.out.print("The last price for SUNW is "); System.out.println(lastPrice);

} catch (Exception ex) { ex.printStackTrace(); } }}

Page 52: Apuntes de XML

El siguiente programa envía un mensaje SOAP con un nombre de compañía a un registro UDDI, y muestra los datos obtenidos del registro:

import javax.xml.soap.*;import javax.xml.messaging.*;import java.util.*;import java.io.*;

public class MyUddiPing {

public static void main(String[] args) { try {

// Comprobar el argumento de entrada if (args.length != 1) { System.err.println("Usage: UddiPing business-name"); System.exit(1); }

// Crear la conexión y el mensaje SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance(); SOAPConnection connection = scf.createConnection(); MessageFactory msgFactory = MessageFactory.newInstance(); SOAPMessage msg = msgFactory.createMessage(); // Obtener el cuerpo del mensaje SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope(); SOAPBody body = envelope.getBody();

// Añadir información de consulta SOAPBodyElement findBusiness = body.addBodyElement(envelope. createName("find_business", "", "urn:uddi-org:api")); findBusiness.addAttribute(envelope.createName("generic"), "1.0"); findBusiness.addAttribute(envelope.createName("maxRows"), "100"); SOAPElement businessName = findBusiness.addChildElement( envelope.createName("name")); businessName.addTextNode(args[0]); // URL destino URLEndpoint endpoint = new URLEndpoint ("http://www-3.ibm.com/services/uddi/testregistry/inquiryapi"); // Envíar mensaje - bloqueo - obtener respuesta SOAPMessage reply = connection.call(msg, endpoint); // Escribir mensaje de respuesta en un fichero System.out.println("Received reply from: " + endpoint); reply.writeTo(new FileOutputStream("res.xml")); // Extraer el cuerpo SOAPBody replyBody = reply.getSOAPPart().getEnvelope().getBody(); System.out.println(""); System.out.println(""); System.out.print( "Content extracted from the reply message: "); // Mostrar información Iterator iter1 = replyBody.getChildElements(); while (iter1.hasNext()) { SOAPBodyElement bodyElement = (SOAPBodyElement)iter1.next(); Iterator iter2 = bodyElement.getChildElements(); while (iter2.hasNext()) { SOAPElement child2 = (SOAPElement)iter2.next(); Iterator iter3 = child2.getChildElements(); String content = child2.getValue(); System.out.println(content);

Page 53: Apuntes de XML

while (iter3.hasNext()) { SOAPElement child3 = (SOAPElement)iter3.next(); Iterator iter4 = child3.getChildElements(); content = child3.getValue(); System.out.println(content); while (iter4.hasNext()) { SOAPElement child4 = (SOAPElement)iter4.next(); content = child4.getValue(); System.out.println(content); } } }

}

// Cerrar la conexión connection.close(); } catch (Exception ex) { ex.printStackTrace(); } }}

 JAX-RPC

 Introducción

Es una API para Java que permite construir servicios web y clientes para los servicios sin preocuparnos de los detalles de los documentos XML que intervienen en las operaciones.

Las llamadas a los métodos y las respuestas se implementan mediante mensajes SOAP. En un servicio web, los métodos que lo constituyen se definen en un interfaz y se implementan

en una clase aparte. En un cliente, las llamadas a los métodos se realizan mediante objetos locales que representan

el método remoto (stubs). Un cliente escrito con JAX-RPC puede interactuar con un servicio escrito en otro lenguaje, y

viceversa, pues esta tecnología se basa en una serie de estándares como HTTP, SOAP y WSDL.

 Un ejemplo

A continuación se muestra un sencillo ejemplo de servicio con un cliente que lo utiliza:

package SR;

import java.rmi.Remote;import java.rmi.RemoteException;

public interface SRInt extends Remote { public int suma(int a, int b) throws RemoteException; public int resta(int a, int b) throws RemoteException;}

package SR;

public class SRImpl implements SRInt {

public int suma(int a, int b) { return a + b; } public int resta(int a, int b) { return a - b; }}

Page 54: Apuntes de XML

package SR;

public class SRClient { public static void main(String[] args) { try { SRInt_Stub stub = (SRInt_Stub)(new ServicioSRImpl().getSRInt()); stub._setTargetEndpoint(args[0]); System.out.println(stub.suma(3, 8)); System.out.println(stub.resta(23, 8)); } catch (Exception ex) { ex.printStackTrace(); } }}

Page 55: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Bibliografía recomendada o En ingléso En castellano

Bibliografía recomendada

 En inglés

Java & XML, 2nd Edition: Solutions to Real-World ProblemsOReillyBrett McLaughlinSeptiembre 2001

Modeling XML Applications with UMLAddison WesleyDavid CarlsonAbril 2001

 En castellano

Java y XMLAnaya OReillyBrett McLaughlin2001

Guía de aprendizaje XMLPrentice HallElizabeth Castro2001

Page 56: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Enlaces recomendados o Generaleso Introduccióno Creación de documentos XMLo Restricción de documentos XMLo Presentación y transformación de documentos XMLo Manipulación de XML desde programas Javao XML y las bases de datoso Otros temas de interéso Servicios web

Enlaces recomendados

 Generales

Últimas noticias sobre XML (inglés) Enlaces a software XML (inglés) Java y XML (inglés) Proyecto colaborativo Apache XML (inglés) XML en Microsoft (inglés) Diseño de aplicaciones XML con UML (inglés)

 Introducción

XML en 10 puntos Breve tutorial de Ángel Barbero FAQ sobre XML (inglés) Motivación del XML (inglés)

 Creación de documentos XML

Especificación XML en castellano Especificación XML comentada (inglés) Sencillo editor XML (inglés) Completo editor XML con innumerables opciones (inglés)

 Restricción de documentos XML

Tutorial sobre DTD Otro tutorial sobre DTD (inglés) Tutorial sobre esquemas XML (inglés) Completísimo curso sobre esquemas XML en transparencias (inglés)

 Presentación y transformación de documentos XML

Uso de CSS con XML Más sobre uso de CSS con XML Documentación de Microsoft, sobre XSLT, Xpath, etc. Tutorial sobre XSLT con numerosos ejemplos (inglés) Tutorial sobre XSLT y Xpath (inglés) Especificación XPath en castellano

 Manipulación de XML desde programas Java

Page 57: Apuntes de XML

Tutorial traducido del sitio oficial de Sun, sobre SAX, DOM, XML, DTD, etc. Página de SAX (inglés) Página de DOM en el W3C (inglés) Página del analizador Xerces (inglés) Página del procesador (XSLT) Xalan (inglés)

 XML y las bases de datos

APIs y herramientas de conversión (inglés) Bases de datos nativas XML (inglés)

 Otros temas de interés

XLink (inglés) JDOM (inglés) Tutorial sobre Cocoon Página de Cocoon (inglés)

 Servicios web

Noticias y artículos Java y servicios web

Page 58: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Material utilizado o Bibliografíao Enlaceso Herramientas

Material utilizado

 Bibliografía

Java y XMLAnaya OReillyBrett McLaughlin2001

Guía de aprendizaje XMLPrentice HallElizabeth Castro2001

 Enlaces

Tutorial traducido del sitio oficial de Sun, sobre SAX, DOM, XML, DTD, etc. Curso sobre esquemas XML de Roger L. Costello XML en Microsoft Tutorial sobre XLink Página de JDOM Tutorial sobre Cocoon Tutorial de Sun sobre servicios web

 Herramientas

XMLSpy 4.3 (versión de evaluación) JDK 1.4 Xerces (Apache) JWSDP EA1

Page 59: Apuntes de XML

Apuntes de XMLAutor: Diego Arranz Hernando

Ejercicios o Creación de documentos XML

Enunciado Solución

o DTDs Enunciado Solución

o Esquemas XML Enunciado Solución

o XSLT Enunciado Solución

o SAX Enunciado Solución

o DOM Enunciado Solución

o DOM (otro) Enunciado Solución

Ejercicios

 Creación de documentos XML

 Enunciado

Construir un documento XML para el siguiente pedido que ha recibido por correo electrónico una empresa que se dedica a la venta de herramientas para jardinería:

"Hola, necesito una cortadora de cesped para mi jardín de esas que anuncian en oferta, me gustaría que fuera uno de esos modelos eléctricos, pues las de gasolina contaminan mucho. Me llamo Roberto Movilla, la cortadora la tendrán que enviar a Albacete, la dirección es Plaza de la Duquesa 12, la recogerá mi esposa que se llama Alicia Abad. Ahora que lo pienso también necesitaré 3 podadoras para los setos. Les paso mi dirección de aquí para lo referente al pago, es General Ricardos 56, aquí en Madrid. Es urgente, por favor, el césped está muy alto."

La fecha del pedido es el 20 de octubre del 99. El empleado que se encarga del pedido ha comprobado algunos datos necesarios: el código postal de la dirección de Albacete es 05020 y el de la de Madrid 28055; también ha consultado el catálogo de productos y ha averiguado que la cortadora vale 148.95 euros y su código de producto es 872-AA, aunque no sabe si es o no eléctrica; una podadora vale 7.98 y su código es 926-FH.

 Solución

<?xml version="1.0" encoding="ISO-8859-1"?><Pedido xmlns="http://www.miempresa.org/pedidos" fecha="1999-10-20"> <Destino> <Nombre>Alicia Abad</Nombre> <Direccion>Plaza de la Duquesa 12</Direccion> <Ciudad>Albacete</Ciudad> <CodPostal>05020</CodPostal> </Destino> <Ordenante>

Page 60: Apuntes de XML

<Nombre>Roberto Movilla</Nombre> <Direccion>General Ricardos 56</Direccion> <Ciudad>Madrid</Ciudad> <CodPostal>28055</CodPostal> </Ordenante> <Observaciones>Es urgente, el césped está muy alto</Observaciones> <Contenido> <Producto codigo="872-AA"> <Nombre>Cortadora de cesped</Nombre> <Cantidad>1</Cantidad> <Precio>148.95</Precio> <Observaciones>Confirmar que es eléctrica</Observaciones> </Producto> <Producto codigo="926-FH"> <Nombre>Podadora</Nombre> <Cantidad>3</Cantidad> <Precio>7.98</Precio> </Producto> </Contenido></Pedido>

 DTDs

 Enunciado

Construir un documento DTD para el documento XML del ejercicio anterior.

 Solución

<!DOCTYPE Pedido SYSTEM "Pedido.dtd">

...

<!ELEMENT Pedido (Destino, Ordenante, Observaciones, Contenido)><!ATTLIST Pedido xmlns CDATA #REQUIRED fecha CDATA #REQUIRED><!ELEMENT Destino (Nombre, Direccion, Ciudad, CodPostal)><!ELEMENT Ordenante (Nombre, Direccion, Ciudad, CodPostal)><!ELEMENT Nombre (#PCDATA)><!ELEMENT Direccion (#PCDATA)><!ELEMENT Ciudad (#PCDATA)><!ELEMENT CodPostal (#PCDATA)><!ELEMENT Observaciones (#PCDATA)><!ELEMENT Contenido (Producto+)><!ELEMENT Producto (Nombre, Cantidad, Precio, Observaciones?)><!ATTLIST Producto codigo CDATA #REQUIRED><!ELEMENT Cantidad (#PCDATA)><!ELEMENT Precio (#PCDATA)>

 Esquemas XML

 Enunciado

Construir un esquema XML para la siguiente DTD:

<!ELEMENT Libro (Titulo, Contenido, Copyright)><!ATTLIST Libro xmlns CDATA #REQUIRED><!ELEMENT Titulo (#PCDATA)><!ELEMENT Contenido ((Capitulo+, Separacion?)+)><!ELEMENT Capitulo (Tema, Seccion+)><!ATTLIST Capitulo

Page 61: Apuntes de XML

materia (XML|Java) "Java"><!ELEMENT Tema (#PCDATA)><!ELEMENT Seccion (#PCDATA)><!ATTLIST Seccion apartados CDATA #REQUIRED dificil (si|no) "no"><!ELEMENT Separacion EMPTY><!ELEMENT Copyright (#PCDATA)>

y probarlo con este documento:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>

<!DOCTYPE Libro [<!ENTITY OReillyCopyright SYSTEM "copyright.txt">]>

<Libro xmlns="http://www.mislibros.com/libros/javaxml" xmlns:Catalogo="http://www.mislibros.com/catalogo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mislibros.com/libros/javaxml libro.xsd">

<Titulo>Java y XML</Titulo> <Contenido>

<Capitulo materia="XML"> <Tema>Introducción</Tema> <Seccion apartados="7">Qué es</Seccion> <Seccion apartados="3">Cómo se usa</Seccion> </Capitulo>

<Capitulo materia="XML"> <Tema>Creando XML</Tema> <Seccion apartados="0">Un documento XML</Seccion> <Seccion apartados="2">La cabecera</Seccion> <Seccion apartados="6">El contenido</Seccion> </Capitulo>

<Capitulo> <Tema>Analizando XML</Tema> <Seccion apartados="3">Preparación</Seccion> <Seccion apartados="3" dificil="true">SAX</Seccion> <Seccion apartados="9" dificil="true">Manejadores</Seccion> <Seccion apartados="0">Una forma mejor de cargar el analizador</Seccion> </Capitulo>

<Separacion/>

<Capitulo materia="Java"> <Tema>JDOM</Tema> <Seccion apartados="2">Introducción</Seccion> <Seccion apartados="4" dificil="true">DOM&amp;JDOM</Seccion> </Capitulo> </Contenido>

<Copyright>&OReillyCopyright;</Copyright> </Libro>

 Solución

<?xml version="1.0"?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.mislibros.com/libros/javaxml" xmlns="http://www.mislibros.com/libros/javaxml" elementFormDefault="qualified">

Page 62: Apuntes de XML

<xs:element name="Libro" type="TipoLibro"/>

<xs:complexType name="TipoLibro"> <xs:sequence> <xs:element name="Titulo" type="xs:string"/> <xs:element name="Contenido" type="TipoContenido"/> <xs:element name="Copyright" type="xs:string"/> </xs:sequence></xs:complexType>

<xs:complexType name="TipoContenido"> <xs:sequence maxOccurs="unbounded"> <xs:element name="Capitulo" type="TipoCapitulo" maxOccurs="unbounded"/> <xs:element name="Separacion" type="TipoVacio" minOccurs="0"/> </xs:sequence></xs:complexType>

<xs:complexType name="TipoCapitulo"> <xs:sequence> <xs:element name="Tema" type="xs:string"/> <xs:element name="Seccion" type="TipoSeccion" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="materia" type="TipoMateria" default="Java"/></xs:complexType>

<xs:complexType name="TipoSeccion"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="apartados" type="xs:nonNegativeInteger" use="required"/> <xs:attribute name="dificil" type="xs:boolean" default="false"/> </xs:extension> </xs:simpleContent></xs:complexType>

<xs:simpleType name="TipoMateria"> <xs:restriction base="xs:string"> <xs:enumeration value="Java"/> <xs:enumeration value="XML"/> </xs:restriction></xs:simpleType>

<xs:complexType name="TipoVacio"/>

</xs:schema>

 XSLT

 Enunciado

A partir del siguiente documento XML, realizar una hoja de estilo XSLT que muestre los datos en una tabla, con las siguientes características: las empresas aparecen ordenadas por el precio de cotización, los precios supreriores a 75 aparecen en azul y los inferiores a 25 en rojo, las empresas del índice general aparecen marcadas con un (*), con una explicación debajo de la tabla. El título del documento refleja el día y hora de la información.

<?xml version="1.0" ?><Bolsa xmlns="http://www.labolsa.com" dia="5-7-2001" hora="11:34"> <Empresa indice="general"> <Nombre>General Motors</Nombre> <Simbolo>GMO</Simbolo> <Precio>28.875</Precio> </Empresa> <Empresa indice="tecno"> <Nombre>Adobe</Nombre> <Simbolo>ADB</Simbolo> <Precio>92.250</Precio> </Empresa> <Empresa indice="tecno">

Page 63: Apuntes de XML

<Nombre>Microsoft</Nombre> <Simbolo>MSF</Simbolo> <Precio>20.313</Precio> </Empresa> <Empresa indice="general"> <Nombre>Coca-Cola</Nombre> <Simbolo>COC</Simbolo> <Precio>38.895</Precio> </Empresa> <Empresa indice="tecno"> <Nombre>Sun Microsystems</Nombre> <Simbolo>SUN</Simbolo> <Precio>45.119</Precio> </Empresa></Bolsa>

 Solución

<?xml version="1.0" encoding="ISO-8859-1" ?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:Bolsa="http://www.labolsa.com" version="1.0">

<xsl:template match="Bolsa:Bolsa"><html> <head> <title>La bolsa el <xsl:value-of select="@dia" /> a las <xsl:value-of select="@hora" /></title> </head> <body> <table border="2" align="center"> <tr> <th>Símbolo</th> <th>Nombre</th> <th>Precio</th> </tr> <xsl:for-each select="Bolsa:Empresa"> <xsl:sort select="Bolsa:Precio" order="descending"/> <tr> <td> <xsl:value-of select="Bolsa:Simbolo"/> </td> <td> <xsl:value-of select="Bolsa:Nombre"/> <xsl:if test="@indice='general'"> (*)</xsl:if> </td> <td> <xsl:choose> <xsl:when test="Bolsa:Precio &gt; 75"> <font color="blue"><xsl:value-of select="Bolsa:Precio"/></font> </xsl:when> <xsl:when test="Bolsa:Precio &lt; 25"> <font color="red"><xsl:value-of select="Bolsa:Precio"/></font> </xsl:when> <xsl:otherwise> <xsl:value-of select="Bolsa:Precio"/> </xsl:otherwise> </xsl:choose> </td> </tr> </xsl:for-each> </table> <p align="center">(*) Estas empresas son del índice general</p> </body></html></xsl:template>

</xsl:stylesheet>

Page 64: Apuntes de XML

 SAX

 Enunciado

Realizar mediante SAX un programa para el documento del libro. El programa debe escribir en un fichero los títulos de los capítulos y un pequeño resumen para cada uno de ellos con el número de secciones, de apartados totales y de apartados difíciles.

 Solución

import java.io.IOException;import java.io.FileWriter;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import org.xml.sax.Attributes;import org.xml.sax.ContentHandler;import org.xml.sax.Locator;import org.xml.sax.helpers.XMLReaderFactory;

public class EjercicioSAX {

public static void main(String[] args) { if (args.length != 1) { System.out.println("Debe haber un parámetro (el fichero)"); } else { String fich = args[0]; System.out.println("Analizando: " + fich + "\n"); try { XMLReader parser = XMLReaderFactory.createXMLReader( "org.apache.xerces.parsers.SAXParser"); ManejadorCaps man = new ManejadorCaps(); parser.setContentHandler(man); parser.parse(fich); System.out.println("Fin del análisis. Todo bien\n"); } catch (IOException e) { System.out.println(e); } catch (SAXException e) { System.out.println(e); } } }}

class ManejadorCaps implements ContentHandler { private Locator loc; private FileWriter f; private boolean extraer; private int numSecciones; private int numApartados; private int numDificiles;

public void setDocumentLocator(Locator l) { loc = l; }

public void startDocument() throws SAXException { try { numSecciones = 0; numApartados = 0; numDificiles = 0; f = new FileWriter("capitulos.txt"); } catch (IOException e) { throw new SAXException ("Problemas al abrir fichero"); } }

Page 65: Apuntes de XML

public void endDocument() throws SAXException { try { f.close(); } catch (IOException e) { throw new SAXException ("Problemas al cerrar fichero"); } }

public void startElement(String espacio, String nomLocal, String nomCompleto, Attributes atrs) { if (nomLocal.equals("Tema")) { extraer = true; } else if (nomCompleto.equals("Seccion")) { numSecciones++; numApartados += Integer.parseInt(atrs.getValue(0)); if (atrs.getValue(1).equals("si")) { numDificiles++; } } }

public void endElement(String espacio, String nomLocal, String nomCompleto) throws SAXException { if (nomLocal.equals("Tema")) { extraer = false; } else if (nomLocal.equals("Capitulo")) { try { f.write("\t" + numSecciones + " secciones\r\n" + "\t" + numApartados + " apartados\r\n" + "\t(" + numDificiles + " difíciles)\r\n"); numSecciones = 0; numApartados = 0; numDificiles = 0; } catch (IOException e) { throw new SAXException ("Problemas al escribir en fichero"); } } }

public void characters(char[] ch, int comienzo, int fin) throws SAXException { try { if (extraer) { String tema = new String(ch, comienzo, fin); f.write(tema + "\r\n"); } } catch (IOException e) { throw new SAXException ("Problemas al escribir en fichero"); } }

public void processingInstruction(String destino, String datos) { }

public void startPrefixMapping(String prefijo, String uri) { }

public void endPrefixMapping(String prefijo) { }

public void ignorableWhitespace(char[] ch, int comienzo, int fin) { }

public void skippedEntity(String nombre) { }}

Page 66: Apuntes de XML

 DOM

 Enunciado

Realizar mediante DOM un programa para el documento del libro. El programa debe escribir en un fichero los títulos de los capítulos y un pequeño resumen para cada uno de ellos con el número de secciones, de apartados totales y de apartados difíciles.

 Solución

import org.w3c.dom.Document;import org.w3c.dom.Node;import org.w3c.dom.Element;import org.w3c.dom.NodeList;import org.w3c.dom.NamedNodeMap;import java.io.IOException;import org.xml.sax.SAXException;import org.apache.xerces.parsers.DOMParser;import java.io.FileWriter;

public class EjercicioDOM {

static FileWriter f; static int numSecciones; static int numApartados; static int numDificiles;

public static void procesar(Node nodo) throws IOException {

Element e = (Element)nodo; String nombre = e.getNodeName(); if (nombre.equals("Libro")) { f = new FileWriter("capitulosDOM.txt"); NodeList hijos = e.getElementsByTagName("Capitulo"); for (int i=0; i<hijos.getLength(); i++) { procesar(hijos.item(i)); } f.close(); } else if (nombre.equals("Capitulo")) { procesar(e.getElementsByTagName("Tema").item(0)); NodeList hijos = e.getElementsByTagName("Seccion"); numSecciones = hijos.getLength(); numApartados = 0; numDificiles = 0; for (int i=0; i<hijos.getLength(); i++) { procesar(hijos.item(i)); } f.write("\tSecciones: " + numSecciones + "\r\n"); f.write("\tApartados: " + numApartados + "\r\n"); f.write("\t(Difíciles: " + numDificiles + ")\r\n"); } else if (nombre.equals("Tema")) { f.write(e.getFirstChild().getNodeValue() + "\r\n"); } else if (nombre.equals("Seccion")) { numApartados += Integer.parseInt(e.getAttribute("apartados")); if (e.getAttribute("dificil").equals("si")) { numDificiles++; } } } public static void main(String[] args) { if (args.length != 1) { System.out.println("Debe haber un parámetro (el fichero)"); } else { String fich = args[0]; System.out.println("Generando árbol para: " + fich + "\n");

Page 67: Apuntes de XML

try { DOMParser parser = new DOMParser(); parser.parse(fich); Document doc = parser.getDocument(); procesar(doc.getDocumentElement()); } catch (IOException e) { System.out.println(e); } catch (SAXException e) { System.out.println(e); } } }}

 DOM (otro)

 Enunciado

Realizar mediante DOM un programa a partir de un documento con las notas detalladas de una serie de alumnos de una clase. El programa debe imprimir por pantalla la media de cada alumno y la media total de la clase, así como generar un documento XML con esta información.

Entrada <?xml version="1.0"?><course> <teacher id="jp"> <name>John Punin</name> </teacher> <student id="js"> <name>John Smith</name> <hw1>30</hw1> <hw2>70</hw2> <project>80</project> <final>85</final> </student> <student id="gl"> <name>George Lucas</name> <hw1>80</hw1> <hw2>90</hw2> <project>100</project> <final>40</final> </student> <student id="lr"> <name>Elizabeth Roberts</name> <hw1>60</hw1> <hw2>95</hw2> <project>50</project> <final>100</final> </student></course>Salida Alumno John Smith = 66.25 Alumno George Lucas = 77.5 Alumno Elizabeth Roberts = 76.25 Media de la clase = 73.333336

<?xml version="1.0" encoding="UTF-8"?><Notas Media="73.333336"> <Alumno> <Nombre>John Smith</Nombre> <Nota>66.25</Nota> </Alumno> <Alumno> <Nombre>George Lucas</Nombre> <Nota>77.5</Nota> </Alumno> <Alumno> <Nombre>Elizabeth Roberts</Nombre>

Page 68: Apuntes de XML

<Nota>76.25</Nota> </Alumno></Notas>

 Solución

import org.w3c.dom.*;import javax.xml.parsers.*;import org.apache.xerces.dom.DocumentImpl;import org.apache.xml.serialize.*;import java.io.*;

public class OtroEjDOM {

static float notas[][] = new float[100][5]; static String nombres[] = new String[100];

public static void main(String[] args) { try { DocumentBuilder parser; DocumentBuilderFactory factoria = DocumentBuilderFactory.newInstance(); parser = factoria.newDocumentBuilder(); Document doc = parser.parse(args[0]); NodeList studs = doc.getElementsByTagName("student"); for (int i=0; i<studs.getLength(); i++) { tratarStud((Element) studs.item(i), i); } calcularNotas(studs.getLength()); } catch (Exception e) { e.printStackTrace(System.err); } }

private static void tratarStud(Element elemStud, int numStud) { nombres[numStud] = extraerValor(elemStud, "name"); notas[numStud][0] = Integer.parseInt(extraerValor(elemStud, "hw1")); notas[numStud][1] = Integer.parseInt(extraerValor(elemStud, "hw2")); notas[numStud][2] = Integer.parseInt(extraerValor(elemStud, "project")); notas[numStud][3] = Integer.parseInt(extraerValor(elemStud, "final")); } private static String extraerValor(Element elem, String campo) { Element subElem = (Element) elem.getElementsByTagName(campo).item(0); return subElem.getFirstChild().getNodeValue(); }

private static void calcularNotas(int numStuds) { float media = 0; int i = 0, j = 0; System.out.println(); for(i = 0; i < numStuds ; i++) { float total = 0; for(j = 0; j < 4; j++) { total += notas[i][j]; } notas[i][4] = total/4; media += notas[i][4]; System.out.println("Alumno " + nombres[i] + " = " + notas[i][4]); } media /= numStuds; System.out.println("Media de la clase = " + media); System.out.println();

try { Document doc= new DocumentImpl(); Element raiz = doc.createElement("Notas");

Page 69: Apuntes de XML

raiz.setAttribute("Media", String.valueOf(media)); for(i = 0; i < numStuds ; i++) { Element alumno = doc.createElement("Alumno"); Element nombre = doc.createElement("Nombre"); nombre.appendChild(doc.createTextNode(nombres[i])); alumno.appendChild(nombre); Element nota = doc.createElement("Nota"); nota.appendChild(doc.createTextNode(String.valueOf(notas[i][4]))); alumno.appendChild(nota); raiz.appendChild(alumno); } doc.appendChild(raiz);

OutputFormat formato = new OutputFormat(doc, "UTF-8", true); StringWriter s = new StringWriter(); XMLSerializer ser = new XMLSerializer(s, formato); ser.serialize(doc); System.out.println(s.toString());

FileWriter f = new FileWriter("notas.xml"); ser = new XMLSerializer(f, formato); ser.serialize(doc);

} catch (IOException e) { System.out.println(e); } }}

Page 70: Apuntes de XML