260 likes | 363 Views
XML. Simple API for XML. Introducción. ¿Cómo maneja la información representada en XML un programa? Requiere módulo parser Lee fichero y crea representación en memoria (objetos, variables, …) ¿Qué alternativas tenemos? Podemos parsear “a pelo” el XML
E N D
XML Simple API for XML
Introducción • ¿Cómo maneja la información representada en XML un programa? • Requiere módulo parser Lee fichero y crea representación en memoria (objetos, variables, …) • ¿Qué alternativas tenemos? • Podemos parsear “a pelo” el XML • Problemas Consideraciones UNICODE, substitución de ENTITIES, gestión namespaces, … • Reinvención de la rueda • Utilizar parsers XML (xerces, saxon, msxml, etc.) • Existen dos tendencias principales • Procesamiento en base a eventos • Procesamiento en árbol
Procesamiento en base a eventos • El parser analiza el documento XML de forma secuencial • Puede pararse para insertar ENTIDADES de DTD o ir validando documento de acuerdo a DTD/Schema • Según lee el documento va generando eventos. • Por ejemplo, consideremos este fragmento XML: • <libro><titulo>Don Quijote de la Mancha</titulo><autor>Miguel de Cervantes</autor></libro> • El parser podría generar los siguientes eventos: startElement:libro startElement:titulo content: Don Quijote de la Mancha endElement:titulo startElement:autor content:Miguel de Cervantes endElement:autor endElement:libro
Procesamiento en base a eventos (II) • Puede haber muchos eventos, no sólo apertura y cierre de un elemento • Definición de un nuevo namespace, atributo encontrado, comentario, processing instruction, etc. • Los parsers orientados a eventos no mantienen memoria del documento • Sólo generan eventos usuario de la API debe mantener el estado si lo necesita • Parser sencillo Aplicación compleja • Limitaciones • Edición y construcción de documentos • Recorrido aleatorio del documento p.e. al aplicar XPaths • Ventajas • Simplicidad • Rapidez • Consumo de memoria reducido • Ideales para leer documentos que no cambian P.e. ficheros de configuración
Procesamiento en base a modelo árbol • Los documentos XML describen estructuras en árbol Representación en memoria de un árbol alternativa más lógica • Existen diferentes modelos de árbol para los documentos XML ligeramente diferentes • XPath • DOM (Document Object Model) API del W3C (Representación de objetos en memoria) • XML Infoset también del W3C • Extensiones para aplicaciones particulares (SVG) • El más extendido y conocido DOM
Procesamiento en base a modelo árbol (II) • Ventajas modelos de árbol • El programa puede acceder de forma nativa a elementos XML • Objetos XML Objetos Java, objetos C++, estructuras C, etc. • No hay limitaciones en cuanto al recorrido • Podemos volver hacia atrás, ir directamente al final, etc. • Sencillo modificar documento • Se añaden nuevos objetos al árbol cuyas ramas se construyen típicamente en base a listas Modelo preferido para editores XML, browsers • Inconvenientes • Grandes requerimientos de memoria un documento XML en memoria puede ocupar. Varias veces tamaño fichero XML. • P.e. consideremos elemento: <a/> (4 bytes UTF-8) • Representación Java podría traducirse a objeto Element (Name(String),AttributeList,NamespaceList) Podría irse a 200 bytes • ¿Cuánto ocuparía la representación de un fichero de 120 MB? • Inviable para procesamiento de grandes volúmenes de información Alternativas mixtas, trucos, etc.
APIs de mayor nivel • Generalmente toda API de manejo información XML se basa por debajo en modelo basado en árbol o basado en eventos • Incluso las implementaciones basadas en árbol se suelen crear sobre APIs en base a eventos • Es habitual que ofrezcan las dos posibilidades • Casos como las APIs de manejo de documentos SVG (Scalable Vector Graphics) añaden extensiones propias a APIs DOM para adaptarse mejor a sus características concretas • En la programación no tenemos por qué quedarnos con un único modelo • Es habitual combinar ambos.
¿Qué es SAX? • SAX significa Simple API for XML API basada en eventos • Web http://www.saxprojet.org • Originariamente fue una especificación para Java • Se ha convertido en un estándar de facto • Portada a multitud de plataformas. Existe soporte para SAX, aparte de Java en: • MSXML 3.0 A través de objeto COM (Visual Basic, C, C++, …) • Pascal • Perl • Python 2.0 • C (Xerces-C), C++ • Xerces API Parser Java y otros lenguajes del proyecto Apache. Soporta entre otros • Interfaces SAX version 2 (actual) • DOM level 3 • JAXP 1.2 Java API for XML Processing • Validación XML Schema
¿Cómo puedo utilizar SAX? • SAX es una API estándar • No obstante cada implementación puede variar ligeramente • Java es uno de los lenguajes más utilizados para la programación XML • Java proporciona la API JAXP Java API for XML Processing • Proporciona interfaces comunes para utilizar: SAX, DOM y APIs para XSLT • Abstrae del fabricante. • Equivalente a JDBC o ADO (MS) para BBDD • ¿Cómo uso entonces una API SAX en Java? • Directamente a través del driver • A través de la API SAX independiente del driver • A través de la API JAXP
¿Qué necesito para empezar? • Java 1.1 o superior • Vamos a utilizar JDK 1.5 • Un parser compatible SAX2 instalado en el classpath • Usaremos Xerces http://xml.apache.org/xerces-j/ • La distribución SAX2 para Java • Viene integrado en JDK 1.5 • Opcionalmente • Entorno de desarrollo Java. • Usaremos NetBeans http://www.netbeans.org • Instalamos todos los componentes necesarios …
Iniciando un proyecto • Abrimos Netbeans • Creamos un nuevo proyecto web: • File New Project • Escojemos el tipo: Java Application • Especificamos los datos del proyecto: • Le damos un nombre al proyecto EjemploSAX • Para Project Directory ponemos uno por ejemplo en el Escritorio llamado CursoXML • Podemos dejar MainClass vacío o le damos un nombre EjemploSAX1
Familiarización entorno • Edición • Podemos navegar por el árbol de la izquierda por las fuentes y ficheros de configuración • Con el botón derecho podemos crear nuevas clases,ficheros jsp,… en el directorio indicado • Ejecución target principal del proyecto: • Compila todas las fuentes no compiladas o modificadas y empaqueta librerías en jars y crea fichero war • Build Build Main Project • El objetivo que ejecutaremos será jar • Construcción parcial: • Si desplegamos el fichero “makefile” del proyecto de ant (build.xml) dentro src y pulsamos con el botón derecho podemos ejecutar cada target por separado (compilación, javadoc, etc.).
Creando la aplicación • Creamos un paquete: p.e. es.captiva.cursoxml • Creamos una clase que se extienda de org.xml.sax.helpers.DefaultHandler: import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; import org.xml.sax.XMLReader; public class EjemploSAX1 extends DefaultHandler { public EjemploSAX1 (){ super(); } } • Le añadimos un método main que va a instanciar un lector (XMLReader) a partir de una factoría XMLReaderFactory. public static void main (String args[]) { XMLReader xr = XMLReaderFactory.createXMLReader(); }
Creando la aplicación (II) • La clase XMLReaderFactory es una clase factoría que busca la implementación de parser adecuado. • ¿Cómo determina la fábrica qué parser debe escoger? • Variable de entorno: org.xml.sax.driver • ¿Cómo le asignamos un valor? • Desde la llamada al programa java -Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser EjemploSAX1 sample.xml • Desde dentro del programa System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser"); • También podríamos en su lugar crear una instancia del driver directamente Perderíamos flexibilidad XMLReader xr = new org.apache.xerces.parsers.SAXParser();
Asociación gestor eventos • Una vez que disponemos de un lector necesitamos asociarle el handler, que es la clase que recibirá los eventos. • Utilizamos los métodos • setContentHandler() Para asociar clase que recibe los eventos relacionados con lectura del documento (encontrado apertura elemento, etc.) • setErrorHandler() Para asociar los eventos de error en el documento • ¿Qué ocurre si hay un evento de un tipo y no hay un handler asociado? • Se ignora el evento • Podría ocurrir un error y que el driver acabara sin decir nada.
Asociación gestor eventos (II) • En nuestra aplicación el gestor de eventos es la propia clase (EjemploSAX1): public static void main (String args[]){ XMLReader xr = XMLReaderFactory.createXMLReader(); EjemploSAX1 handler = new EjemploSAX1(); xr.setContentHandler(handler); xr.setErrorHandler(handler); } • Sólo queda invocar al parser, que hay que alimentarlo con datos XML. El parser recibe estos datos en una clase org.xml.sax.InputSource. • Si miramos la documentación de la API (doc en Xerces) vemos que un InputSource puede crearse a partir de un InputStream o Reader, más adecuado para leer contenido textual.
Alimentando al parser • ¿Cómo va a recibir los datos nuestra aplicación? • Indicando nombres de ficheros XML en línea de comandos. • Creamos un java.io.FileReader (subclase de Reader para ficheros) por cada fichero de entrada. for (int i = 0; i < args.length; i++) { System.out.println(“Procesando fichero “ + args[i] + “...”); FileReader fr = new FileReader(args[i]); xr.parse(new InputSource(fr)); } • El método parse() es el que llama al parser y empieza a procesador documentos XML.
Gestión de eventos • Esta aplicación por ahora no hace nada • Necesitamos gestionar los eventos • Escribir métodos dentro de nuestra clase que reciben eventos. • Métodos: • startDocument() • endDocument() • startElement(String uri, String name, String qName, Attributes atts) • endElement(String uri, String name, String qName) • characters (char ch[], int start, int length) • Otros métodos Ver API DefaultHandler
Gestión de eventos (II) • Nuestra aplicación va a: • Contar el número de nodos elemento • Imprimir inicio y cierre de elemento • Imprimir texto dentro de los elementos • Para el contador implementamos variable miembro de EjemploSAX1: • int numElementos; • Implementamos la función miembro llamada al inicio del documento dentro de : public void startDocument () { this.numElementos = 0; System.out.println("********** Inicio del documento **********"); } • Y la de fin de documento, donde imprimimos el número de elementos encontrados: public void endDocument () { System.out.println("************ Fin del documento ***********"); System.out.println(">>>>>>> Se han procesado: " + this.numElementos + " elementos"); }
Gestión de eventos (III) • Al comenzar un elemento imprimimos su nombre e incrementamos el contador: public void startElement (String uri, String name, String qName, Attributes atts) { this.numElementos ++; if (uri.length() == 0) System.out.println(“Inicio elemento: " + qName); else System.out.println(“Inicio elemento: {" + uri + "}" + name); } • Cabe destacar el parámetro uri. En caso de tratarse de un elemento definido en un namespace el parser pasa la URI de dicho namespace. • El parámetro qName es la versión cualificada del nombre del elemento P.e.: xhtml:body • Y evento para fin del elemento: public void endElement(String uri, String name,String qName) { if (uri.length() == 0) System.out.println("Fin elemento: " + qName); else System.out.println("Fin elemento: {" + uri + "}" + name); }
Gestión de eventos (IV) • Por último el evento de texto. Para que se vea más claro substituimos tabuladores y nuevas lineas por “\t”, “\n”, “\r”: public void characters (char ch[], int start, int length){ System.out.print(“Texto: \""); for (int i = start; i < start + length; i++) { switch (ch[i]) { case '\\': System.out.print("\\\\"); break; case '"': System.out.print("\\\""); break; case '\n': System.out.print("\\n"); break; case '\r': System.out.print("\\r"); break; case '\t': System.out.print("\\t"); break; default: System.out.print(ch[i]); break; } } System.out.print("\"\n"); }
Últimos retoques • Completamos la importación de todos las clases que necesitamos para que no se queje el compilador: package es.captiva.xml.ejemplos; import java.io.FileReader; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; import org.xml.sax.XMLReader; import org.xml.sax.InputSource; import org.xml.sax.Attributes; • Compilamos el proyecto y obtenemos EjemploSAX1.jar en el directorio dist
Ejecución • Copiamos EjemploSAX1.jar a un directorio con ficheros XML (cualquiera de prácticas pasadas) y ejecutamos: java –jar EjemploSAX1.jar fich1.xml fich2.xml fich3.xml • Vemos la salida del programa. Funciona y no debería. ¿Por qué? • No hemos especificado ningún driver • La explicación JDK incluye un driver que utiliza por defecto
Ejecución (II) • Volvemos a ejecutar especificando el driver de Xerces: java –Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser –jar EjemploSAX1.jar fich1.xml fich2.xml fich3.xml • Ahora obtenemos el error: Exception in thread "main" java.lang.ClassNotFoundException: org.apache.xerces.parsers.SAXParser at org.xml.sax.helpers.XMLReaderFactory.loadClass(XMLReaderFactory.java:189) at org.xml.sax.helpers.XMLReaderFactory.createXMLReader(XMLReaderFactory .java:150) at es.captiva.xml.ejemplos.EjemploSAX1.main(EjemploSAX1.java:88) • No ha encontrado la clase del driver especificada. Copiamos xercesImpl.jar a %JAVA_HOME%\jre\lib\ext
Ejercicio • Probar con los ficheros XML de prácticas anteriores • Buscar ficheros con y sin namespaces • Modificaciones ejercicio • Añadir soporte para atributos (número de atributos totales e impresión de los que encuentre) • Añadir soporte para NOTATIONS y PROCESSING INSTRUCTIONS
Referencias • SAX • http://http://www.saxproject.org • Xerces • http://xml.apache.org/xerces-j/ • Javadoc API XML • http://java.sun.com/xml/jaxp/dist/1.1/docs/api/