APIs de Java para XML

El API Java para Proceso de XML (JAXP) hace f�cil el proceso de datos XML con aplicaciones escritas en el lenguaje Java. JAXP contiene los analizadores est�ndars SAX (Simple API for XML Parsing) y DOM (Document Object Model) para que podamos elegir entre analizar nuestros datos como streams de eventos y construir una representaci�n de objetos con ellos. La versi�n 1.1 de JAXP tambi�n soporta el est�ndar XSLT (XML Stylesheet Language Transformations), d�ndonos control sobre la representaci�n de los datos y permiti�ndonos convertir los datos a otros documentos XML o a otros formatos, como a HTML. JAXP tambi�n proporciona soporte para espacios de nombres, permiti�ndonos trabajar con DTDs que de otra forma tendr�an conflictos de nombrado.

Dise�ado para ser flexible, JAXP nos permite usar cualquier analizador compatible XML desde dentro de nuestra aplicaci�n. Esto lo hace con algo llamado capa de conectividad, que nos permite enchufar una implementaci�n de los APIs SAX o DOM. La capa de conectividad tambi�n nos permite enchufar un procesador XSL, lo que nos permite controlar la forma en que se muestran los datos. La Implementaci�n de Referencia 1.1 de JAXP (disponible en http://java.sun.com/xml) proporciona el procesador de XSLT Xalan y el analizador Crimson, �mbos desarrollados conjuntamente entre Sun y la Fundaci�n de Software Apache, que proporciona software open-source.

.�El API SAX

SAX define un API para un analizador basado en eventos. Estar "basado en eventos" significa que el analizador lee un documento XML desde el principio hasta el final, y cada vez que reconoce una s�ntaxis de construcci�n, se lo notifica a la aplicaci�n que lo est� ejecutando. El analizador SAX notifica a la aplicaci�n llamando a los m�todos del interface ContentHandler. Por ejemplo, cuando el analizador encuentra un s�mbolo ("<"), llama al m�todo startElement; cuando encuentra caracteres de datos, llama al m�todo characters; y cuando encuentra un s�mbolo ("</"), llama al m�todo endElement, etc. Para ilustrar, echemos un vistazo al documento XML del ejemplo de la primera secci�n y veamos que hace el analizador en cada l�nea. (Por simplicidad, no se han incluido las llamadas al m�todo ignorableWhiteSpace.)

<priceList> [el analizador llama a startElement]
    <coffee> [el analizador llama a startElement]
        <name>Mocha Java</name> [El analizador llama a startElement, characters, y endElement]
        <price>11.95</price> [el analizador llama a startElement, characters, y a endElement]
    </coffee> [el analizador llama a endElement] 

Las implementaciones por defecto de los m�todos que llama el analizador no hacen nada, necesitamos escribir un subclase que implemente los m�todos apropiados para obtener la funcionalidad que queremos. Por ejemplo, supongamos que queremos obtener el precio por libra del caf� "Mocha". Escribiriamos una clase extendiendo DefaultHandler (la implementaci�n por defecto de ContentHandler) en la que escribir�amos nuestras propias implementaciones de los m�todos startElement y characters.

Primero necesitamos crear un objeto SAXParser desde un objeto SAXParserFactory. Llamar�amos al m�todo parse sobre �l, pas�ndole la lista de precios y un ejemplar de nuestra nueva clase handler (con sus nuevas implementaciones de los m�todos startElement y characters). En este ejemplo, la lista de precios es un fichero, pero el m�todo parse tambi�n puede aceptar una gran variedad de fuentes de entrada, incluyendo objetos InputStream, URL, y InputSource.

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser SAXParser = factory.newSAXParser();
SAXParser.parse("priceList.xml", handler);

El resultado de llamar al m�todo parse depende, por supuesto, de como est�n implementados los m�todos en handler. El analizador SAX atravesar� el fichero priceList.xml l�nea a l�nea, llamando a los m�todos apropiados. Adem�s de los m�todos ya mencionados, el analizador llamar� a otros m�todos como startDocument, endDocument, ignorableWhiteSpace, y processingInstructions, pero estos m�todos tambi�n tienen sus implementaciones por defecto que no hacen nada.

Las siguientes definiciones de m�todos muestran una forma de implementar los m�todos characters y startElement para que puedan encontrar e imprimir el precio del caf� Mocha Java. A causa de la forma en que trabaja el analizador SAX estos m�todos trabajan juntos para buscar en el elemento name, los caracteres "Mocha Java", y el elemento price que sigue inmediantemente a "Mocha Java". Estos m�todos usan tres banderas para seguir la pista de las condiciones que han encontrado. Observa que el analizador SAX tendr� que llamar a estos m�todos m�s de una vez antes de se alcancen las condiciones para imprimir el precio:

public void startElement(..., String elementName, ...){
    if(elementName.equals("name")){
        inName = true;
    } else if(elementName.equals("price") && inMochaJava ){
        inPrice = true;
    inName = false;
    }
}

public void characters(char [] buf, int offset, int len) {
    String s = new String(buf, offset, len);
    if (inName && s.equals("Mocha Java")) {
        inMochaJava = true;
        inName = false;
    } else if (inPrice) {
        System.out.println("The price of Mocha Java is: " + s);
        inMochaJava = false;
        inPrice = false;
    }
}

Una vez que el analizador ha encontrado el elemento coffee "Mocha Java", aqu� tenemos el estado despu�s de la siguientes llamadas a m�todos:

  • siguiente llamada a startElement -- inName es true
  • siguiente llamada a characters -- inMochaJava es true
  • siguiente llamada a startElement -- inPrice es true
  • siguiente llamada a characters -- imprime el precio

El analizador SAX puede realizar validaci�n mientras analiza los datos XML, lo que significa que chequea si los datos siguen las reglas especificadas en el DTD de los documentos XML. Una analizador SAX ser� con validaci�n si fue crado mediante un objeto SAXParserFactory con la validaci�n activada. Esto se hace para la factor�a de objetos SAXParserFactory en la siguiente l�nea de c�digo:

factory.setValidating(true);

Para que el analizador sepa qu� DTD utilizar para la validaci�n, el documento XML debe referenciar el DTD en su declaraci�n DOCTYPE. Esa declaraci�n deber�a ser similar a esta:

<!DOCTYPE PriceList SYSTEM "priceList.DTD">

.�El API DOM

El API "Document Object Model" (DOM), definido por el grupo de trabajo DOM de la W3C, es un conjunto de interfaces para construir una representaci�n de objeto, en forma de �rbol, de un documento XML analizado. Una vez que hemos construido el DOM, podemos manipularlo con m�todos DOM como insert y remove, igual que manipular�amos cualquier otra estructura de datos en forma de �rbol. As�, al contrario que un analizador SAX, un analizador DOM permite acceso aleatorio a piezas de datos particulares de un documento XML. Otra diferencia es que con un analizador SAX, s�lo podemos leer un documento XML, mientras que con un analizador DOM, podemos construir una representaci�n objeto del documento y manipularlo en memoria, a�adiendo un nuevo elemento o eliminando uno existente.

En el ejemplo anterior, usamos un analizador SAX para buscar s�lo un dato en un documento. Usando un analizador DOM hubieramos tenido que tener el modelo del objeto del documento completo en memoria, los que generalmente es menos eficiente para b�squedas que implican unos pocos �tems, especialmente si el documento es largo. En el siguiente ejemplo, a�adimos un nuevo caf� a la lista de precios usando un analizador DOM. No podemos usar una analizador SAX para modificar la lista de precios porque s�lo permite la lectuda de datos.

Supongamos que queremos a�adir el caf� "Kona" a la lista de precios. Leeremos el fichero XML de la lista de precios en un DOM y luego insertamos el nuevo elemento coffee, con su nombre y su precio. El siguiente fragmento de c�digo crea un objeto DocumentBuilderFactory, que luego es usado para crear el objeto DocumentBuilder. Luego el c�digo llama al m�todo parse sobre el builder, pas�ndole el fichero "priceList.xml".

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse("priceList.xml");

En este punto, el documento es una representaci�n DOM de la lista de precios situada en la memoria. El siguiente fragmento de c�digo a�ade un nuevo caf� (con el nombre "Kona" y el precio de 13.50) al documento de la lista de precios. Como queremos a�adir el nuevo caf� justo antes del caf� cuyo nombre es "Mocha Java", el primer paso es obtener una lista de elementos name e iterar a trav�s de la lista para encontrar "Mocha Java". Usando el interface Node incluido en el paquete org.w3c.DOM, el c�digo crea un objeto Node para el nuevo elemento coffee y tambi�n nuevos nodos para los elementos name y price. Estos dos elementos contienen los datos, por eso el c�digo crea un objeto TextNode para cada uno de ellos y a�ade los nodos de texto a los nodos que representan los elementos name y price.

NodeList list = document.getElementsByTagName("name");
Node thisNode = list.getItem("name");
// loop through list
Node thisChild = thisNode.getChildNode();
if(thisNode.getFirstChild() instanceof org.w3c.DOM.TextNode) {
    String data = thisNode.getFirstChild().getData();
}
if (data.equals("Mocha Java")) {             // new node will be inserted before Mocha Java
    Node newNode = document.createElement("coffee");
    Node nameNode = document.createElement("name");
    TextNode textNode = document.createTextNode("Kona");
    nameNode.appendChild(textNode);
    Node priceNode = document.createElement("price");
    TextNode tpNode = document.createTextNode("13.50");
    priceNode.appendChild(tpNode);
    newNode.appendChild(nameNode);
    newNode.appendChild(priceNode);
    thisNode.insertBefore(newNode, thisNode);
    }

Obtenemos una analizador DOM que tiene validaci�n de la misa forma que un analizador SAX validante: llamamos a setValidating(true) sobre una factor�a de analizadores DOM antes de usarla para crear nuestro analizador DOM, y nos aseguramos de que el documento XML referencia su DTD en la declaraci�n DOCTYPE.

.�Espacios de Nombres XML

Todos los nombres en un DTD son �nicos, as� se evita la ambiguedad. Sin embargo, si un documento XML particular referencia uno o m�s DTDs, hay una posibilidad de que dos o m�s DTDs contengan el mismo nombre. Por lo tanto, el documento necesita especificar un espacio de nombres para cada DTD para que el analizador sepa qu� definici�n usar cuando analice un ejemplar de un DTD particular.

Aqu� est� la notaci�n est�ndard para declarar espacios de nombres XML, lo que normalmente se hace en el elemento ra�z de un documento XML. En el siguiente ejemplo de declaraci�n de espacios de nombres, la notaci�n xmlns identifica a nsName y se configura con la URL del espacio de nombres actual:

<priceList xmlns:nsName="myDTD.dtd"
    xmlns:otherNsName="myOtherDTD.dtd">
...
</priceList>

Dentro del documento, podemos especificar a qu� espacio de nombres pertenece un elemento de esta forma:

<nsName:price> ...

Para hacer que nuestros analizador SAX o DOM pueda reconocer los espacios de nombres, llamamos al m�todo setNamespaceAware(true) sobre nuestro ejemplar de ParserFactory. Despu�s de esta llamada a este m�todo, cualquier parser que cree la factor�a de parsers tendr� cuidado con los espacios de nombres.

.�El API XSLT

XSLT (XSL Transformations), definido por el grupo de trabajo XSL de la W3C, describe un lenguaje para transformar documentos XML en otros documentos XML o en otros formatos. Para realizar la transformaci�n, normalmente necesitamos suministrar una hoja de estilo, que est� escrita en "XML Stylesheet Language" (XSL). La hoja de estilo XSL espec�fica como se mostrarr�n los datos XML. XSLT usa las instrucciones de formateo de la hoja de estilo para realizar la transformaci�n. El documento convertido puede ser otro documento XML o un documento en otro formato, como HTML.

JAXP soporta XSLT con el paquete javax.xml.transform, que nos permite enchufar un transformer XSLT para realizar las transformaciones. Los subpaquetes tienen APIs de streams espeficicos, de SAX-, y de DOM-, que nos permiten realizar transformaciones directamente desde �rboles DOM y eventos SAX. Los dos siguientes ejemplos muestran como crear un documento XML desde un �rbol DOM y como transfomar el documento XML resultante en HTML usando una hoja de estilo XSL.

.�Transformiar un �rbol DOM en un Documento XML

Para transformar el �rbol DOM creado en la secci�n anterior en un documento XML, el siguiente c�digo primero crea un objeto Transformer que realizar� la transformaci�n:

TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();

Usando el nodo ra�z del �rbol DOM, la siguiente l�nea de c�digo construye un objeto DOMSource como fuente de la transformaci�n:

DOMSource source = new DOMSource(document);

El siguiente fragmento de c�digo crea un objeto StreamResult para tomar el resultado de la transformaci�n y transforma el �rbol en XML:

File newXML = new File("newXML.xml");
FileOutputStream os = new FileOutputStream(newXML);
StreamResult result = new StreamResult(os);
transformer.transform(source, result);

.�Transformar un Documento XML en un Documento HTML

Tambi�n podemos usar XSLT para convertir el nuevo documento XML, "newXML.xml", a HTML usando una hoja de estilo. Cuando escribimos una hoja de estilo usamos espacios de nombres XML para referenciar el XSL construido. Por ejemplo, cada hoja de estilo tiene un elemento ra�z identificando el lenguaje de la hoja de estilo, como se muestra en la siguiente l�nea de c�digo:

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

Cuando referenciamos un constructor particular en el lenguaje de la hoja de estilos, usamos el prefijo del espacio de nombres seguido por dos puntos y el constructor particular a aplicar. Por ejemplo, la siguiente parte de una hoja de estilo indica que el dato name debe insertase en una fila de una tabla HTML:

<xsl:template match="name">
    <tr><td>
        <xsl:apply-templates/>
    </td></tr>
</xsl:template>

La siguiente hoja de estilo especifica que el dato XML es convertido a HTML y que las entradas de caf�s se insertan en las filas de una tabla:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="priceList">
        <html><head>Coffee Prices</head>
            <body>
                <table>
                    <xsl:apply-templates />
                </table>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="name">
        <tr><td>
            <xsl:apply-templates />
        </td></tr>
    </xsl:template>
    <xsl:template match="price">
        <tr><td>
            <xsl:apply-templates />
        </td></tr>
    </xsl:template>
</xsl:stylesheet>

Para realizar la transformaci�n necesitamos obtener un transformer XSLT y usarlo para aplicar la hoja de estilos a los datos XML. El siguiente fragmento de c�digo obtiene un transformer ejemplarizando un objeto TransformerFactory, lee los ficheros de la hoja de estilos y del XML, crea un fichero para la salida HTML, y finalmente obtiene el objeto Transformer desde la factor�a de objetos TransformerFactory llamada tFactory.

TransformerFactory tFactory = TransformerFactory.newInstance();
String stylesheet = "prices.xsl";
String sourceId = "newXML.xml";
File pricesHTML = new File("pricesHTML.html");
FileOutputStream os = new FileOutputStream(pricesHTML);
Transformer transformer = tFactory.newTransformer(new StreamSource(stylesheet));

La transformaci�n se consigue llamando al m�todo transform, pas�ndole los datos y el stream de salida:

transformer.transform(new StreamSource(sourceId), new StreamResult(os));

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO