Transformaciones XML con XSLT
Transformaciones XML con XSLT
Generación de páginas Web usando XSLT y Página principal del curso de XML
Usando hojas de estilo para generar WML
XML (teléfonos WAP)
Tutorial avanzado de generación de HTML
a partir de XML/XSLT
J. J. Merelo Otros cursos y tutoriales: comercio
electrónico, WAP, Webmaster
Página principal del grupo GeNeura
1 Introducción Ficheros de ejemplo
Al igual que XML, XSLT es un lenguaje de programación. Forma parte de la trilogía transformadora de
XML, compuesta por las CSS (Cascading Style Sheets, hojas de estilo en cascada), que permite dar una
apariencia en el navegador determinada a cada una de las etiquetas XML; XSLT (XML Stylesheets Language for
Transformation , o lenguaje de transformación basado en hojas de estilo); y XSL:FO, (Formatting Objects,
objetos de formateo), o transformaciones para fotocomposición, o, en general, para cualquier cosa que no sea
XML, como por ejemplo HTML "del viejo" o PDF (el formato de Adobe).
XSLT es pues, un lenguaje que se usa para convertir documentos XML en otros XHTML sí es XML, sigue un DTD
documentos XML; puede convertir un documento XML que obedezca a un DTD a otro que (varios, en realidad), y sólo admite
documentos "bien formados".
obedezca otro diferente, un documento XML bien formado a otro que siga un DTD, o, lo más
HTML no lo es, aunque pude
habitual, convertirlo a "formatos finales", tales como WML (usado en los móviles WAP) o convertirse fácilmente en XHTML
XHTML. usando utilidades tales como Tidy.
Los programas XSLT están escritos en XML, y generalmente, se necesita un procesador de hojas de estilo,
o stylesheet processor para procesarlas, aplicándolas a un fichero XML.
El estilo de programación con las hojas XSLT es totalmente diferente a los otros lenguajes a los que
estamos acostumbrados (tales como C++ o Perl), pareciéndose más a "lenguajes" tales como el AWK, o a otros
lenguajes funcionales, tales como ML o Scheme. En la práctica, eso significa dos cosas:
• No hay efectos secundarios. Una instrucción debe de hacer lo mismo cualquier que sea el camino de
ejecución que llegue hasta ella. O sea, no va a haber variables globales (¡Cielos!), ni bucles en los que se
incremente el valor de una variable, o tenga un test de fin de bucle, ni nada por el estilo. En realidad, esto
no es tan grave, y se puede simular usando recursión, como se verá.
• La programación está basada en reglas: cuando ocurre algo en la entrada, se hace algo en la salida. En
eso, se parece al AWK, o a cierto estilo de programación en PERL, pero no en el resto de las cosas. Al fin y
al cabo, no hay efectos secundarios.
En resumen, programar con las hojas XSLT (en inglés se les llama SAX significa Simple API for XML; un filtro SAX
stylesheets o logicsheets) puede ser un poco frustante, pero cuando uno aprende trata un fichero XML como un canal (stream) sobre el
cual se van aplicando transformaciones según se va
a usarlas, no puede vivir sin ellas. En realidad, son la única alternativa cuando
leyendo. Para transformaciones simples tales como
uno quiere adaptar un contenido descrito con XML a diferentes clientes (por extraer un tipo de etiqueta determinada, y, de hecho,
ejemplo, móviles de diferente tamaño, diferentes navegadores), y la mejor la mayoría de las incluidas en este tutorial, es mucho
alternativa cuando uno quiere procesar documentos XML (aunque haya otras: mejor usar un filtro SAX. El principal problema es
que carecen de un lenguaje para describir esas
filtros SAX, expresiones regulares...). Otra alternativa, sobre todo si se está transformaciones, y la sintaxis y aplicación depende
trabajando ya con un documento XML en forma de DOM (Document object totalmente del lenguaje en el que se trabaje. En Perl,
model) es trabajar directamente sobre él. En este claso, de todas formas, se por ejemplo, se puede usar XML::SAX, un módulo
pueden usar transformaciones XSL, sólo que se aplicarán en memoria, en vez de que permite hacer este tipo de transformaciones.
Generalmente, en caso de ficheros muy grandes a los
leerlas desde un fichero. que haya que hacerle un procesamiento relativamente
simple, SAX es una opción mejor, más rápida y con
Lo que consiguen las hojas de estilo es separar la información (almacenada menos consumo de memoria.
en un documento XML) de su presentación, usando en cada caso las
transformaciones que sean necesarias para que el contenido aparezca de la forma más adecuada en el cliente.
Es más, se pueden usar diferentes hojas de estilo, o incluso la misma, para presentar la información de
diferentes maneras dependiendo de los deseos o de las condiciones del usuario.
Aparte del hecho habitual de procesar documentos XML, XSLT es un lenguaje de programación, y por
tanto se podría hacer cualquier cosa con ellas; incluso calcular la célebre criba de Eratóstenes o ejecutar un
algoritmo genético. Pero a nosotros nos va a interesar más como simple herramienta de transformación de XML.
Actualmente hay varias versiones del estándar XSLT: la versión 1.0, que es la que implementan la
mayoría de los procesadores, y se denomina "recomendación", es decir, para el consorcio W3, lo equivalente a
un estándar, y la versión 2.0 , que, a fecha de 4 de noviembre del 2004, es un "working draft", o borrador de
trabajo, que es el paso previo a un estándar. Algunos procesadores, tales como el Saxon, implementan ya esta
última versión. Hay algunas diferencias importantes: el tratamiento uniforme de los árboles (técnicamente, se
pueden convertir fragmentos de árboles de resultados en nodesets), uso de múltiples documentos de salida, y
funciones definidas por el usuario que se pueden definir en XSLT, y no sólo en Java u otro lenguaje, como
sucedía en estándares anteriores. .
Para Windows, en sus diferentes versiones, hay dos herramientas que permiten editar Las convenciones que seguimos en
XML y hojas de estilo XSLT, y aplicar directamente la una a la otra. Una de ellas es XMLSpy, los ejemplos son las siguientes:
cada etiqueta XML en el
que tiene un IDE muy bonito, pero que casca con relativa frecuencia. De hecho, he sido
documento XML van en diferente
incapaz de aplicar una hoja de estilo a un documento XML. Otra opción es usar eXcelon color, dependiendo de su posición
Stylus, un peaso de programa, pero que sólo está disponible para WindowsNT/2000 (y no sé en la jerarquía; en las hojas XSL,
si XP); la versión 3.0 beta es gratuita para desarrolladores. el código XML está en rojo, el
código XSLT en verde, y el código
que no es exclusivo ni de uno ni de
En realidad, para editar XML y XSLT no hace falta ningún editor especial, pero viene otro, y que aparecerá tal cual en el
bien un editor de XML o incluso un entorno integrado que te ayude a indentar bien el código, documento final, en azul.
e incluso a cerrar las etiquetas en el orden correcto, o te saque la etiqueta y atributos
admisibles en cada momento en función del DTD. En ese sentido, si se trabaja en Windows, el mejor es el
[Link] 29/05/2017
Tutorial de XSL Page 2 of 19
eXcelon Stylus; en Linux, se puede uno apañar bien con el XEmacs (que te valida usando un DTD, si es
necesario).
Este tutorial no pretende ser una introducción exhaustiva al XML, en realidad, para los efectos de este
tutorial, hay que saber poco XML: sólo que hace falta emparejar bien las etiquetas, y la estructura de árbol que
sigue un documento XML (es lo que se denomina XML bien formado). En realidad, HTML se puede definir como
un documento bien formado, de hecho, la última versión de HTML, XHTML, también lo es, o sea que no es un
salto grande pasar de WML/XHTML a XML. En todo caso, los que quieran saber un poco más sobre el tema,
pueden consultar los diferentes tutoriales del curso GeNeura de XML.
Ejercicios 1
1. Crear un documento XML que describa una ficha de alumno. Tiene que tener una etiqueta raíz (por ejemplo,
acta), una etiqueta por cada alumno, y dentro de ellas, etiquetas para el DNI, nombre, apellidos y nota.
En muchos casos, lo que se necesita es aplicar hojas de estilo dentro de una aplicación, La principal diferencia entre
o usarlas desde línea de comandos a partir de otra aplicación o otro lenguaje de la versión 2 de Xalan y las
programación. En ese caso, lo más útil es usar un procesador de hojas de estilo, que anteriores es que implementa
habitualmente se encuentra en conjunción con un parser XML, con o sin validación. De estos, el llamado TrAX, una API
hay los siguientes: para poder aplicar
transformaciones a árboles
• Xalan, que será el que más usemos en este tutorial, y que además es gratuito. La XML; probablemente
versión actual es la 2.6. Es una herramienta escrita en Java, y lo único que se necesita incorpore también la versión
para hacerla funcionar es una máquina virtual Java (JVM), tal como la de Microsoft, Sun 1.1 de XSLT
o IBM. Xalan necesita un parser XML para funcionar, tal como el Xerces, aunque el
fichero correspondiente ([Link]) viene incluido en la distribución.
• Saxon, un procesador bastante rápido, también escrito en Java, con su propio parser incluido, aunque se
puede usar uno externo. Hay una versión denominada Instant Saxon, un procesador rápido, y fácil de usar,
sólo para Windows. Por lo pronto, es el único que implementa la versión 2.0 de XSLT.
• Hay otros muchos procesadores, tales como el XT de James Clark, xsltproc o el Sablotron. Todos ellos y
muchos más se pueden encontrar en la página de procesadores XSLT de [Link]. En Linux
recomiendo el xsltproc, basado en la librería XML/XSL de gnome; es muy rápido, es un ejecutable y no
hace falta instalar Java para usarlo.
• A su vez, los procesadores de hojas de estilo se pueden usar como librerías de clases, o desde otros
lenguajes. Por ejemplo, el módulo XML::XSLT para Perl. Estos módulos se pueden usar para poder trabajar
con XSLT fuera de entornos de publicación, como por ejemplo un servidor web normal. xalan es en realidad
una librería que se puede usar también desde programas en Java.
• Algunos navegadores también lo implementan, o lo harán en el futuro. En concreto, el Mozilla debería
incluirlo a partir de la versión 0.9; desde la versión 0.7 se podía incluir un plugin llamado TransforMiiX, que
teóricamente aplica XSLT. En realidad, casi todos los navegadores modernos, con mayor o menor fortuna,
lo incluyen. Firefox, por ejemplo, lo toma sin problemas.
Finalmente, para este curso, se puede usar un formulario simple que aplica hojas de estilo XSLT a
documentos XML usando Perl: aplicador de hojas de estilo.
[Link] 29/05/2017
Tutorial de XSL Page 3 of 19
Esto debería dar como resultado algo como lo que hay en esta página web.
El saxon es otro procesador de hojas de estilo, que está disponible como un fichero .jar, y que por tanto
se puede ejecutar en cualquier plataforma. Para usarlo, se escribe (después de definir el camino a la máquina
virtual Java y al .jar correspondiente):
El Instant Saxon es una versión de Saxon que ocupa poco y es relativamente fácil de usar. Hay que tener
instalada una máquina virtual Java en Windows para que funcione; si tenemos instalado el Internet Explorer,
con eso vamos que ardemos. Una vez instalado el explorer, basta escribir:
Que nos dará el mismo resultado que anteriormente, con un poco de suerte.
También se puede usar el script en geneura, editando los ficheros anteriores y cortándolos y pegándolos
en el sitio adecuado. Este script usa dos librerías de Perl: XML::LibXML y XML::LibXSLT, que a su vez están
basadas en las librerías de Gnome LibXML2 equivalentes.
Para empezar, el código del documento XML contiene una etiqueta, tienda, que incluye otras dos
etiquetas, nombre y telefono, que contienen el texto que queremos que aparezca en la página web. En el resto, la
primera línea simplemente describe que el resto del documento es XML, y asocia la hoja de estilo XSLT
([Link]) al documento. Esta segunda línea se usa en entornos de publicación tales como el cocoon; algunos
procesadores de XSLT la usan para tomar el nombre de la hoja de estilo que se va a usar; también lo suelen
usar navegadores como el Mozilla/Netscape/Firefox o el Internet Explorer. Cada una de estas etiquetas se
denominan elementos; y en principio, un documento puede tener tantas etiquetas como queramos.
El XML original, como se ve, es simplemente XML bien formado, no usa un DTD ni lo necesita: basta con
que haya una etiqueta raíz (tienda, en nuestro caso), las etiquetas estén emparejadas correctamente y los
atributos entre comillas. Diferentes documentos XML podrían ser procesados con la misma hoja de estilo, y
darían diferente resultado. Ahora mismo, tal como está, un documento XML tiene asociada una sola hoja de
estilo XSLT, y para ese viaje no hacen falta alforjas, salvo por el hecho de que muchos documentos XML pueden
tener la misma hoja XSL y de esa forma mantener una apariencia común. También se verá más adelante la
forma de que el procesador XSLT seleccione diferentes hojas XSLT dependiendo de las circunstancias
(principalmente, el cliente).
La primera hoja de estilo con la que nos enfrentamos es relativamente simple. El "esqueleto" es un
documento HTML normal, al cual tenemos que añadir "contenido dinámico", es decir, contenido generado a
partir del XML original. Para hacernos una idea, en este caso simple, una hoja XSLT es como una plantilla sobre
la que se cambian los contenidos por sus valores al aplicarla. En realidad, tendríamos que pensar en una hoja
XSLT con en un jardinero que va podando árboles, partiendo de la raíz. Al llegar a una rama, hace algo con ella:
la poda, inserta otra cosa, o simpelemente la deja tal cual; el árbol, en este caso, es realmente el árbol DOM del
documento XML que está tratando.
Para empezar, se incluyen una serie de instrucciones, de la línea 1 a la 5: no son instrucciones en sí, sino
que modifican el aspecto de la salida. La primera declara el documento XML y el tipo de codificación (que podría
ser ISO-8859-1 en vez de UTF-8 si quisiéramos incluir acentos y demás caracteres idiosincráticos) y la segunda
es la etiqueta raíz de la hoja de estilo (cerrada en la última línea; recordemos que una hoja de estilo XSL es
también un documento XML y por tanto tiene que seguir todas sus convenciones), que declara la versión de
XSLT que se está usando y el espacio de nombres (namespace) que vamos a usar, es decir, el prefijo que
[Link] 29/05/2017
Tutorial de XSL Page 4 of 19
usarán todas las instrucciones propias de XSLT; en este caso, usamos xsl, pero cambiando esta instrucción
podríamos usar otro cualquiera.
Ese esqueleto está organizado en "templates", que son partes de la hoja que se "disparan" cuando
encuentran una etiqueta que corresponda a lo que hay en su atributo match. El primer y único template comienza
en la línea 5, y, en este caso, el template que corresponde a la etiqueta raíz genera un esqueleto de página
HTML. La "orden" en la línea 9 cede el control a los otros templates, es decir, trata de aplicar todos los demás
templates que haya en el documento, incluyendo el resultado de aplicarlos precisamente en ese punto (es decir,
entre las etiquetas h1. En este caso no hay más templates, salvo los llamados los templates por defecto, que lo
único que hacen es incluir el contenido de las etiquetas en el documento de salida. Es decir, en la práctica lo que
hemos hecho es decirle dónde tiene que incluir en el esqueleto los valores del documento original, sin
procesarlos más.
La orden <xsl:apply-templates /> podría haberse sustituido, en este caso, por <xsl:value-of
select='tienda' /> y habría tenido exactamente el mismo efecto, es decir, incluir el contenido de la etiqueta
tienda (y todas las que descienden de ella).
Ejercicios 2
1. Crear un documento con otra etiqueta raíz, por ejemplo zzzxxx, y ver qué efecto tiene en la salida .
2. Crear un documento con varias etiquetas, con diferentes niveles de anidación, y aplicar la hoja de estilo, para
ver qué efecto tiene.
<tienda>
<nombre>La tiendecilla </nombre>
<telefono>953 87 12 23 </telefono>
<producto>
<codigo>92 </codigo>
<cantidad>10 </cantidad>
<articulo>Radio-Casette </articulo>
</producto>
<producto>
<codigo>103 </codigo>
<cantidad>50 </cantidad>
<articulo>Reloj Cocina </articulo>
</producto>
<producto>
<codigo>1312 </codigo>
<cantidad>3 </cantidad>
<articulo>Sofá </articulo>
</producto>
</tienda>
5 <xsl:template match='/'>
6 <html>
7 <xsl:apply-templates />
8 </html>
9 </xsl:template>
11 <xsl:template match='tienda'>
12 <head><title><xsl:value-of select='nombre' /> (Generado por [Link])</title></head>
13 <body>
14 <h1><xsl:value-of select='nombre' /> </h1>
16 <h2>Teléfono: <xsl:value-of select='telefono' /> </h2>
18 <h2>Nuestros mejores productos </h2>
19 <table>
20 <tr><th>Código</th><th>Existencias</th><th>Artículo</th></tr>
21 <xsl:apply-templates select='producto' />
22 </table>
23 </body>
24 </xsl:template>
26 <xsl:template match='producto'>
27 <tr><xsl:apply-templates /></tr>
28 </xsl:template>
30 <xsl:template match='codigo|cantidad|articulo'>
31 <td><xsl:apply-templates /></td>
32 </xsl:template>
Esta hoja, a la que se le han suprimido los elementos comunes con la hoja anterior (comienzo y final), se
compone de cuatro templates diferentes, mientras que la anterior tenía solamente uno. Cada template trata
elementos de diferente profundidad dentro del árbol del documento XML: el primer template trataría la raíz, el
segundo las ramas que descienden de él, y el tercer y cuarto ramas progresivamente más bajas.
[Link] 29/05/2017
Tutorial de XSL Page 5 of 19
Por eso el primer template simplemente incluye el código de apertura y cierre del documento HTML, y
cede control al siguiente template, que trata la primera etiqueta, tienda, tal como aparece en el atributo match.
En este template se incluyen dentro del patrón en HTML el nombre y al telefono, usando xsl:value-of, que
simplemente incluye el contenido del elemento correspondiente. También se crea el esqueleto de una tabla en
HTML (líneas 19 en adelante), con su cabecera, y cede control al siguiente template, que se encargará de cada
uno de los productos; para que se procesen sólo las etiquetas de este tipo que desciendan de tienda, y no las
otras (nombre, telefono), que ya están incluidas en la salida, se usa el atributo select (línea 21): con xsl:apply-
templates select='producto' se aplicarán sólo los templates que correspondan a este elemento.
Ese template comienza en la línea 26 y crea el esqueleto de una fila, cediendo el control a los templates
que traten con los descendientes. Hay un sólo template que lo hace, el que comienza en la línea 30; en vez de
procesar un sólo tipo de elemento, procesa 3, y para ello usamos | para indicar que puede procesar cualquiera
de ellos, incluyéndolos dentro de un demarcador de celda de tabla en HTML
Ejercicios 3
1. Crear un documento para una clasificación de equipos de fútbol en XML, y transformarlo mediante XSLT en
una tabla HTML, con cada equipo en una fila, diferentes valores (puntuación, goles a favor y en contra) en
columnas, con el nombre del equipo en negrita.
Este catálogo lo podemos presentar directamente como un formulario HTML, usando la hoja de estilo
siguiente: ([Link]; sólo están las líneas que difieren de los ejemplos anteriores)
[Link] 29/05/2017
Tutorial de XSL Page 6 of 19
11 <xsl:template match='tienda'>
37 <xsl:template match='caracteristicas'>
38 <td><ul>
39 <xsl:for-each select='linea'>
40 <li><xsl:value-of select='.' /></li>
41 </xsl:for-each>
42 </ul></td>
43 </xsl:template>
44
45 <xsl:template match='opciones'>
46 <td><xsl:value-of select='@nombre' /><select>
47 <xsl:for-each select='opcion'>
48 <option><xsl:value-of select='@valor' /></option>
49 </xsl:for-each>
50 </select></td>
51 </xsl:template>
52
53 <xsl:template match='precio'>
54 <td>Precio: <xsl:value-of select='.' /> <xsl:value-of select='@moneda' />s </td>
55 </xsl:template>
56
57 </xsl:stylesheet>
Si todavía no sabes lo que es un XPath, esta
En la línea 18 (la tercera del ejemplo) aparece la primera estructura nueva: es una ocasión tan buena como otra
xsl:for-each, que realiza un bucle sobre una serie de elementos que cumplan la cualquiera. Se trata de una forma de
condición que pone en el atributo select; en este caso, todos los elementos url expresar o seleccionar de forma única nodos
que desciendan del contexto actual (estamos al nivel de la etiqueta tienda). En o grupos de nodos de un árbol DOM que
este atributo se puede incluir cualquier XPath que dé como resultado un node- represente a un documento XML. Hay un
set, y se ejecutará una vez por cada elemento del mismo. Por ejemplo, si excelente tutorial que explica qué tipos de
pusiéramos <xsl:for-each select='producto'> se ejecutaría una vez por cada nodos hay, y cómo expresar un nodo
producto, exactamente a como se hace arriba con xsl:apply-templates (en determinado.
realidad, para lo que sabemos en este punto del tutorial, son prácticamente
iguales).
Justamente dentro del bucle usamos atributos; en realidad, forman parte de la definición de XPath y no
tienen mucha historia: para usar un atributo, se le pone la arroba delante y punto. En este caso, se ponen las
llaves alrededor para separar el atributo del valor del elemento que se está procesando (., en la línea 19). Las
características y opciones se procesan de manera análoga: se ejecuta un bucle para cada uno de los
subelementos, generando elementos de una lista en un caso, y opciones de un formulario en otro caso.
Ejercicios 4
1. Hacer el ejercicio anterior, usando atributos para alguna de las cantidades.
4
5 <xsl:param name='seccion' />
48 <xsl:template match='opciones'>
49 <td><xsl:value-of select='@nombre' />
50 <xsl:choose>
51 <xsl:when test='@tipo="unica"' >
52 <select>
53 <xsl:for-each select='opcion'>
54 <option><xsl:value-of select='@valor' /></option>
55 </xsl:for-each>
56 </select>
57 </xsl:when>
58 <xsl:when test='@tipo="si_no"'>
[Link] 29/05/2017
Tutorial de XSL Page 7 of 19
Para usar esta hoja pasándole parámetros desde la línea de órdenes, habrá que hacerlo así (usando
saxon):
java [Link]
-IN [Link]
-XSL [Link]
-PARAM seccion Muebles
-OUT [Link]
Si se usa la hoja de estilo dentro de un entorno de publicación tal como el Cocoon, habrá que pasarle los
parámetros al documento XML, bien directamente desde el URL o desde un formulario, algo así:
[Link] En Mozilla/Firefox y otros navegadores debería
funcionar algo similar, pero no funciona. Si alguien encuentra como se hace, que avise.
En cualquier caso, el resultado será una página que incluirá solamente los productos correspondientes a
una sección.
El truco para hacer esto está en los primeros templates. Para empezar, XSLT es bastante idiosincrático, y
no puede recoger los parámetros que se le pasan a no ser que se declare un parámetro interno, y se le asigne el
nombre. Este parámetro es similar a las variables de los lenguajes de toda la vida, salvo que no se le puede
cambiar el valor: una vez que se le asigna uno al principio, se queda con él; el ámbito del parámetro será toda
la hoja, y mientras se esté ejecutando. Eso se hace en la línea 5; posteriormente, en la línea 16 se usa el valor
de la variable en una sentencia xsl:value-of; para acceder a su valor, se usa $seccion.
En la línea 27 se usan los predicados de XPath para seleccionar sólo aquellos nodos en los que el
elemento seccion tenga el mismo valor que la variable; en este atributo se puede usar cualquier XPath,
incluyendo este tipo de decisiones; conocer XPath y usarlo con sabiduría nos puede ahorrar un montón de
código.
Para tomar decisiones (más que para seleccionar) un poco más complejas, con diferentes opciones, XSLT
incluye las órdenes xsl:choose/xsl:when, que se usan conjuntamente (como el switch/case en C), tal como se ve
en la línea 53. En este caso se usa para seleccionar diferente presentación, dependiendo del valor del atributo
tipo; en caso de que sea "unica" usamos unos menuses, mientras que si es "si_no" usamos una "checkbox", que
se pueda pulsar o no dependiendo de la opción.
Ejercicios 5
1. Cambiar la clasificación, de forma que se usen sólo los equipos que tengan una puntuación mayor que una
dada, que se pase como parámetro.
2. Cambiar la clasificación, de forma que aparezcan en una tabla los tres primeros con un color, y los siguientes
con un color diferente. Usar expresiones XPath para seleccionarlos o <xsl:number>; usar si es necesario
una variable para establecer el color.
¿Qué ocurre si
queremos sacar los
resultados por orden
alfabético, en vez del mismo orden que en el documento? Habrá que usar una nueva opción de apply-templates,
sort. Por ejemplo, si queremos formatear el siguiente fichero XML ([Link]):
[Link] 29/05/2017
Tutorial de XSL Page 8 of 19
<raiz>
<cosa>Pepe </cosa>
<cosa>Juan </cosa>
<cosa>Enrique </cosa>
<cosa>Xabier </cosa>
<cosa>Aarón </cosa>
</raiz>
Se puede hacer con la siguiente hoja de estilo ([Link]), de la cual extraemos solo las órdenes
pertinentes:
11 <xsl:apply-templates select='cosa'>
12 <xsl:sort select='.' data-type='text'/>
13 </xsl:apply-templates><br />
El resultado se puede ver en el fichero [Link]. En este caso, en vez de aplicar la orden apply-
templates en un solo tag "vacío" (con el / al final) se aplica en forma de tag y antitag, con las opciones en medio.
La opción xsl:sortsirve para ordenar, y como clave de ordenación se puede usar cualquier atributo, XPath, o en
este caso, el contenido en sí de la etiqueta cosa. En la salida, saldrán ordenados, Aarón primero y Xabier el
último. El atributo data-type sirve para indicar el criterio de ordenación,< code>text para texto y number para
ordenación numérica.
Todavía se puede cambiar un poco más el sistema: a veces resulta que uno quiere procesar de forma
diferente un elemento, dependiendo de la entrada. Meter decisiones puede ser un poco coñazo, así que el propio
estándar XSL tiene la forma de hacerlo: usando modos, tal como se hace en la siguiente y bonita hoja de estilo
([Link]):
2
3 <xsl:stylesheet version="1.0" xmlns:xsl="[Link]
4
5 <xsl:param name='modo' />
6 <xsl:output encoding='iso-8859-1' />
7 <xsl:template match='raiz'>
8 <xsl:processing-instruction name="cocoon-format">type="text/html"</xsl:processing-instruction>
9 <html>
10 <head><title>Ordenando</title></head>
11 <body>
12 Mode: <xsl:value-of select='$modo' />
13 <ol>
14 <xsl:choose>
15 <xsl:when test='$modo = verbose'>
16 <xsl:apply-templates select='cosa' mode='verbose'>
17 <xsl:sort select='.' data-type='text'/>
18 </xsl:apply-templates><br />
19 </xsl:when>
20 <xsl:otherwise>
21 <xsl:apply-templates select='cosa' mode='normal'>
22 <xsl:sort select='.' data-type='text'/>
23 </xsl:apply-templates><br />
24 </xsl:otherwise>
25 </xsl:choose>
26 </ol>
27 </body>
28 </html>
29 </xsl:template>
30
31 <xsl:template match='cosa' mode='normal'>
32 <li><xsl:value-of select='.'/></li>
33 </xsl:template>
34
35 <xsl:template match='cosa' mode='verbose'>
36 <li>Nombre: <xsl:value-of select='.'/></li>
37 </xsl:template>
38
39 </xsl:stylesheet>
En esta hoja de estilo se usa el atributo mode al llamar y al definir un template; los nombres que le hemos
asignado son arbitrarios, pero lo que hacen es que, en caso de que se le pase como parámetro "verbose"
imprimirá "nombre" delante del nombre de la persona; si no, lo imprimirá como antes. Para que funcione, se
toma una decisión (a partir de la línea 14): en caso de que el modo sea "verbose", se llama al template usando
como atributo de modo esa palabra; en otro caso, se llama al template "normal". Ese código tiene el efecto de
que se llame a un template o a otro, según el modo que se haya elegido.
Pero claro, esto se puede resolver, en este caso, de una forma mucho más simple. ¿No sería ideal que se
pudiera llamar a un template con parámetros, como si de una subrutina se tratara? Pues sí, se puede, tal como
se hace en la hoja siguiente ([Link]):
[Link] 29/05/2017
Tutorial de XSL Page 9 of 19
La principal diferencia con los dos anteriores está en la línea 14: la orden xsl:with-param hace que se llame
al template con un parámetro determinado, cuyo nombre y valor queda establecido por los atributos. En este
caso, estamos asignándole al parámetro miModo el mismo valor que el del parámetro modo (y por eso es
innecesario, peor admitámoslo por mor de la pedagogía). Ese parámetro se recibe dentro del template con una
sentencia similar a la que se usa para los parámetros globales: xsl:param; si el parámetro no se declara aquí, al
principio del template, XSL no le hará ni puto caso.
Y ya dentro del template, usamos una decisión, como las que se han visto anteriormente, para imprimir el
introito a cada nombre en caso de que el modo sea el adecuado. Y aquí paz y después gloria.
Ejercicios 6
1. Cambiar el programa de procesamiento del XML de los equipos de fútbol, de forma que salgan ordenados por
orden de puntuación (se supone que el original puede estar desordenado), o por orden alfabético, dependido de
un parámetro.
2. Añadir modos a la hoja de procesamiento de las quinielas, de forma que, en un modo, salga en forma de tabla,
y en otro modo, en forma de lista ordenada.
3. Cambiar la hoja de procesamiento de las quinielas, de forma que cada fila aparezca con un color diferente.
Como siempre, aquí está la salida. Se han puesto las líneas que introducen elementos nuevos solamente.
La principal complicación de este tipo de problemas, que se resuelven fácilmente con un bucle for en
cualquier lenguaje de programación pachanguero, en lenguajes funcionales pueden ser un poco más
complicados. Por eso, muchos procesadores de XSL tienen extensiones que permiten hacer bucles
convencionales, como veremos más adelante.
El principal problema es que, dado que no se pueden actualizar variables por la ausencia de efectos
secundarios, no se puede crear un bucle que vaya comprobando el valor de una variable y actualizándolo en
[Link] 29/05/2017
Tutorial de XSL Page 10 of 19
cada iteración. La única solución es sustituir los bucles clásicos por bucles recursivos, en los cuales se llama
recursivamente a una subrutina (en este caso, template) hasta que se cumple una condición.
En este caso, vamos a incluir una etiqueta select y sus correspondientes option, una para cada uno de las
opciones que haya. Y no tenemos más remedio que llamar a una rutina recursivamente. Eso se hace en la línea
65. En este caso en vez de dejar que los templates se disparen según los valores de una etiqueta, lo llamamos
explícitamente con la orden xsl:call-template. Y dado que se trata de una especie de subrutina o procedimiento,
hay que llamarlo también con sus correspondientes parámetros, para lo cual se usa xsl:with-param. Es decir, las
siguientes órdenes
<xsl:call-template name='option-range'>
<xsl:with-param name='range' select='@rango'/>
</xsl:call-template>
Esto correspondería a algo así como void function option-range(var range, var i=0), es decir, declaración
de dos variables, una de las cuales tiene un valor por defecto, el 0, y otra sin valor por defecto, que tiene que
ser dado por el usuario.
El resto de ese template, a partir de la línea 118, comprueba si el range es distinto al contador que
usamos, i, y si lo es, imprime las etiquetas HTML, y vuelve a llamarse recursivamente, incrementando el
contador. Cuando range y i sean iguales, la recursión para.
En este template se usan también variables, las que se pasan como parámetro. Las variables, aunque no
lo son en el sentido clásico, se pueden actualizar dentro de un template, asignársele valor y pasar como
parámetro a otros templates; para asignarles valor se puede usar esta construcción:
<xsl:param name='i'>0</xsl:param>
[Link] 29/05/2017
Tutorial de XSL Page 11 of 19
En resumen, con esta hoja de estilo se obtiene una página HTML ([Link]) similar a la
anterior, salvo que las respuestas de valor numérico se seleccionan a
través de un menú.
<xsl:stylesheet version="1.0"
xmlns:xsl="[Link]
xmlns:saxon="[Link]
extension-element-prefixes="saxon">
<xsl:for-each select='saxon:range(0,@rango)'>
<option><xsl:value-of select='.' /></option>
</xsl:for-each>
Ejercicios
Contenido
de esta
sección
• Funciones
XPath
9 Funciones y bucles • xsl:variable
• Bucles y
node-
sets
[Link] 29/05/2017
Tutorial de XSL Page 12 of 19
realidad no sirve para nada, porque cada campo no tiene nombre propio
ni nada de eso. O sea, que hay que ponerle nombre propio, para poder
procesarlo de verdad como un formulario. Como el jefe no dice que haya
que hacerlo de verdad, ya veremos como lo haremos luego. Y hacemos la
siguiente hoja de estilo ([Link]),
de la cual ponemos sólo los sitios que más han cambiado.:
59 <xsl:template match="cuestion">
60 <p><br/></p>
61 <table border="0" width="90%" bgcolor="#000000" cellspacing="0" cellpadding="0">
62 <tr>
63 <td width="100%">
64 <table border="0" width="100%" cellpadding="4">
65 <tr>
66 <td width="100%" colspan='2' bgcolor="#e0e0e0">
67 <big> <xsl:value-of select="pregunta"/></big>
68 </td>
69 </tr>
70 <xsl:choose>
71 <xsl:when test='@tipo="multiple"'>
72 <xsl:variable name='pos' select='position()' />
73 <xsl:variable name='varios' select='@varios' />
74 <xsl:for-each select='.//respuesta'>
75 <tr>
76 <td width="100%" bgcolor="white">
77 <xsl:value-of select='position()' />. <xsl:value-of select='.' />
78 </td>
79 <td width="100%" bgcolor="white">
80 <xsl:choose>
81 <xsl:when test='$varios=1'>
82 <input type='radio' name='radio{$pos}' />
83 </xsl:when>
84 <xsl:otherwise>
85 <input type='checkbox' name='cb{$pos}' />
86 </xsl:otherwise>
87 </xsl:choose>
88 </td>
89 </tr>
90 </xsl:for-each>
91 </xsl:when>
92 <xsl:when test='@tipo="numero"'>
93 <tr>
94 <td colspan ='2' width="100%" bgcolor="white">
95 <select name='{concat("select",position())}'>
96 <xsl:call-template name='option-range'>
97 <xsl:with-param name='range' select='@rango'/>
98 </xsl:call-template>
99 </select>
100 </td>
101 </tr>
102 </xsl:when>
103 <xsl:when test='@tipo="rollete"'>
104 <tr>
105 <td colspan='2' width="100%" bgcolor="white">
106 <input type='text' name='{concat("radio",position())}'/>
107 </td>
108 </tr>
109 </xsl:when>
110 <xsl:when test='@tipo="bool"'>
111 <tr>
112 <td bgcolor="white">
113 Si
114 </td>
115 <td bgcolor="white">
116 <input type='radio' name='{concat("radio",position())}'/>
117 </td>
118 </tr>
119 <tr>
120 <td bgcolor="white">
121 No
122 </td>
123 <td bgcolor="white">
124 <input type='radio' name='{concat("radio",position())}' />
125 </td>
126 </tr>
127 </xsl:when>
128 </xsl:choose>
129 </table>
130 </td>
131 </tr>
132 </table>
133 </xsl:template>
[Link] 29/05/2017
Tutorial de XSL Page 13 of 19
Ejercicios
1. A partir de un fichero XML con los equipos de fútbol tales como los
que se han usado en ejercicios anteriores, devolver otro fichero XML
que contenga sólo los equipos que tengan más goles a favor que en
contra.
Contenido de
esta sección
• Procesando
con XSL
[Link] 29/05/2017
Tutorial de XSL Page 14 of 19
• Algunas
extensiones
En fin, que el jefe que dice que vale, que el formulario está Xalan
para
perfecto, pero a ver, tanto XML y tanta gaita gallega, pero al final escribir
el formulario habrá que procesarlo usando PERL o algún otro lenguaje ficheros, y
serio. Así que, para demostrarle que no tiene razón, tendremos que lo mismo
procesar también el formulario usando XSLT, aunque sea nada más que en
por eso. Y lo hacemos sobre el siguiente fichero de encuesta ([Link]): XSLT 1.1
<encuesta>
<cuestion tipo='multiple'>
<respuesta>Si </respuesta>
<respuesta>No </respuesta>
</cuestion>
<cuestion tipo='multiple'>
</cuestion>
<cuestion tipo='multiple'>
<respuesta>Epatante </respuesta>
</cuestion>
</encuesta>
Esta encuesta la procesaremos con la siguiente hoja de estilo ([Link]), de la cual sólo mostramos las
líneas en las que se diferencia con la anterior:
2
3 <xsl:stylesheet version="1.0"
4 xmlns:xsl="[Link]
5 xmlns:redirect='[Link]'
6 extension-element-prefixes="redirect">
7
8 <xsl:param name='radio2'></xsl:param>
9 <xsl:param name='radio4'></xsl:param>
10 <xsl:param name='radio6'></xsl:param>
11
12 <xsl:template match='/'>
13 <xsl:choose>
14 <xsl:when test="$radio2">
15 <xsl:call-template name='procesa-encuesta'>
16 </xsl:call-template>
[Link] 29/05/2017
Tutorial de XSL Page 15 of 19
17 </xsl:when>
18 <xsl:otherwise>
19 <xsl:apply-templates />
20 </xsl:otherwise>
21 </xsl:choose>
22 </xsl:template>
23
24 <xsl:template name="procesa-encuesta">
25 <xsl:processing-instruction name="cocoon-format">type="text/html"</xsl:processing-instruction>
26 <redirect:write select='"/tmp/[Link].1"'>
27 Resultados:
28 <xsl:value-of select='$radio2' /> -
29 <xsl:value-of select='$radio4' /> -
30 <xsl:value-of select='$radio6' />
31 </redirect:write>
32 <html>
33 <head>
34 <title>Procesando encuesta</title>
35 </head>
36 <body>
37 <h1>Procesando encuesta</h1>
38
39 <table border="0" width="80%" bgcolor="#000000" cellspacing="0" cellpadding="0">
40 <tr>
41 <td width="100%">
42 <table border="0" width="100%" cellpadding="4">
43 <tr>
44 <td width="100%" bgcolor="#c0c0c0" align="right">
45 <big><big>Encuesta chuli</big></big>
46 </td>
47 </tr>
48 <tr>
49 <td width="100%" bgcolor="#ffffff" align="center">
50 <xsl:for-each select='.//cuestion'>
51 <table border="0" width="90%" bgcolor="#000000" cellspacing="0" cellpadding="0">
52 <tr>
53 <td width="100%">
54 <table border="0" width="100%" cellpadding="4">
55 <tr>
56 <td width="100%" bgcolor="#e0e0e0">
57 <big> <xsl:value-of select="pregunta"/></big>
58 </td>
59 <td width="100%" bgcolor="white">
60 <xsl:choose>
61 <xsl:when test='position()=1'> <xsl:value-of select='$radio2' /> </xsl:when>
62 <xsl:when test='position()=2'> <xsl:value-of select='$radio4' /> </xsl:when>
63 <xsl:when test='position()=3'> <xsl:value-of select='$radio6' /> </xsl:when>
64 </xsl:choose>
65 </td>
66 </tr>
67 </table>
68 </td>
69 </tr>
70 </table>
71 <p><br/></p>
72
73 </xsl:for-each>
74 </td>
75 </tr>
76 </table>
77 </td>
78 </tr>
79 </table>
80 </body>
81 </html>
82 </xsl:template>
83
export
CLASSPATH=$CLASSPATH:/usr/local/xalan-j_1_2_2/[Link]
[Link] 29/05/2017
Tutorial de XSL Page 16 of 19
Más adelante, en las líneas 8,9 y 10, se tienen que declarar los
parámetros del formulario que se van a usar. En este caso, el
formulario que se ha creado tiene 3 elementos: radio2, 4 y 6. A la
vez, se inicializan con un valor nulo; en la misma sentencia se le
podría asignar un valor por defecto, simplemente metiéndolo dentro de
los tags. En nuestro caso, no nos conviene, porque vamos a usarlo para
saber si el fichero XML se está procesando "de primeras" o no, o se
está procesando después de rellenar el formulario. Hay otra
alternativa a declarar esas variables, y es usar las taglibs
que vienen con el Cocoon; en concreto,
request:get-parameter-names. Una vez más, no son
universales, o sea que no van a funcionar en todos los sistemas,
aunque probablemente haya algo muy similar en el resto de los
sistemas.
java [Link]
-in [Link] -xsl [Link] -out [Link]
-param radio2 3 -param radio4 5 -param radio6 3
[Link] 29/05/2017
Tutorial de XSL Page 17 of 19
Resultados:
3 -
5 -
3
<xsl:document href="encuesta_resultados_s.1">
Resultados:
<xsl:value-of select='$radio2' /> -
<xsl:value-of select='$radio4' /> -
<xsl:value-of select='$radio6' />
</xsl:document>
java [Link]
-o [Link] [Link]
[Link] radio2=3 radio4=6 radio6=1
[Link] 29/05/2017
Tutorial de XSL Page 18 of 19
Ejercicios
1. Sobre cualquier documento XML, hacer una hoja de estilo que tome
como parámetro un XPath y presente ese XPath del documento original.
3. A partir de un documento XML que contenga una tabla HTML, hacer una
hoja de estilo, que, según el valor de un parámetro, escriba sólo el
valor de la primera columna o sólo el contenido de la tabla, sin
etiquetas.
• Un sitio
bastante completo, con tutoriales de XSLT y de muchas otras cosas, que incluye páginas en las cuales se pueden
aplicar transformaciones XSLT sobre la marcha.
• XSLT
Programmer's Reference, 2nd edition, por Michael Kay, un peazo de libro,
completo, que sirve como tutorial y como referencia
también. Imprescindible. Además,
ahora está actualizado a la
segunda edición, incluyendo la
versión 1.1 de XSLT.
[Link] 29/05/2017
Tutorial de XSL Page 19 of 19
• Un sitio
bastante completo, con tutoriales de XSLT y de muchas otras cosas, que incluye páginas en las cuales se pueden
aplicar transformaciones XSLT sobre la marcha.
• El resto, lo puedes ver en una lista de punteros, con artículos, libros y tutoriales.
Este tutorial es (c) Juan J. Merelo Guervós. Se podrá reproducir en todo o en parte, siempre que se mantenga un enlace al sitio original.
[Link] 29/05/2017