=========================================== Sindicación y transformación de contenidos =========================================== Introducción =========================================== Muchas páginas web disponen de "feeds". Un "feed" es un mecanismo de suscripción que facilita la recepción de información. En general, los feed utilizan un vocabulario XML llamado RSS o uno llamado Atom. RSS =========================================== RSS es un estándar para la "sindicación" o "agregación" de recursos (recursos web normalmente). Su objetivo principal era permitir a un sitio web publicar las novedades con facilidad y que el usuario puede ir derectamente al lugar que le interese. Formato de archivo RSS ---------------------------------------------- Todo archivo RSS es, por supuesto, un XML .. code-block:: xml Canal de noticias de SSOO de DAM http://ssoo.iesmaestredecalatrava.es En este canal... Nueva versión de Ubuntu http://ubuntu.org Nueva versión... Canal de Lenguajes de marcas http://xml.iesmaestredecalatrava.es En este canal... Publicado nuevo validador del W3C http://validator.w3c.org Hay nuevo validador... Las reglas serían las siguientes: * Todo archivo de descripción de recursos en RSS utiliza el preámbulo típico de los documentos xml .. code-block:: xml * Todo RSS tiene un solo elemento raíz en el cual se puede indicar la versión RSS a la que nos ceñimos .. code-block:: xml * Un RSS tiene uno o más canales .. code-block:: xml * Todo canal debe tener, al menos un título, un enlace base (la dirección del propio sitio web) y una descripción: .. code-block:: xml ... ... Resumiendo los puntos más importantes: 1. Usar como elemento raíz ``rss``. 2. Todo RSS tiene uno o más ``channel`` 3. Todo ``channel`` tiene al menos ``title``, ``link`` y ``description`` 4. Despues de estos elementos, un ``channel`` puede tener uno o más elementos ``item`` (que son los que contienen las noticias) 5. Todo ``item`` también debe tener un ``title``, un ``link`` y ``description`` Ejercicio ---------------------------------------------- Crear un fichero Java que construya el siguiente fichero XML: .. code-block:: xml Prueba http://www.google.es Prueba de descripcion Una posible solución es esta: .. code-block:: java public class CreadorRSS { public byte[] getEtiquetas( String titulo, String enlace, String descripcion) { String resultado=""; resultado+=""; resultado+=titulo; resultado+="\n"; resultado+=""; resultado+=enlace; resultado+="\n"; resultado+=""; resultado+=descripcion; resultado+=""; return resultado.getBytes(); } public void crearArchivo(String nombre) throws IOException{ FileOutputStream fos= new FileOutputStream(nombre); String cabecera="\n"; fos.write(cabecera.getBytes()); String rss="\n"; fos.write(rss.getBytes()); byte[] etiquetas=this.getEtiquetas( "Titulo de la noticia", "http://www.algo.com", "Noticia muy importante"); fos.write(etiquetas); String rssCierre=""; fos.write(rssCierre.getBytes()); fos.close(); } public static void main(String[] args) throws IOException { CreadorRSS creador=new CreadorRSS(); creador.crearArchivo("D:/oscar/archivo.rss"); } } El siguiente código Java ilustra otra forma de hacerlo: .. code-block:: java public void crearRSS(){ DocumentBuilderFactory fabrica; DocumentBuilder constructor; Document documentoXML; try{ fabrica= DocumentBuilderFactory.newInstance(); constructor=fabrica.newDocumentBuilder(); documentoXML=constructor.newDocument(); TransformerFactory fabricaConv = TransformerFactory.newInstance(); Transformer transformador = fabricaConv.newTransformer(); DOMSource origenDOM = new DOMSource(documentoXML); Element e=documentoXML.createElement("rss"); documentoXML.appendChild(e); StreamResult resultado= new StreamResult( new File("D:\\resul\\archivo.rss")); transformador.transform(origenDOM, resultado); } catch (Exception e){ System.out.print("No se han podido crear los"); System.out.println(" objetos necesarios."); e.printStackTrace(); return ; } } XPath =================================== Según el W3C, XPath (que ya va por su versión 3.0) es un lenguaje diseñado para acceder a las distintas partes de un archivo XML. En nuestro caso nos va a resultar de mucha utilidad combinado con XSLT, que se verá un poco despues. XPath se basa en expresiones. Así, dado un archivo XML y una expresión XPath se dice que la expresión "se evalúa" y se obtiene un resultado que puede ser: * Una lista de nodos. * Un ``boolean`` (true o false) * Un ``float``. * Una cadena. XPath también ofrece algunas funciones de utilidad que se asemejan a las de algunos lenguajes de programación. Acceso a elementos --------------------- El mecanismo de acceso en XPath es muy similar al acceso a directorios que ofrecen algunos sistemas operativos. Para los ejemplos siguientes se usará el siguiente archivo XML .. code-block:: xml Teclado 480 Monitor 1.8 Raton 50 Así dado este archivo tenemos las expresiones siguientes: Si usamos la expresión ``/inventario`` se selecciona *el nodo inventario que cuelga de la raíz*. Como puede verse la raíz en XPath es un elemento conceptual, no existe como elemento. Además, dado como es XML solo puede haber un elemento en la raíz. Así, el resultado de evaluar la expresión ``/inventario`` para el archivo de ejemplo produce el resultado siguiente: .. code-block:: xml Teclado 480 Monitor 1.8 Raton 50 Como puede verse, obtenemos el propio archivo original. Sin embargo, podemos movernos a través del árbol XML de forma similar a un árbol de directorios. Y obsérvese que decimos "similar". Observemos por ejemplo que dentro de ```` hay 3 elementos ````. Si pensamos en la expresión XPath ``/inventario/producto`` puede que pensemos que obtendremos el primer producto (el que tiene el código AAA-111), sin embargo **una expresión XPath se parece a una consulta SQL**, y lo que obtiene la expresión es "todo elemento ```` que sea hijo de ````. Es decir, el fichero siguiente (que no es XML, sino una lista de nodos): .. code-block:: xml Teclado 480 Monitor 1.8 Raton 50 En cualquier lista podemos acceder a sus elementos como si fuese un vector. Sin embargo en XPath **los vectores empiezan por 1**. Por lo cual la expresión ``/inventario/producto[1]`` produce este resultado: .. code-block:: xml Teclado 480 Y la expresión ``/inventario/producto[3]`` produce este: .. code-block:: xml Raton 50 Obsérvese que no existe el elemento 4 y que por tanto la expresión ``/inventario/producto[4]`` producirá un error. Otro aspecto relevante es que no deben confundirse los vectores con las condiciones (que el W3C llama "predicados"), y con las cuales podremos seleccionar nodos que cumplan ciertas condiciones De hecho, una buena forma de verlos es asumir que en los corchetes **siempre se ponen condiciones y que si hay un número como por ejemplo el 2 nos referimos a la condicion "extraer el elemento cuya posición es igual a 2**. Dado un elemento, también podemos extraer un cierto atributo usando la arroba @. Así, la expresión ``/inventario/producto[3]/@codigo`` devuelve como resultado ``ACD-981``, que es el atributo código del tercer elemento ``producto`` que está dentro de ``inventario`` el cual cuelga de la raíz. Supongamos que deseamos extraer el producto cuyo código sea "AAA-111". Si usamos ``/inventario/producto`` extraemos todos los elementos producto hijos de inventario, pero recordemos que entre corchetes podemos poner condiciones. Dado que queremos comprobar si @codigo = "AAA-111", la expresión correcta será ``/inventario/producto[@codigo="AAA-111"]``, la cual nos devuelve lo siguiente: .. code-block:: xml Teclado 480 De hecho se puede profundizar aún más y usar la expresión ``/inventario/producto[@codigo="AAA-111"]/nombre`` que extrae los nombres de los elementos producto cuyo código sea "AAA-111". Y aún más para extraer solo el texto de los elementos nombre usando la expresión ``/inventario/producto[@codigo="AAA-111"]/nombre/text()``. Como vemos en esta última expresión ya hemos usado una función, en concreto ``text()``. En una condicion podemos referirnos a cualquier hijo de un nodo, así por ejemplo, podemos extraer los productos cuyo peso sea mayor de 50 usando ``/inventario/producto[peso>=50]``. Sin embargo, sabemos que la unidad es importante, por lo que en realidad podemos extraer los que pesen más de 50 gramos usando esto ``/inventario/producto[peso>=50 and peso/@unidad="g"]``. Si se observa despacio el fichero, se observará que en realidad el tercer producto debería aparecer también. Para ello debemos ampliar la expresión convirtiendo los 50 g a kg, es decir comparando con 0.005 kg y la expresión siguiente ``/inventario/producto[(peso>=50 and peso/@unidad="g") or (peso>=0.005 and peso/@unidad="kg")]``. Utilizando XPath y XSLT veremos que podemos transformar un XML en casi cualquier otro XML utilizando la potencia combinada de ambos lenguajes. Adaptación y transformación de XML =========================================== Muy a menudo va a ocurrir que un cierto formato XML va a ampliarse o a modificarse o simplemente se necesita convertir un documento XML en otro con un formato distinto. Supongamos una estructura como la siguiente: .. code-block:: xml Don Quijote Cervantes Poeta en Nueva York Lorca Supongamos que un cierto sitio se necesita almacenar la información de esta forma: .. code-block:: xml Don Quijote Poeta en Nueva York En general, para poder modificar o presentar los XML se puede hacen varias cosas: * En primer lugar, se puede usar CSS para poder cargar los documentos XML en un navegador y mostrarlos de forma aceptable. * Se pueden utilizar otras tecnologías para transformar por completo la estructura del XML. * Se puede usar un lenguaje llamado XSLT (Xml Stylesheet Language Transformation) para convertir el XML en otro distinto. * Se puede utilizar XSL:FO (Xml Stylesheet Language: Formatting Objects) cuando se desee convertir el documento en algo que se desee imprimir (normalmente un PDF) CSS con XML ---------------------------------------------- Supongamos de nuevo el archivo anterior, el cual ahora queremos mostrar en un navegador: .. code-block:: xml Don Quijote Cervantes Poeta en Nueva York Lorca Si usamos el archivo ``estilo.css`` de esta forma: .. code-block:: css catalogo{ background-color:rgb(220, 230, 220); display:block; } libro{ display:block; border: solid black 1px; margin-bottom:20px; } title{ margin: 10px; display:block; } autor{ display:block; font-face:Arial; text-decoration:underline; } Veremos algo como esto: .. image:: estilo-xml.png :align: center :scale: 50% Ejercicio ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Crear una hoja de estilo asociada al catálogo anterior, que muestre la información de cada libro de forma parecida a una tabla, en la que el ``title`` utilice un color de fondo distinto del ``autor``. .. image:: estilo-xml2.png :align: center :scale: 50% .. code-block:: css catalogo{ background-color:rgb(220, 230, 220); display:block; } libro{ display:block; width:100%; margin-bottom:40px; clear:both; } title{ float:left; width:45%; border:solid black 1px; padding:5px; text-align:center; background-color:rgb(180,180,240); } autor{ float:left; text-align:center; width:45%; border:solid black 1px; padding:5px; background-color:rgb(340,180,240); } Transformación de XML ---------------------------------------------- Si deseamos *transformar un XML en otro XML* necesitaremos usar XSLT. Un archivo XSLT tiene la extensión XSL e indica las reglas para convertir entre formatos XML. El documento XSL básico sería así (los navegadores la darán por mala, ya que no hace absolutamente nada): .. code-block:: xml En este caso xsl es el espacio de nombres. Un espacio de nombres es un contenedor que permite evitar que haya confusiones entre unas etiquetas y otras que se llamen igual. En este caso, queremos usar la etiqueta definida por el W3C. Una hoja básica sería esta .. code-block:: xml Resultado Documento resultado Algunos navegadores no ejecutan XSL por seguridad. Los detalles de como “abrir” la seguridad de cada uno de estos navegadores deben investigarse en el manual de cada uno de ellos. Cabe destacar que esta hoja simplemente genera HTML básico pero no recoge ningún dato del XML original. Ejercicio (carga de estilos) ---------------------------------------------- Hacer que el archivo XML de libros cargue esta hoja de estilos. Solución: consiste en añadir una línea al archivo que referencie el archivo de transformación y el tipo de lenguaje usado para transformar. .. code-block:: xml ... (El resto es igual) Ejercicio (conversion entre XMLs) ------------------------------------- Dado el fichero de información del catálogo, transformar dicho XML en otro fichero en el que la etiqueta ``title`` vaya en español, es decir, que el resultado quede así: .. code-block:: xml Don Quijote Cervantes Poeta en Nueva York Lorca La solución podría ser algo así: .. code-block:: xml Ejercicio (generación de atributos) ------------------------------------------ Dado el archivo XML del catálogo generar un XML en el que el autor vaya como un atributo del título, es decir, que quede algo así: .. code-block:: xml Don Quijote Poeta en Nueva York La solución: .. code-block:: xml Ejercicio (tabla HTML) ------------------------ Convertir el catalogo XML en una tabla HTML Solución: .. code-block:: xml Catalogo de libros

Listado de libros

Ejercicio (generacion) ---------------------------------------------- Hacer que el XSL genere un HTML con información del archivo XML de libro. .. code-block:: xml Ejemplo de transformación

Resultado

Ejercicio ---------------------------------------------- Extraer los títulos de los libros pero consiguiendo encerrarlos en una lista ordenada HTML para que aparezcan numerados. .. code-block:: xml Ejemplo de transformación

Resultado

Ejercicio ---------------------------------------------- Supongamos que ahora un libro tiene varios autores y el XML es algo así: .. code-block:: xml Don Quijote Cervantes Patrones de diseño en programación Erich Gamma John Vlissides Ralph Johnson ¿Como mostrar en HTML el título y todos los autores de cada libro? .. code-block:: xml Ejemplo de transformación

Resultado

Ejercicio ---------------------------------------------- Se desea hacer lo mismo que en el ejercicio anterior pero haciendo que los autores aparezcan de forma ordenada. La solución está fundamentada en el uso de la etiqueta siguiente: .. code-block:: xml ..cosas del bucle... La solución completa sería así: .. code-block:: xml Ejemplo de transformación

Resultado

Ejercicio ---------------------------------------------- Suponiendo que además todos los libros tienen además un elemento ```` mostrar los libros editados despues del 2000. .. code-block:: xml Don Quijote Cervantes 1984 Patrones de diseño en programación Ralph Johnson Erich Gamma John Vlissides 2007 .. code-block:: xml Ejemplo de transformación

Resultado

En general, las condiciones se escriben así: * > o mayor que o ``>`` * < o menor que o ``<`` * >= o mayor o igual o ``≥`` * <= o menor o igual o ``≤`` * <> o distinto o ``&neq;`` Ejercicio XSL, paso a paso ------------------------------------------------------ Dado el siguiente XML crear un programa con XSLT que muestre los titulos y los autores de los libros cuya fecha de edicion sea posterior al 2000. .. code-block:: xml Don Quijote Cervantes La sociedad civil moderna Luis Diaz Pedro Campos Hagámoslo paso a paso. En primer lugar tendremos que crear el fichero ``ejercicio1.xsl`` y crear la estructura básica: .. code-block:: xml Ahora recorramos los libros que hay en el catalogo (recordemos que la estructura es ``catalogo/libro``. Simplemente por ver si funciona, de momento el navegado solo muestra los títulos y en una sola línea. .. code-block:: xml .. figure:: ejercicio1xslpaso1.png :figwidth: 50% :align: center Paso inicial del XSL Avancemos un poco más y creemos una estructura HTML válida .. code-block:: xml Filtrado con XSLT

Filtrado con XSLT

.. figure:: ejercicio1xslpaso2.png :figwidth: 50% :align: center Extrayendo los titulos con XSL Ahora vamos a procesar solo los libros cuya ``fechaedicion`` sea posterior al 2000. Añadamos un ``if`` .. code-block:: xml Filtrado con XSLT

Filtrado con XSLT

.. figure:: ejercicio1xslpaso3.png :figwidth: 50% :align: center Procesando los que son > 2000 Ahora para cada libro queremos también mostrar los elementos autor con su propia lista .. code-block:: xml Filtrado con XSLT

Filtrado con XSLT

Y el navegador muestra lo siguiente .. figure:: ejercicio1xslpaso4.png :figwidth: 50% :align: center Mostrando también los autores Ejercicio: condiciones complejas ----------------------------------- Supongamos que nos dan el siguiente fichero de inventario: .. code-block: xml 10 Ordenador 450 Altavoz Y supongamos que nos dicen que se necesita extraer la información relativa a los productos que pesan más de 5. Una primera aproximación equivocada sería esta: .. code-block:: xml Esta solución está equivocada porque de entrada *la pregunta está mal* Si se refieren a 5kg solo debería mostrarse el ordenador y si se refieren a 5g solo debería mostrarse el altavoz. Una solución correcta sería esta. Obsérvese como se meten unos if dentro de otros para extraer la información deseada. .. code-block:: xml Transformación en tabla --------------------------- Se nos pide convertir el inventario de antes en la tabla siguiente donde el peso debe estar normalizado y aparecer siempre en gramos: .. image:: tabla_tras_xslt1.png :align: center :scale: 50% Una posible solución sería: .. code-block:: xml Tabla de inventario
Transformacion de pedidos --------------------------- Dado el siguiente archivo XML: .. code-block:: xml 1430 4 500 499 1830 6 1000 1199 1250 2 750 699 Android 2 6 LiPo iOS 4 9 LiIon Crear un fichero de estilos que permita mostrar la información de los portátiles en forma de tabla. .. figure:: xsl1.png :figwidth: 50% :align: center Transformacion XSL Una posible solución sería esta: .. code-block:: xml Ejercicio 1

Resultado

Peso RAM Disco Precio
Transformación de pedidos (II) ------------------------------------------------------ Con el mismo fichero de pedidos crear una sola tabla que tenga 3 columnas y aglutine información tanto de portátiles como de tablets: * Cuando procesemos portátiles, las columnas serán respectivamente "precio", "ram" y "disco". Solo se procesan portátiles con más de 2GB de RAM. * Cuando procesemos tablets, las columnas serán "plataforma", "ram" y "batería". Solo se procesan los tablets con más de 2GB de RAM y que además tengan un tamaño superior a 7 pulgadas. El fichero siguiente ilustra una posible forma de hacerlo: .. code-block:: xml Ejercicio 1

Resultado

Precio: Memoria: Disco duro:
Ejercicio (no se da la solución) ------------------------------------------------------ Poner en una lista ordenada (elemento ``ol``) todas las capacidades RAM que se encuentren en el fichero XML.