===========================================
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
Teclado480Monitor1.8Raton50
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
Teclado480Monitor1.8Raton50
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
Teclado480Monitor1.8Raton50
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
Teclado480
Y la expresión ``/inventario/producto[3]`` produce este:
.. code-block:: xml
Raton50
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
Teclado480
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 QuijoteCervantesPoeta en Nueva YorkLorca
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 QuijoteCervantes
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 QuijoteCervantes
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 QuijoteCervantesPatrones de diseño en programaciónErich GammaJohn VlissidesRalph 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 QuijoteCervantes1984Patrones de diseño en programaciónRalph JohnsonErich GammaJohn Vlissides2007
.. 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 QuijoteCervantes
La sociedad civil moderna
Luis DiazPedro 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
10Ordenador450Altavoz
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
14304500499183061000119912502750699Android26LiPoiOS49LiIon
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.