Introducción
XSLT (Transformaciones XSL) es un lenguaje de programación declarativo que permite generar documentos a partir de documentos XML.
¿Qué es un lenguaje de programación declarativo? ¿E imperativo?
- Lenguaje declarativo: Se centra en lo que deseamos obtener como resultado porque consiste en una serie de reglas o plantillas que hay que aplicar a un documento XML.
- Lenguaje imperativo: Se enfoca en la secuencia de pasos para resolver un problema.
El funcionamiento de transformación de documentos se describe a continuación:
Esquema de funcionamiento de procesador XSLT. En verde los documentos XML
- El documento XML es el documento inicial a partir del cual se va a generar el resultado.
- La hoja de estilo XSLT es el documento que contiene el código fuente del programa, es decir, las reglas de transformación que se van a aplicar al documento inicial.
- El procesador XSLT es el programa de ordenador que aplica al documento inicial las reglas de transformación incluidas en la hoja de estilo XSLT y genera el documento final.
- El resultado de la ejecución del programa es un nuevo documento (que puede ser un documento XML o no).
XSLT se utiliza para obtener a partir de un documento XML otros documentos (XML o no). A un documento XML se le pueden aplicar distintas hojas de estilo XSLT para obtener distintos resultados y una misma hoja de estilo XSLT se puede aplicar a distintos documentos XML.
El lenguaje XSLT está normalizado por el W3C, que ha publicado tres versiones de este lenguaje:
- noviembre de 1999: XSLT 1.0
- enero de 2007: XSLT 2.0
- junio de 2017: XSLT 3.0
- marzo de 2021: XSLT 2.0 (2ª ed)
Linea del tiempo de XSLT
Aunque hay incompatibilidades entre estas versiones, lo que se cuenta en esta lección es válido para todas ellas.
Procesadores XSLT
Un procesador XSLT es un software que lee un documento XSLT y otro XML, y crea un documento de salida aplicando las instrucciones de la hoja de estilos XSLT a la información del documento XML.
Pueden estar integrados dentro de un explorador Web, en un servidor web, o puede ser un programa que se ejecuta desde la línea de comandos.
El procesador que vamos a usar un procesador XSL gratuito y de código abierto llamado Saxon-HE.
Si quieres saber como instalar Saxon-HE puedes leer el apartado Instalación de Saxon-HE del artículo Transformación de datos con XML y XSL para su reutilización.
También se puede usar XML Copy Editor como se puede ver en el apartado “Aplicar una transformación XSLT” del artículo XML Copy Editor.
Quizás necesites configurar variables de entorno en este proceso. Si quieres saber que son las variables de entorno y como se configuran, lee el artículo Tutorial: La variable de entorno Path
Hojas de estilo XSLT
XSLT es un lenguaje declarativo. Por ello, las hojas de estilo XSLT no se escriben como una secuencia de instrucciones, sino como una colección de plantillas (template rules). Cada plantilla establece cómo se transforma un determinado elemento (definido mediante expresiones XPath). La transformación del documento se realiza de la siguiente manera:
- El procesador analiza el documento y construye el árbol del documento.
- El procesador recorre el árbol del documento desde el nodo raíz.
- En cada nodo recorrido, el procesador aplica o no alguna plantilla:
- Si a un nodo no se le puede aplicar ninguna plantilla, su contenido se incluye en el documento final (el texto del nodo, no el de los nodos descendientes). A continuación, el procesador recorre sus nodos hijos.
- Si a un nodo se le puede aplicar una plantilla, se aplica la plantilla. La plantilla puede generar texto que se incluye en el documento final. En principio, el procesador no recorre sus nodos hijos, salvo que la plantilla indique al procesador que sí que deben recorrerse los nodos hijos.
- Cuando el procesador ha recorrido el árbol, se ha terminado la transformación.
Una hoja de estilos XSL es un documento XML con extensión .xsl, en el que se define las transformaciones a realizar en el documento, mediante una serie de elementos y atributos.
¿Qué extensión deben tener los ficheros XSLT?
Primero, se debe indicar la cabecera para indicar que es un fichero XML:
1
<?xml version="1.0" encoding="UTF-8" ?>
Posteriormente se indica el siguiente elemento raíz para indicar que es un documento XSL:
1
2
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
</xsl:stylesheet>
Dentro de la instrucción xsl:stylesheet
se pueden encontrar los llamados elementos de alto nivel y las plantillas, como en el ejemplo siguiente:
1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
</xsl:template>
</xsl:stylesheet>
Estas etiquetas son:
- El elemento de alto nivel
xsl:output
indica el tipo de salida producida. - La instrucción
xsl:template
es una plantilla.- El atributo
match
indica los elementos afectados por la plantilla y contiene una expresión XPath. - El contenido de la instrucción define la transformación a aplicar (si la instrucción no contiene nada, como en el ejemplo anterior, sustituirá el nodo por nada, es decir, eliminará el nodo, aunque conservará el texto contenido en el elemento).
- El atributo
Cuando se aplica una plantilla a un nodo, en principio no se recorren los nodos descendientes. Para indicar que sí queremos recorrer los nodos descendientes y aplicarles las plantillas que les correspondan, hay que utilizar la instrucción <xsl:apply-templates />
, como en el ejemplo siguiente:
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="elemento">
</xsl:template>
</xsl:stylesheet>
¿Qué lenguaje tiene mayor funcionalidad: XSLT o CSS?
Con CSS NO se pueden realizar operaciones, como sumar valores de todos los elementos de un documento. Por ejemplo, no se podrían combinar todas las nóminas anuales de un empleado con el fin de obtener un total de ingresos.
Enlazar documentos XML con hojas de estilo XSLT
Se puede asociar de forma permanente una hoja de estilo XSLT a un documento XML mediante la instrucción de procesamiento <?xml-stylesheet ?>
, la misma que permite asociar hojas de estilo CSS. La instrucción de procesamiento <?xml-stylesheet ... ?>
va al principio del documento, después de la declaración XML.
¿Se pueden usar hojas de estilos CSS en un documento XML?
1
2
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="ejemplo.xsl"?>
Cuando se visualiza en un navegador web un documento XML enlazado con una hoja de estilo XSLT, los navegadores muestran el resultado de la transformación, aunque si se muestra el código fuente de la página, los navegadores muestran el documento XML original.
Google Chrome no muestra los documentos XML que enlazan a hojas de estilo XSLT abiertos como archivos locales (
file://...
), como se comenta en la lección de diferencias entre navegadores. Firefox sí lo hace.
¿Qué ocurre si abro documentos XML con hojas de estilo XSLT en el navegador?
Al abrir en un navegador una página XML enlazada con una hoja de estilo XSLT, el navegador muestra el resultado de la transformación. Pero no muestra el código fuente obtenido como resultado, sino interpretando ese código fuente, como cuando se enlaza una hoja de estilo CSS vacía.
Elementos básicos de XSLT
xsl:stylesheet
: Define el elemento raíz de la hoja de transformaciones.xsl:transform
: Define el elemento raíz de la hoja de transformaciones.xsl:output
: Define el formato del documento de salidaxsl:template
: Instrucción principal de XSLT. Representa una plantilla con una serie de acciones que se realizarán si el patrón de la plantilla (atributo match) encaja con algún elemento o elementos del árbol XML.xsl:apply-templates
: Instrucción principal de XSLT. Permite aplicar plantillas sobre nodos hijos al actual.xsl:call-template
: Permite invocar a una plantilla por su nombre. Al aplicarse la plantilla con nombre el contexto no cambian lo que significa que en la plantilla invocada hay que utilizar las mismas rutas XPath. El atributo name es el que indica el nombre de la plantilla.xsl:value-of
: Visualiza el contenido del elemento indicado en el atributo select, y de sus descendientes. Existe una versión simplificada que sólo se puede usar en la creación de nuevos elementos.xsl:text
: Permite escribir el texto literal en la salida.
Elemento xsl:stylesheet
Elemento raíz en una hoja de estilo XSLT.
Elementos hijo de xsl:stylesheet
:
xsl:import
: Incluye una hoja de estilo XSLT externa en el documento de salida.xsl:include
: Incluye una hoja de estilo XSLT externa en el documento de salida.xsl:strip-space
: Elimina espacios en blanco en el documento de origen. Con el atributo obligatorio elements se seleccionan los elementos, en los cuales se eliminarán los espacios en blanco.xsl:preserve-space
: Con este elemento puede especificarse qué elementos deben conservar los espacios en blanco.xsl:output
: Define el formato del documento de salidaxsl:key
: Declara una clave para la búsqueda de nodos.xsl:decimal-format
: Define el formato de salida para los números decimales.xsl:attribute-set
: Con este elemento se definen conjuntos de atributos (xsl:attribute
).xsl:variable
: Mediante este elemento podemos definir variables. Cuando se usa como elemento de alto nivel se definen variables globales, que son válidas en toda la hoja de estilo. De no ser así, las variables tendrán validez local.xsl:param
: Con este elemento se declaran parámetros.xsl:template
: Instrucción principal de XSLT. Representa una plantilla con una serie de acciones que se realizarán si el patrón de la plantilla (atributo match) encaja con algún elemento o elementos del árbol XML.xsl:namespace-alias
: Se usa para sustituir un espacio de nombres en la hoja de estilos por otro espacio de nombres en el documento de salida.
Elemento xsl:template
Con el elemento xsl:template
elemento se definen un conjunto de reglas (plantilla) que indican cómo deben procesarse los nodos.
A través del atributo match
se establecen los nodos a los que se aplicará la plantilla. Para seleccionar el árbol del documento completo, se utiliza el patrón raíz (/
). Por ejemplo:
1
2
3
<xsl:template match="/">
instrucciones de plantilla
</xsl:template>
Con el atribulo opcional name
se le puede asignar un nombre a la plantilla, el cual se puede invocar por medio de xsl:call-template
.
Las instrucciones de plantilla indican la transformación a realizar sobre el patrón. Este ejemplo, transforma el elemento nombre en su valor con formato título. Por ejemplo:
1
2
3
<xsl:template match="nombre">
<h2><xsl:value-of/><h2>
</xsl:template>
Elementos hijo de xsl:template
:
xsl:apply-templates
xsl:call-template
: Este elemento se usa para invocar una plantilla por su nombre.xsl:apply-imports
xsl:for-each
: Crea un bucle que se ejecuta para cada uno de los nodos de contexto seleccionados.xsl:value-of
: Este elemento añade el valor de un nodo en el documento de salida.xsl:number
: Este elemento asigna un valor numérico a la posición de un elemento en el documento de salida y sirve por lo tanto para la numeración.xsl:choose
: Con este elemento se define una elección entre varias alternativas.xsl:if
: Con este elemento se crea un proceso condicionado.xsl:text
: Permite añadir texto de forma literal en el documento de salida.xsl:copy
: Copia un nodo de contexto en el documento de salida.xsl:variable
: Mediante este elemento podemos definir variables.xsl:message
: Se emplea para mostrar un mensaje durante el proceso de transformación en el procesador XSLT.xsl:fallback
xsl:processing-instruction
xsl:comment
: Sirve para añadir comentarios en el documento de salida.xsl:element
: Crea elementos XML en el documento de salida.xsl:attribute
: Se utiliza para crear atributos en el documento de salida.xsl:param
Instrucciones de control
xsl:for-each
: Permite iterar sobre una lista de elementos y aplicar transformaciones sobre ellos. El atributo select define la lista de elementos sobre los que se va a iterar.xsl:sort
: Envía a la salida datos del documento XML de partida ordenados por algún criterio. Los atributos principales son:select
: expresión XPath que indica el conjunto de nodos a ordenar.lang
: indica qué idioma se utiliza al ordenardata-type
: especifica el tipo de datos que se ordenarán.order
: concreta si el orden es ascendente o descendente.case-order
: especifica si las mayúsculas van antes que las minúsculas o viceversa (lower-first
,upper-first
).
xsl:if
: Se utiliza para producir un comportamiento condicional. Sólo permite preguntar por una condición y la manera de actuar si esta es cierta. El atributo test es el que incluye la expresión XPath que debe ser cierta o falsa.xsl:choose
,xsl:when
,xsl:otherwise
: Permiten implementar un comportamiento condicional con múltiples opciones y una opción por defecto. Es equivalente a un switch de Java.
Generación de nuevos elementos
xsl:element
: Permite generar un nuevo elemento/nodo en el documento de salida. El atributo obligatorio name especifica el nombre del nuevo elemento.xsl:attribute
: Permite generar un nuevo atributo de un elemento/nodo. El atributo obligatorio name especifica el nombre del atributo.xsl:comment
: Genera un comentario en el documento de salida. Puede ser un texto literal o un dato extraído del documento XML original.xsl:processing-instruction
: Permite generar instrucciones de procesamiento de salida.xsl:copy-of
: Realiza una copia literal de un elemento a la salida. Los atributos y elementos descendientes se copiarán también.xsl:copy
: Realiza una copia de un nodo, pero no de sus descendientes ni atributos.
Ejemplo 1
Tenemos un XML que queremos transformar que representa un catálogo de CDs:
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
...
</catalog>
Y un XSLT que indica como se transforma dicho XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Artist</th>
</tr>
<xsl:for-each select="catalog/cd">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="artist"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Si aplicamos la transformación obtenemos un fichero HTML que en el navegador se ve de la siguiente manera:
Fichero HTML resultado abierto en un navegador
Ejemplo 2
Tenemos un XML que queremos transformar:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="raquetas.xsl"?>
<tienda>
<raqueta>
<marca>BABOLAT</marca>
<modelo>PURE DRIVE</modelo>
<anyo>2012</anyo>
</raqueta>
<raqueta>
<marca>YONEK</marca>
<modelo>MPTOUR 5</modelo>
<anyo>1997</anyo>
</raqueta>
<raqueta>
<marca>WILSON</marca>
<modelo>HAMMER</modelo>
<anyo>2000</anyo>
</raqueta>
</tienda>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<h3>COLECCIÓN DE RAQUETAS</h3>
<table border="1">
<tr bgcolor="#ccffff">
<th style="text-align:left">MARCA</th>
<th style="text-align:left">MODELO</th>
<th style="text-align:left">AÑO</th>
</tr>
<xsl:for-each select="tienda/raqueta">
<tr>
<td><xsl:value-of select="marca"/></td>
<td><xsl:value-of select="modelo"/></td>
<td><xsl:value-of select="anyo"/></td>
</tr>
</xsl:for-each>
</table>
</html>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<html>
<h3>COLECCIÓN DE RAQUETAS</h3>
<table border="1">
<tr bgcolor="#ccffff">
<th style="text-align:left">MARCA</th>
<th style="text-align:left">MODELO</th>
<th style="text-align:left">AÑO</th>
</tr>
<tr>
<td>BABOLAT</td>
<td>PURE DRIVE</td>
<td>2012</td>
</tr>
<tr>
<td>YONEK</td>
<td>MPTOUR 5</td>
<td>1997</td>
</tr>
<tr>
<td>WILSON</td>
<td>HAMMER</td>
<td>2000</td>
</tr>
</table>
</html>
Fichero HTML resultado abierto en un navegador
¿Qué tendría que hacer para arreglar el problema de la codificación del fichero HTML de la imagen anterior?
Elementos avanzados de XSLT
xsl:preserve-space
: Con este elemento puede especificarse qué elementos deben conservar los espacios en blanco.xsl:strip-space
: Elimina espacios en blanco en el documento de origen. Con el atributo obligatorio elements se seleccionan los elementos, en los cuales se eliminarán los espacios en blanco.xsl:import
: Incluye una hoja de estilo XSLT externa en el documento de salida.xsl:apply-imports
: El elementoxsl:apply-imports
permite buscar la plantilla adecuada para el nodo de contexto. Para ello se tienen en cuenta los nodos de contexto importados a través dexsl:import
.xsl:include
: Incluye una hoja de estilo XSLT externa en el documento de salida.xsl:variable
: Mediante este elemento podemos definir variables. Cuando se usa como elemento de alto nivel se definen variables globales, que son válidas en toda la hoja de estilo. De no ser así, las variables tendrán validez local.xsl:with-param
: Se define el valor de un parámetro que se pasará a una plantilla.xsl:param
: Con este elemento se declaran parámetros.xsl:number
: Este elemento asigna un valor numérico a la posición de un elemento en el documento de salida y sirve por lo tanto para la numeración.xsl:decimal-format
: Define el formato de salida para los números decimales.xsl:namespace-alias
: Se usa para sustituir un espacio de nombres en la hoja de estilos por otro espacio de nombres en el documento de salida.xsl:attribute-set
: Con este elemento se definen conjuntos de atributos (xsl:attribute
).xsl:fallback
: Define un fragmento de código a ejecutar en caso de que una nueva versión de XSLT o extensión no sea reconocida.xsl:message
: Se emplea para mostrar un mensaje durante el proceso de transformación en el procesador XSLT.xsl:key
: Declara una clave para la búsqueda de nodos.
Prioridades y resolución de conflictos
Si aplicamos varias plantillas a la vez, cada regla tiene una prioridad que puede ir de -9 a 9. Por defecto se aplican las siguientes prioridades:
Patrón | Prioridad |
---|---|
* , @* , text() y otros patrones para los que no se indica un nombre concreto. | -0.5 |
Prefijo:* , @prefijo: y otros patrones para los que se indica el espacio de nombres, pero no el nombre concreto. | -0.25 |
producto , @unidades y otros patrones donde se indiquen los nombres de los elementos y atributos concretos. | 0 |
proveedor/representante , /productos/producto/precio , precio/@unidades y otros patrones para los que se indique una jerarquía (además del nombre del elemento y/o atributo) | 0.5 |
Se puede asignar prioridades de manera explícita mediante el atributo priority. Por ejemplo:
1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/" priority="3">
...
</xsl:template>
</xsl:stylesheet>
¿Qué ocurrirá si a una plantilla se le asigna una prioridad mayor que 0.5?
Más ejemplos de plantillas XSLT
Vamos a ver ejemplos de plantillas trabajando sobre el documento siguiente:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<biblioteca>
<libro>
<titulo>La vida está en otra parte</titulo>
<autor>Milan Kundera</autor>
<fechaPublicacion año="1973"/>
</libro>
<libro>
<titulo>Pantaleón y las visitadoras</titulo>
<autor fechaNacimiento="28/03/1936">Mario Vargas Llosa</autor>
<fechaPublicacion año="1973"/>
</libro>
<libro>
<titulo>Conversación en la catedral</titulo>
<autor fechaNacimiento="28/03/1936">Mario Vargas Llosa</autor>
<fechaPublicacion año="1969"/>
</libro>
</biblioteca>
Si los ejemplos de este artículo se abren en el navegador, el resultado no coincide en casi todos los casos con el que se muestra en esta página ya que los navegadores no respetan los saltos de línea ni los espacios en blanco, ni muestran las etiquetas.
Plantillas vacías o no existentes
Si no hay plantillas, el procesador simplemente recorre todos los nodos y extrae el texto contenido por cada nodo. En el ejemplo siguiente, el resultado incluye el contenido de los nodos <título>
y <autor>
puesto que no hay ninguna plantilla.
1
2
3
4
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
</xsl:stylesheet>
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
La vida está en otra parte
Milan Kundera
Pantaleón y las visitadoras
Mario Vargas Llosa
Conversación en la catedral
Mario Vargas Llosa
Si hay una plantilla vacía, el procesador no genera ningún resultado en el documento final ni recorre los nodos hijos. En el ejemplo siguiente, el resultado incluye el contenido de los nodos <titulo>
, ya que no hay regla para ellos, pero los de <autor>
se pierden porque la plantilla es vacía.
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="autor">
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
La vida está en otra parte
Pantaleón y las visitadoras
Conversación en la catedral
En el caso más extremo, si la plantilla vacía se aplica al nodo raíz, el procesador no genera ningún resultado en el documento final ni recorre ningún nodo hijo.
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
</xsl:template>
</xsl:stylesheet>
1
<?xml version="1.0" encoding="UTF-8"?>
La instrucción xsl:value-of
La instrucción xsl:value-of
extrae el contenido del nodo seleccionado.
En el ejemplo siguiente, el documento final contiene los autores de los libros porque la plantilla los genera con la instrucción xsl:value-of
. Como se ha aplicado una plantilla al nodo <libro>
, sus hijos (<titulo>
, <autor>
y <fechaPublicacion>
) no se recorren. Por eso, los títulos de los libros no aparecen en el documento final.
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="libro">
<xsl:value-of select="autor"/>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
Milan Kundera
Mario Vargas Llosa
Mario Vargas Llosa
En el ejemplo siguiente, se obtienen el titulo y el autor de los libros, pero uno a continuación de otro. Los saltos de línea se crean tras cada aplicación de la regla (es decir, a cada libro), pero no en el interior de la regla.
1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="libro">
<xsl:value-of select="titulo"/>
<xsl:value-of select="autor"/>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
La vida está en otra parteMilan Kundera
Pantaleón y las visitadorasMario Vargas Llosa
Conversación en la catedralMario Vargas Llosa
En el ejemplo siguiente, los autores se obtienen gracias a la regla que extrae el contenido del nodo (el carácter punto “.” hace referencia al propio elemento) y los títulos se obtienen porque al no haber reglas para ese nodo se extrae el contenido. El resultado es el mismo que el del ejemplo 1-1, pero por motivos distintos.
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="autor">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
La vida está en otra parte
Milan Kundera
Pantaleón y las visitadoras
Mario Vargas Llosa
Conversación en la catedral
Mario Vargas Llosa
También se pueden extraer los valores de los atributos, utilizando @
.
En el ejemplo siguiente, las fechas de publicación se obtienen gracias a la regla que extraen el valor del atributo y los títulos y autores se obtienen porque al no haber reglas para ese nodo se extrae el contenido.
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="fechaPublicacion">
<xsl:value-of select="@año"/>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
La vida está en otra parte
Milan Kundera
1973
Pantaleón y las visitadoras
Mario Vargas Llosa
1973
Conversación en la catedral
Mario Vargas Llosa
1969
Generar texto adicional
Se puede generar texto escribiéndolo en la regla, por ejemplo, código html.
En el ejemplo siguiente se obtienen los nombres de los autores porque la regla selecciona el nodo <libro>
como en el ejemplo, pero además generamos las etiquetas <p>
. El resultado sigue sin verse bien en el navegador, porque aunque hay etiquetas <p>
, falta la etiqueta global <html>
.
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="libro">
<p><xsl:value-of select="autor"/></p>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<p>Milan Kundera</p>
<p>Mario Vargas Llosa</p>
<p>Mario Vargas Llosa</p>
Dentro de la regla podemos hacer referencia a varios subnodos.
En el ejemplo siguiente se obtienen los nombres de los autores y los títulos de los libros porque la regla selecciona el nodo <libro>
como en el ejemplo, pero además generamos las etiquetas <p>
. El resultado sigue sin verse bien en el navegador, porque aunque hay etiquetas <p>
, falta la etiqueta global <html>
.
1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="libro">
<p><xsl:value-of select="autor"/></p>
<p><xsl:value-of select="titulo"/></p>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<p>Milan Kundera</p>
<p>La vida está en otra parte</p>
<p>Mario Vargas Llosa</p>
<p>Pantaleón y las visitadoras</p>
<p>Mario Vargas Llosa</p>
<p>Conversación en la catedral</p>
Los siguientes ejemplos intentan conseguir el mismo resultado que el ejemplo anterior , pero utilizando dos reglas, y no lo consiguen:
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="libro">
<p><xsl:value-of select="autor"/></p>
</xsl:template>
<xsl:template match="libro">
<p><xsl:value-of select="titulo"/></p>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<p>La vida está en otra parte</p>
<p>Pantaleón y las visitadoras</p>
<p>Conversación en la catedral</p>
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="libro">
<p><xsl:value-of select="titulo"/></p>
</xsl:template>
<xsl:template match="libro">
<p><xsl:value-of select="autor"/></p>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<p>Milan Kundera</p>
<p>Mario Vargas Llosa</p>
<p>Mario Vargas Llosa</p>
¿Por qué en un caso se obtienen sólo los títulos y en el otro sólo los autores? Porque el procesador XSLT sólo aplica una regla a cada nodo. Si tenemos dos reglas para el mismo nodo, el procesador sólo aplica una de ellas (la última, en este caso).
Además de generar etiquetas, se puede generar texto.
En el ejemplo siguiente se generan frases a partir del contenido de los nodos.
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="libro">
<p><xsl:value-of select="autor"/> escribió "<xsl:value-of select="titulo"/>"</p>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<p>Milan Kundera escribió "La vida está en otra parte"</p>
<p>Mario Vargas Llosa escribió "Pantaleón y las visitadoras"</p>
<p>Mario Vargas Llosa escribió "Conversación en la catedral"</p>
Aplicar reglas a subnodos: la instrucción xsl:apply-templates
La instrucción xsl:apply-templates
hace que se apliquen a los subelementos las reglas que les sean aplicables.
En el ejemplo siguiente, se genera la etiqueta <html>
además de unos párrafos con los nombres de los autores. Este ejemplo sí que se puede ver en el navegador ya que se interpreta como html.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<h1>Autores</h1>
<xsl:apply-templates />
</html>
</xsl:template>
<xsl:template match="libro">
<p><xsl:value-of select="autor"/></p>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<html><h1>Autores</h1>
<p>Milan Kundera</p>
<p>Mario Vargas Llosa</p>
<p>Mario Vargas Llosa</p>
</html>
La primera regla sustituye el elemento raíz (y todos sus subelementos) por las etiquetas <html>
y <h1>
, pero además aplica a los subelementos las reglas que les son aplicables. En este caso, sólo hay una regla para los elementos <libro>
que generan los párrafos.
Saltos de línea y espacios en blanco: las instrucciones xsl:text y xsl:strip-space
Al transformar un documento, los procesadores XSLT incorporan saltos de línea y espacios en blanco en el resultado, pero no lo hacen de forma uniforme. Por ejemplo, XML Copy Editor y Notepad++ (con el plug-in XML Tools) producen diferentes resultados.
No parece haber una solución sencilla que funcione en todos los procesadores, pero sí soluciones que funcionen en cada uno de ellos.
La instrucción xsl:strip-space
En el caso de XML Copy Editor, la forma más sencilla de mejorar el formato de presentación de los resultados, eliminando líneas en blanco innecesarias y sangrando los elementos anidados, es utilizar la instrucción xsl:strip-space
. Pero debe tenerse en cuenta que esta instrucción no produce el mismo resultado en otros procesadores XSLT (como en Notepad++ con XML Tools).
La instrucción xsl:strip-space
permite indicar si los elementos que contienen únicamente espacios en blanco se incluyen en la transformación o no.
En el ejemplo anterior (del apartado sobre la instrucción xsl:apply-templates
) la etiqueta <h1>
se generaba en la misma línea que la etiqueta <html>
, pero en el ejemplo siguiente se generan en líneas distintas (y las etiquetas se muestran sangradas) al utilizar la instrucción xsl:strip-space
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*" />
<xsl:template match="/">
<html>
<h1>Autores</h1>
<xsl:apply-templates />
</html>
</xsl:template>
<xsl:template match="libro">
<p><xsl:value-of select="autor"/></p>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<html>
<h1>Autores</h1>
<p>Milan Kundera</p>
<p>Mario Vargas Llosa</p>
<p>Mario Vargas Llosa</p>
</html>
La instrucción xsl:text
En el caso de Notepad++ con XML Tools, se puede mejorar el formato de presentación de los resultados, insertando líneas en blanco innecesarias y sangrando los elementos anidados, utilizando la instrucción xsl:text
. Pero debe tenerse en cuenta que esta instrucción no permite eliminar líneas en blanco que se producen en otros procesadores (como en XML Copy Editor).
La instrucción xsl:text
permite generar texto que no se puede generar simplemente añadiéndolo (saltos de líneas y espacios en blanco, por ejemplo).
En el ejemplo anterior (del apartado sobre la instrucción xsl:apply-templates
) la etiqueta <h1>
se generaba en la misma línea que la etiqueta <html>
, pero en el ejemplo siguiente se generan en líneas distintas al añadir un salto de línea con la entidad de carácter
(y un par de espacios para alinear la etiqueta <h1>
con las etiquetas <p>
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<xsl:text> </xsl:text>
<h1>Autores</h1>
<xsl:apply-templates />
</html>
</xsl:template>
<xsl:template match="libro">
<p><xsl:value-of select="autor"/></p>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<html>
<h1>Autores</h1>
<p>Milan Kundera</p>
<p>Mario Vargas Llosa</p>
<p>Mario Vargas Llosa</p>
</html>
La instrucción xsl:attribute
La instrucción xsl:attribute
permite generar un atributo y su valor. Se utiliza cuando el valor del atributo se obtiene a su vez de algún nodo.
Por ejemplo, a partir del siguiente documento XML, se quiere generar la etiqueta <img>
. en la que el valor del atributo src sea el contenido de la etiqueta <imagen>
.
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<licencias>
<licencia>
<nombre>Creative Commons By - Share Alike</nombre>
<imagen>cc-bysa-88x31.png</imagen>
</licencia>
</licencias>
No se puede utilizar la instrucción xsl:value-of
como en el ejemplo incorrecto siguiente:
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="licencia">
<p><img src="<xsl:value-of select="imagen" />" /></p>
</xsl:template>
</xsl:stylesheet>
1
Error at line 5, column 19: not well-formed (invalid token)
En este caso el problema no es debido a la utilización de comillas dobles (también daría error si se hubieran utilizado comillas simples o entidades), sino que es necesario utilizar la instrucción xsl:attribute
.
Para generar un atributo en una etiqueta, es necesario utilizar la instrucción xsl:attribute
, como en el ejemplo siguiente:
1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="licencia">
<p><img>
<xsl:attribute name="src">
<xsl:value-of select="imagen" />
</xsl:attribute>
</img>
</p>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
<?xml version="1.0" encoding="UTF-8"?>
<p>
<img src="cc-bysa-88x31.png"/>
</p>
En la hoja de estilo XSLT, la etiqueta <img>
se escribe con apertura y cierre, aunque en el resultado aparece como etiqueta monoatómica.
De todas formas, el navegador no mostraría todavía la imagen, puesto que no interpreta la etiqueta <img>
como la etiqueta de imagen del html.
Como en ejemplos anteriores, para que la imagen se muestre en el navegador sería necesario generar también la etiqueta <html>
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<xsl:apply-templates />
</html>
</xsl:template>
<xsl:template match="licencia">
<p><img>
<xsl:attribute name="src">
<xsl:value-of select="imagen" />
</xsl:attribute>
</img>
</p>
</xsl:template>
</xsl:stylesheet>
1
2
3
4
<?xml version="1.0" encoding="UTF-8"?>
<html>
<p><img src="cc-bysa-88x31.png"/></p>
</html>
Bibliografía
- https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms256069(v=vs.100)?redirectedfrom=MSDN
- https://programminghistorian.org/es/lecciones/transformacion-datos-xml-xsl
- https://www.mclibre.org/consultar/xml/lecciones/xml-xslt.html
- https://www.data2type.de/es/xml-xslt-xslfo/xslt/referencia-xslt1#xsl%3Atemplate
- https://www.w3schools.com/xml/xsl_intro.asp
- https://www.w3schools.com/xml/xml_xslt.asp
- https://www.mclibre.org/consultar/xml/otros/xmlcopyeditor.html