XSLT Mini COMO
Versión: 1.0
Ultima actualización: 25-03-2002
Autor: Ibon Urretavizcaya
Indice
|
|
|
'XSLT Mini COMO' bajo licencia FDL v1.1 o superior
|
FDL
|
Copyright (c) 2002 Ibon Urretavizcaya. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts and with no Back-Cover Texts. A copy of the license is included in the previous link.
|
La información que hay en internet sobre XML y las aplicaciones que surgen sobre ella se están multiplicando rápidamente, pero para estar al día hay que doblegarse ante el inglés. Así que trataré de que este documento explique de forma clara y sencilla que es lo que a día de hoy XSLT ofrece.
Este mini como parte con un enfoque muy general del XML y profundiza rápidamente hacia los detalles del XSLT. Por ello recomiendo hacer una primera lectura rápida del mismo para comprender la estructura general, para más adelante estudiar las zonas de mayor interés para el lector. También pretendo que sirva como una guia de consulta rápida y para ese fin el índice enlaza con todas las tablas del documento.
Lo primero que crea confusión al aprender XML es la cantidad de acrónimos que existen, vamos a tratar de sentar unas bases firmes en las que poder apoyar tanta sucesión de siglas.
Bien XML es, dejándonos de tecnicismos, un estándar que ha gustado mucho a la comunidad de desarrolladores y ha generado en tiempo récord innumerables herramientas basadas en este estándar. XML no es más que una forma ordenada de escribir un archivo de texto y tomando esto como base podemos utilizar las nuevas herramientas que se han desarrollado para poder maximizar la productividad del contenido que hemos ordenado.
Y una vez definida la base empecemos a enumerar que acrónimos existen a su alrededor, voy a agruparlos en 5 grupos: evolución, extensiones, herramientas, esquemas y formatos.
La "evolución" agrupa aquellos acrónimos que son los pasos previos del XML y algunos cambios posteriores a su primera definición.
Evolución
|
SGML
|
Estandard ISO.
|
|
XML
|
Recomendación de W3C.
|
|
MinXML
|
(Minimal XML) simplificación de la comunidad web.
|
|
Canonical XML
|
Recomendación de W3C. Simplificación de XML.
|
Las "extensiones" son ampliaciones comúnmente utilizadas de las características propias del XML.
Extensiones
|
Namespaces
|
Permite mezclar lenguajes XML.
|
|
XInclude
|
Permite combinar diferentes lenguajes XML.
|
|
XML Base
|
Resuelve URIs relativas.
|
Las "herramientas" agruparían aquellas aplicaciones cuyo objetivo es facilitar y potenciar el trabajo con archivos XML. Cada una se especializa en un campo y algunas se apoyan en otras para poder crear cada vez herramientas más especializadas.
Herramientas
|
XPath
|
Para navegar por la estructura XML.
|
|
XPointer
|
(XML Pointer Language) Para definir puntos exactos o rangos de la estructura XML.
|
|
XLink
|
(XML Linking Language) utiliza XPointer y XPath. Para enlazar contenidos.
|
|
XQuery
|
utiliza XPath y los tipos de datos definidos en XML Schema. Para extraer información como si de una base de datos se tratara.
|
|
XSLT
|
(XSL Transformations) utiliza XPath. Para transformaciones de archivos XML en otros archivos de texto.
|
|
XSL-FO
|
(XSL Formatting Objects) Para un control exacto y detallado de la apariencia.
|
|
XML Information Set
|
Definición de terminología común XML.
|
|
XML Signature
|
Firma Digital de recursos web.
|
|
XML Encryption
|
Encriptación de recursos web.
|
|
XML Fragment Interchange
|
Para trabajar con fragmentos XML.
|
|
XML Protocol
|
Define protocolos de intercambio de información
|
|
SOAP
|
(Simple Object Access Protocol).
|
|
XForms
|
Formularios para inserción de datos.
|
|
RDF
|
(Resource Description Framework) Definición de meta-información.
|
|
DOM
|
(Document Object Model) para procesar código XML basado en la estructura.
|
|
SAX
|
(Standard API for XML) para procesar código XML basado en eventos.
|
Los "esquemas" son un caso especial de "herramientas", todas ellas tienen como objetivo definir que estructura debe de cumplir un archivo XML para ser válido. Existe una gran diversidad de esquemas y por ello he definido un grupo a parte. La variedad de esquemas se debe a que ninguno es "el mejor" y posiblemente no pueda existir un esquema perfecto para todas las necesidades, así que por ahora cada cual tiene su favorito en función de las necesidades.
Esquemas
|
DTD
|
(Document Type Definition) de W3C.
|
|
XML-DATA
|
de W3C.
|
|
DCD
|
(Document Content Description) de W3C.
|
|
DDML
|
(Document Definition Markup Language) de W3C.
|
|
SOX
|
(Schema for Object-oriented XML) de W3C.
|
|
XML Schema
|
de W3C.
|
|
Assertion Grammars
|
de Dave Raggett.
|
|
Schematron
|
de Rick Jellife.
|
|
Examplotron
|
de Eric van der Vlist.
|
|
TREX
|
(Tree Regular Expressions for XML) de James Clark.
|
|
RELAX
|
de Makoto Murara.
|
|
RELAX NG
|
de Makoto Murata y James Clark (unión de los dos anteriores).
|
|
DSD
|
(Document Structure Description) de BRICS y AT&T.
|
Si yo (con la carga subjetiva que ello conlleva) tuviese que destacar 3 esquemas elegiría: DTD, XML Schema y Relax NG.
DTD tiene su lugar garantizado porque ha sido utilizado durante mucho tiempo junto con el SGML, esta más orientado a contenido texto y por ello su soporte de tipos de datos es muy limitado, otra pega es que tiene su propia sintaxis que hay que aprender.
XML Schema resuelve los anteriormente citados inconvenientes del DTD, pero debido a su excesiva complejidad no ha terminado de convencer.
Relax NG es la evolución de los XML DTDs: sigue una definición de tipo gramática, es una aplicación XML, no necesita ser definido en el archivo XML origen, permite trabajar con tipos de datos, incluso importar tipos de forma sencilla, etc.
Los "formatos" agruparían aquellas aplicaciones XML cuyo objetivo es guardar un tipo de contenido, es al fin y al cabo un formato de archivo que aprovecha las ventajas del XML. Cada vez más programas utilizan el formato XML para guardar datos de configuración de la aplicación o incluso su formato original es XML.
Formatos
|
XHTML
|
XMLización de HTML 4.0 de W3C.
|
|
CML
|
(Chemical Markup Language).
|
|
WML
|
(Wireless Markup Language) para servicios WAP.
|
|
ThML
|
(Theological Markup Language).
|
|
SVG
|
(Scalable Vector Graphics).
|
|
DIA
|
Formato original del programa.
|
|
Gnumeric
|
Formato original del programa.
|
Lo primero que debemos hacer es declarar que nos encontramos ante un archivo XML, para ello los cinco primeros caracteres del archivo deben ser: " <?xml ". Veamos que atributos puede tener, los opcionales están marcados en verde:
Declaración <?xml ... ?>
|
version
|
Versión XML necesaria para procesar el contenido. { 1.0 }
|
|
encoding
|
Define la codificación de texto utilizada. { UTF-8, ISO-8859-1, ISO-8859-15 }
|
|
standalone
|
Especifica si el archivo XML es autónomo o depende de un archivo DTD. { no, yes }
|
Voy a citar rápidamente las características básicas que un archivo XML debe cumplir para estar "bien formado". Si un archivo no esta "bien formado" al ser procesado dará un error y se detendrá el proceso.
Reglas básicas del XML
|
1 elemento root
|
Todo el documento XML debe estar contenido en un único elemento, al que llamaremos 'root'.
|
|
Elementos anidados
|
Todos los elementos deben contener elementos completos, es decir, deben contener tanto la etiqueta de apertura como la de cierre. Por tanto se debe respetar el orden inverso al de apertura a la hora de cerrarlos. { <elemento1>..<elemento2>..</elemento2>..</elemento1> }
|
|
Atributos entre comillas
|
Todos los atributos de los elementos deben tener su valor entre comillas. Pudiéndose elegir entre comillas simples o dobles. { <elemento atributo="valor"> = <elemento atributo='valor'> }
|
|
Mayúsculas y minúsculas
|
Las etiquetas en XML, a diferencia con el HTML, diferencian entre mayúsculas y minúsculas. Salvo que tengas una buena excusa utiliza solo minúsculas y cúrate en salud.
|
|
Cerrar elementos
|
Todos los elementos deben cerrarse con la etiqueta correspondiente. { <elemento>...</elemento> }
|
|
Elementos vacíos
|
Los elementos que no contengan nada pueden abrir y cerrarse con una única etiqueta. { <elemento/> }
|
Otra posible causa de errores de "mal formación" de archivos XML se debe a la utilización de símbolos reservados XML para fines diferentes a los que XML define. Para evitarlo deben ser sustituidos:
Símbolos reservados
|
<
|
<
|
|
&
|
&
|
|
>
|
>
|
|
"
|
"
|
|
'
|
'
|
Por último, citar que existen 2 atributos definidos por XML, los cuales pueden utilizarse en cualquier elemento:
Atributos XML
|
xmlns:*
|
Permite definir 'namespaces'. Es decir, definen prefijos que permiten diferenciar entre elementos con el mismo nombre.
|
|
xml:lang
|
Permite definir el idioma en el que esta el contenido. El idioma debe definirse con 2 letras según la ISO-639 y puede añadirsele un subcódigo de 2 letras del país según la ISO-3166. Por ejemplo: 'es-ES'. { ISO-639, ISO-3166 }
|
XML Path Language (XPath)
|
Versión 1.0
|
Recomendación W3C 16 Noviembre 1999 { versión explicada en este mini-como }
|
|
Versión 2.0
|
Boceto de trabajo W3C 20 Diciembre 2001
|
No es objeto de este mini como definir la sintaxis de XPath, pero como su utilización es ineludible voy a resumir sus puntos básicos, después con los ejemplos XSLT explicaré con mayor detalle cada punto. Téngase en cuenta que solo con un gran dominio sobre XPath es posible maximizar el rendimiento de XSLT.
XPath es un lenguaje no-XML que permite identificar partes de documentos XML. Para XPath un documento XML no es más que un árbol de nodos, existen 7 tipos de nodos:
Nodos
|
Nodo 'root'
|
Contiene al elemento 'root', es decir todo el documento. { / }
|
|
Nodos elemento
|
Contienen un elemento { * }
|
|
Nodos atributo
|
Contienen el atributo de un elemento. { @* }
|
|
Nodos texto
|
Contienen el texto entre las etiquetas de un elemento. { text() }
|
|
Nodos comentario
|
Contienen un comentario del autor. { comment() }
|
|
Nodos instrucción
|
Contienen instrucciones en otro lenguaje de programación. { processing-instruction() }
|
|
Nodos 'namespace'
|
Contiene la definición de un 'namespace'. { namespace() }
|
Existen 3 tipos de operadores que podemos utilizar: matemáticos, boléanos y de expresiones.
Operadores matemáticos
|
+
|
Suma.
|
|
-
|
Resta.
|
|
*
|
Multiplicación.
|
|
div
|
División.
|
|
mod
|
Resto de una división.
|
Operadores boléanos
|
=
|
Igual.
|
|
<
|
Menor.
|
|
<=
|
Menor o igual.
|
|
>
|
Mayor.
|
|
>=
|
Mayor o igual.
|
|
!=
|
Diferente.
|
|
and
|
Y.
|
|
or
|
O.
|
Operadores de expresiones.
|
/
|
Para bajar al nodo hijo.
|
|
//
|
Hace referencia a todos los nodos hijo del nodo actual.
|
|
.
|
Nodo actual. { node() }
|
|
..
|
Para subir al nodo padre.
|
|
@
|
Hace referencia a los nodos atributo del elemento actual.
|
|
|
|
Permite unir varias expresiones Xpath.
|
|
*
|
Permite seleccionar cualquier nodo sea cual sea su nombre.
|
|
[]
|
El predicado permite definir filtros que seleccionen los nodos que nos interesan.
|
|
$
|
Precede a un nombre de variable.
|
Hasta ahora hemos visto las expresiones más comunes para moverse por el árbol de nodos, las cuales son iguales a las utilizadas para moverte por el sistema de ficheros Unix. Pero existen más expresiones y para utilizarlas deberemos utilizar la sintaxis no abreviada, denominada también como ejes:
Ejes
|
child::*
|
El eje hijo contiene todos los nodos comentario, elemento, instrucción y texto hijos del nodo actual. { / }
|
|
parent::*
|
El eje padre contiene el nodo padre del nodo actual. { .. }
|
|
self::*
|
Este eje contiene el nodo actual. { . }
|
|
atributte::*
|
El eje atributo contiene todos los nodos atributo del nodo actual. { @ }
|
|
ancestor::*
|
El eje ancestro contiene el nodo padre, abuelo, bisabuelo, etc... del nodo actual hasta llegar al nodo 'root'. Este eje contiene el nodo 'root', salvo que el nodo actual sea el nodo 'root'.
|
|
ancestor-or-self::*
|
Este eje contiene el nodo actual y el nodo padre, abuelo, bisabuelo, etc... del nodo actual hasta llegar al nodo 'root'. Siempre incluye el nodo 'root'.
|
|
descendant::*
|
El eje descendientes contiene todos los nodos comentario, elemento, instrucción y texto hijos, nietos, bisnietos, etc... del nodo actual.
|
|
descendant-or-self::*
|
Este eje contiene el nodo actual y todos los nodos comentario, elemento, instrucción y texto hijos, nietos, bisnietos, etc... del nodo actual. { // }
|
|
preceding-sibling::*
|
Este eje contiene todos los nodos anteriores que comparten el mismo padre que el nodo actual. Si el nodo actual es un atributo o un 'namespace', al considerar que son nodos sin padre, este eje no contiene nada.
|
|
following-sibling::*
|
Este eje contiene todos los nodos posteriores que comparten el mismo padre que el nodo actual. Si el nodo actual es un atributo o un 'namespace', al considerar que son nodos sin padre, este eje no contiene nada.
|
|
preceding::*
|
Este eje contiene todos los nodos anteriores al nodo actual, excepto los nodos ancestro, atributo y 'namespace'.
|
|
following::*
|
Este eje contiene todos los nodos posteriores al nodo actual, excepto los nodos descendientes, atributo y 'namespace'.
|
|
namespace::*
|
Este eje contiene los nodos 'namespace' del nodo actual. Si el nodo actual no es un elemento este eje no contiene nada.
|
XPath, además de lo que hemos visto hasta ahora, define 27 funciones que facilitan mucho el trabajo. Vamos a agrupar las funciones en 4 grupos:
Funciones con nodos
|
position()
|
Devuelve el numero de posición del nodo actual. { elemento[position()=1] = elemento[1] }
|
|
last()
|
Devuelve el numero de posición del último nodo. { elemento[position()=last()] es el último }
|
|
count()
|
Devuelve el numero total de nodos. { count(//elemento) }
|
|
id()
|
Devuelve un conjunto de nodos que tengan ese identificador. El atributo con el identificador debe estar definido en el DTD como de tipo ID. { id('es'), id('es eu en pt jp') }
|
|
name()
|
Devuelve una cadena de caracteres con el nombre completo del elemento, incluyendo el prefijo 'namespace'. { name(elemento) es 'xsl:elemento' }
|
|
local-name()
|
Devuelve una cadena de caracteres con el nombre local del elemento, sin el prefijo 'namespace'. { local-name(elemento) es 'elemento' }
|
|
namespace-uri()
|
Devuelve una cadena de caracteres con la URI asociada al 'namespace' del elemento. { namespace-uri(elemento) es 'http://www.w3.org/1999/XSL/Transform' }
|
|
lang()
|
Devuelve verdadero o falso en función de que el código de idioma sea igual o no al atributo xml:lang más cercano del nodo actual. { si lang('es') es verdad esta en español }
|
Funciones con cadenas de caracteres
|
string()
|
Convierte cualquier objeto en una cadena de caracteres.
|
|
starts-with()
|
Devuelve verdadero o falso en función de que la primera cadena empiece o no con la segunda. { starts-with('abcd','a') es verdad, starts-with('abcd','b') es falso }
|
|
contains()
|
Devuelve verdadero o falso en función de que la primera cadena contenga o no la segunda. { contains('abcd','a') es verdad, contains('abcd','b') es verdad }
|
|
substring-before()
|
Devuelve la subcadena anterior a la segunda cadena encontrada en la primera cadena. { substring-before('es-ES','-') es 'es' }
|
|
substring-after()
|
Devuelve la subcadena posterior a la segunda cadena encontrada en la primera cadena. { substring-before('es-ES','-') es 'ES' }
|
|
substring()
|
Devuelve una subcadena de la primera cadena utilizando el primer numero como inicio y el segundo (si existe) como longitud. { substring('abcdef', 3, 2) es 'cd', substring('abcdef', 4) es 'def' }
|
|
string-length()
|
Devuelve un numero con la longitud de la cadena. { string-length('abcdef') es 6 }
|
|
normalize-space()
|
Elimina los espacios anteriores y posteriores de la cadena y sustituye las sucesiones de espacios por un solo espacio.
|
|
concat()
|
Devuelve una cadena concatenada de los objetos entre paréntesis.
|
|
translate()
|
Devuelve una cadena a la que tomando como origen la primera cadena se le ha sustituido la segunda cadena por la tercera. { translate('a-b-c','-','_') es 'a_b_c' }
|
Funciones boleanas
|
true()
|
Siempre devuelve verdadero.
|
|
false()
|
Siempre devuelve falso.
|
|
not()
|
Cambia el valor de verdadero a falso y de falso a verdadero.
|
|
boolean()
|
Convierte cualquier objeto en verdadero o falso.
|
Funciones numéricas
|
number()
|
Convierte cualquier objeto en un número.
|
|
round()
|
Redondea el valor entre paréntesis.
|
|
floor()
|
Redondea hacia abajo el valor entre paréntesis.
|
|
ceiling()
|
Redondea hacia arriba el valor entre paréntesis.
|
|
sum()
|
Suma el contenido.
|
XSL Transformations (XSLT)
|
Versión 1.0
|
Recomendación W3C 16 Noviembre 1999 { versión explicada en este mini-como }
|
|
Versión 2.0
|
Boceto de trabajo W3C 20 Diciembre 2001
|
XSLT es una aplicación que define un lenguaje para modificar archivos XML. Este lenguaje precisa definir que transformaciones se quieren hacer y a que partes del documento. Para lo primero el propio XSLT define unos elementos, pero para lo segundo XSLT se basa en la sintaxis que define XPath. Por lo tanto XSLT es un lenguaje que va a definir que transformaciones vamos a realizar y cada vez que precisemos seleccionar un elemento a modificar utilizaremos XPath.
XSLT al ser una aplicación XML, se escribe en archivos XML y debe seguir todas las reglas que ello implica. Tendremos a nuestra disposición los elementos y funciones que define XSLT, la sintaxis y funciones propias de XPath e incluso podremos utilizar otras aplicaciones como XLink y XPointer.
Para conseguir realizar la modificación deberemos escribir una hoja de estilo explicando, con la sintaxis apropiada, que queremos que el procesador XSLT haga con el archivo XML. La hoja de estilo tiene la extensión 'xsl' y una vez definida funcionará con cualquier procesador XSLT escrito en cualquier lenguaje y ejecutado en cualquier entorno.
Procesadores XSLT con licencia libre
|
Napa
|
Kevin Jones. { ??? }
|
|
Sablotron
|
Ginger Alliance. { C++, Perl, PHP, Python }
|
|
XML::XSLT
|
Geert Josten y Egon Willighagen. { Perl }
|
|
MDC-XSL
|
Minoru Development Corporation. { C++ }
|
|
Xalan
|
Apache XML Project. (LotusXSL de Alphaworks, IBM) { C++, Java, Python[Pyana] }
|
|
jd.xslt
|
Johannes Döbler. { Java }
|
|
SAXON
|
Michael H. Kay. { Java }
|
|
XT
|
James Clark. { Java }
|
|
Koala XSL Engine
|
INRIA. { Java }
|
|
XSL:P
|
Keith Visco. { Java [enlace-roto] }
|
|
4suite
|
Fourthought. { python }
|
|
Gnome libxslt library
|
Daniel Veillard. { C, perl[XML::LibXSLT] }
|
|
XSLTC
|
Olivier Gerardin. { C++ }
|
|
Unicorn XSLT Processor
|
Unicorn Enterprises. { C++ }
|
La gran ventaja del XSLT es la capacidad de transformar una única fuente de información en infinidad de formatos y de adaptar el contenido y la presentación para que se adapte a cualquier medio, ya sea visual, inalámbrico, físico, temporal, braille, etc... el límite lo pone la imaginación, o la necesidad.
Otra de las ventajas es que por fin permite separar el contenido de la presentación, pudiéndose modificar aspectos visuales fácilmente sin que los contenidos se vean mezclados en el proceso.
Permite reutilizar los datos contenidos en formato XML para otros fines diferentes al original.
XSLT puede utilizar las funciones de XPath y además define 10 funciones propias. Vamos a utilizar el mismo sistema de agrupación que hemos utilizado antes:
Funciones especiales
|
element-available()
|
Comprueba si un elemento esta disponible. Tiene utilidad a la hora de utilizar elementos extendidos.
|
|
function-available()
|
Comprueba si la función esta disponible. Tiene utilidad a la hora de utilizar funciones extendidas.
|
|
system-property()
|
Devuelve información sobre el procesador XSLT. { xsl:version, xsl:vendor, xsl:vendor-url }
|
|
unparsed-entity-uri()
|
Devuelve la URI de la entidad no comprobada.
|
Funciones con nodos
|
current()
|
Devuelve el nodo actual. Fuera del predicado es igual a '.' de XPath, pero dentro del predicado puede no serlo.
|
|
document()
|
Permite cargar el nodo 'root' de un documento XML.
|
|
generate-id()
|
Genera una cadena de caracteres para cada nodo. Un mismo nodo siempre obtiene la misma cadena durante una misma transformación.
|
|
key()
|
Lista el conjunto de nodos que pertenecen contienen cierta clave. Una función con mayores prestaciones que la función id() de XPath.
|
Funciones con cadenas de caracteres
|
format-number()
|
Convierte un numero a una cadena de caracteres siguiendo el patrón que se especifique. El patrón utiliza los valores definidos en el elemento 'xsl:decimal-format'.
|
Para la función 'format-number()' vamos a definir la simbología que podemos utilizar para definir el patrón:
Simbología del patrón de 'format-number()'
|
0
|
Un dígito, incluyendo los ceros a la izquierda y decimales. Definido en el atributo 'zero-digit' de 'xsl:decimal-format'.
|
|
#
|
Un dígito, sin incluir los ceros a la izquierda y decimales. Definido en el atributo 'digit' de 'xsl:decimal-format'.
|
|
.
|
Separador decimal. Definido en el atributo 'decimal-separator' de 'xsl:decimal-format'.
|
|
,
|
Separador de grupos (mil). Definido en el atributo 'grouping-separator' de 'xsl:decimal-format'.
|
|
;
|
Separador del patrón positivo y negativo. Definido en el atributo 'pattern-separator' de 'xsl:decimal-format'.
|
|
-
|
Símbolo negativo. Definido en el atributo 'minus-sign' de 'xsl:decimal-format'.
|
|
%
|
Divide entre 100 y muestra el símbolo de porcentaje. Definido en el atributo 'percent' de 'xsl:decimal-format'.
|
|
X
|
Indica cualquier carácter para prefijo o sufijo. Definido en el atributo 'prefix' o 'suffix' de 'xsl:decimal-format'.
|
|
'
|
Utilizado para proteger caracteres especiales en el prefijo o sufijo.
|
|
X*
|
Indica cero o más ocurrencias de X.
|
|
(X | Y)
|
Indica que X y Y son válidos.
|
|
X..Y
|
Indica cualquier carácter entre X y Y.
|
|
S - T
|
Indica que si caracteres en S, pero no en T. ???
|
A parte de estas funciones se pueden generar otras, llamadas funciones extendidas. Estas funciones pueden ahorrar mucho trabajo, pero debe saberse que se pierde compatibilidad de la hoja de estilo y posiblemente solo funcione en el procesador XSLT en el que fue desarrollada.
Antes de empezar con los elementos XSLT voy a hacer hincapié en los posibles contenidos de un atributo, que como ya sabemos tiene que estar entre comillas:
Entre comillas
|
<xsl:* atributo= 'texto' />
|
Expresión XPath que hace referencia al ELEMENTO 'texto'.
|
|
<xsl:* atributo= "texto" />
|
Igual al anterior.
|
|
<xsl:* atributo= '"texto"' />
|
El atributo toma como valor la PALABRA 'texto'.
|
|
<xsl:* atributo= "'texto'" />
|
Igual al anterior.
|
|
<xsl:* atributo= '@texto' />
|
Expresión XPath que hace referencia al ATRIBUTO 'texto'.
|
|
<xsl:* atributo= "@texto" />
|
Igual al anterior.
|
|
<xsl:* atributo= '"@texto"' />
|
El atributo toma como valor la PALABRA '@texto'.
|
|
<xsl:* atributo= "'@texto'" />
|
Igual al anterior.
|
|
<* atributo= '{@texto}' />
|
ATENCIÓN: Permite aplicar al atributo de un elemento cualquiera (NO xsl:*) el valor de un atributo directamente. Es muy útil.
|
|
<* atributo= "{@texto}" />
|
Igual al anterior.
|
La estructura básica de una hoja de estilo es la siguiente:
Hoja de estilo 11.1
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
...
</xsl:stylesheet>
|
El ejemplo 11.1 declara que nos encontramos ante un archivo XML y define un elemento root 'xsl:stylesheet' que contendrá toda la información sobre las transformaciones a realizar. El resto de la línea define el prefijo 'xsl' como el indicado para todos los elementos del lenguaje XSLT. En la siguiente tabla aparecen todos los atributos de este elemento, están señalados en verde los opcionales.
<xsl:stylesheet> = <xsl:transform>
|
version
|
Define que versión de XSLT necesita la hoja de estilo. { 1.0 }
|
|
xmlns:xsl
|
Define la URI para el 'namespace' XSL. { http://www.w3.org/1999/XSL/Transform }
|
|
xmlns:*
|
Define la URI para cualquier otro 'namespace'.
|
|
id
|
Define un identificador para la hoja de estilo.
|
|
extension-element-prefixes
|
Define los prefijos 'namespace' para llamar a elementos extendidos.
|
|
exclude-result-prefixes
|
Define que prefijos 'namespace' no deben ser enviados al resultado.
|
Los elementos 'top level' son los únicos que pueden ser hijos de 'xsl:stylesheet'. Para facilitar su aprendizaje voy a mostrar los 12 elementos agrupados en 4 grupos:
Definen el modelo
|
xsl:template
|
Contiene un modelo que será aplicado a los nodos que haya que transformar.
|
|
xsl:attribute-set
|
Define grupos de atributos que posteriormente serán aplicados a elementos. { Solo puede tener hijos 'xsl:attribute' }
|
|
xsl:import
|
Importa modelos de otras hojas de estilo dándoles una prioridad inferior a los modelos de la hoja actual. { Debe definirse al principio, Sin hijos }
|
|
xsl:include
|
Permite incluir modelos de otras hojas de estilo con igual prioridad que los modelos de la hoja actual. { Sin hijos }
|
Definen el formato del resultado
|
xsl:output
|
Define las características básicas del formato del resultado. { Sin hijos }
|
|
xsl:strip-space
|
Definen los elementos a los que se les va a quitar los espacios sobrantes. { Sin hijos }
|
|
xsl:preserve-space
|
Definen los elementos a los que no se les va a quitar los espacios sobrantes. { Sin hijos }
|
|
xsl:decimal-format
|
Permite definir el formato en el que los valores numéricos serán mostrados. Permite definir varios estilos por medio de nombres, sin nombre es el estilo por defecto. { Sin hijos }
|
Definen un seudo-lenguaje de programación
|
xsl:param
|
Define el nombre y valor de un parámetro. Esta diseñado para guardar un valor, pasarlo entre modelos, e incluso entre el procesador XSLT y la hoja de estilo. { Debe definirse al principio, Si es hijo de 'xsl:stylesheet' es global, En caso contrario es local }
|
|
xsl:variable
|
Define una función que devuelve un valor en función del contenido de la variable. { Si es hijo de 'xsl:stylesheet' es global, En caso contrario es local }
|
Definen características especiales
|
xsl:namespace-alias
|
Permite definir un alias para un 'namespace'. { Sin hijos }
|
|
xsl:key
|
Define una clave que facilita la posterior búsqueda de nodos mediante la función key(). { Sin hijos }
|
Ahora vamos a agrupar de igual modo los 21 elementos restantes que define XSLT:
Definen el modelo
|
xsl:value-of
|
Calcula el valor de una expresión XPath.
|
|
xsl:copy
|
Permite copiar un elemento, pero no copia ni sus atributos ni sus hijos.
|
|
xsl:copy-of
|
Permite copiar un elemento incluyendo sus atributos, sus hijos, nietos, etc. { Sin hijos }
|
|
xsl:apply-templates
|
Define los nodos a los que hay que aplicar los modelos apropiados. Puede definir también que parámetros se le deben pasar al modelo. { Solo puede tener hijos 'xsl:with-param' y 'xsl:sort' }
|
|
xsl:call-template
|
Permite llamar a un modelo en concreto por su nombre. Puede definir también que parámetros se le deben pasar al modelo. { Solo puede tener hijos 'xsl:with-param' }
|
|
xsl:element
|
Permite crear un elemento.
|
|
xsl:attribute
|
Permite añadir un atributo a un elemento. { Debe definirse al principio }
|
|
xsl:text
|
Permite escribir texto de forma literal en el archivo resultante.
|
|
xsl:comment
|
Permite crear comentarios en el archivo resultante. También permite generar definiciones CSS. { <!-- ... --> }
|
|
xsl:processing-instruction
|
Permite crear instrucciones en otros lenguajes de programación en el archivo resultante.
|
|
xsl:apply-imports
|
Permite aplicar modelos importados aumentando su prioridad. { Sin hijos }
|
Definen el formato del resultado
|
xsl:number
|
Permite contar elementos y mostrar la numeración en el formato deseado. También puede utilizarse para dar formato a valores numéricos. { Sin hijos }
|
|
xsl:sort
|
Ordena un conjunto de nodos. { Sin hijos, Debe ser hijo de 'xsl:apply-templates' o 'xsl:for-each' }
|
Definen un seudo-lenguaje de programación
|
xsl:if
|
Define una condición y solo si se cumple se procesará su contenido.
|
|
xsl:choose
|
Permite elegir entre varias situaciones definidas con 'xsl:when', en el caso de que no se cumpla ninguna elige el elemento 'xsl:otherwise'. { Solo puede tener hijos 'xsl:when' y 'xsl:otherwise' }
|
|
xsl:when
|
Define una condición dentro del elemento 'xsl:choose' y si es la primera en cumplirse se procesa su contenido. { Debe ser hijo de 'xsl:choose' }
|
|
xsl:otherwise
|
Define que procesar dentro del elemento 'xsl:choose' en el caso de que las condiciones de los elementos 'xsl:when' precedentes no se cumplan. { Debe ser hijo de 'xsl:choose', Debe definirse al final }
|
|
xsl:for-each
|
Recorre, de uno en uno, el conjunto de nodos a los que hace referencia. { Puede tener hijos 'xsl:sort' al principio }
|
|
xsl:with-param
|
Selecciona un parámetro que será pasado al modelo. { Debe ser hijo de 'xsl:apply-templates' o 'xsl:call-template' }
|
Definen características especiales
|
xsl:fallback
|
Define un modelo que será utilizado en el caso de que un elemento extendido no se encuentre disponible.
|
|
xsl:message
|
Permite mandar un mensaje a la salida de texto. Ayuda a localizar errores en las hojas de estilo.
|
Hasta ahora nos hemos limitado a citar de forma ordenada todas las herramientas que podemos utilizar, es hora de empezar a ver ejemplos. Cada vez que utilicemos un elemento nuevo explicaremos en una tabla todos sus posibles atributos, señalando los opcionales en verde. La hoja de estilo más sencilla que podemos definir contiene sólo el elemento 'xsl:stylesheet'.
Hoja de estilo 14.1
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
</xsl:stylesheet>
|
Para poder utilizar esta hoja de estilo necesitamos un archivo XML a transformar. Supongamos que el ejemplo 14.2 contiene el listado de obras de una biblioteca:
Documento XML 14.2
<?xml version="1.0"?>
<biblioteca nombre="Biblioteca Municipal">
<libro>Matemáticas</libro>
<libro>Historia</libro>
<revista>Ciencia</revista>
<revista>OVNI</revista>
</biblioteca>
|
Si procesamos el documento XML 14.2 con la hoja de estilo 14.1 obtenemos el documento resultante 14.3:
Documento resultante 14.3
<?xml version="1.0" encoding="UTF-8"?>
Matemáticas
Historia
Ciencia
OVNI
|
Con este ejemplo podemos ver que transformaciones por defecto realiza el procesador XSLT ante una hoja de estilo sin contenido: el documento resultante tiene una declaración XML con codificación UTF-8 y muestra el contenido de todas las etiquetas, pero no los nombres de la etiquetas ni sus atributos. Supongamos que el documento que queremos obtener sea un archivo mostrando como título el nombre de la biblioteca:
Hoja de estilo 14.4
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="biblioteca">
<xsl:value-of select="@nombre"/>
</xsl:template>
</xsl:stylesheet>
|
En la hoja de estilo 14.4 hemos definido un elemento 'xsl:template' el cual contiene un modelo que se limita a un elemento vacío 'xsl:value-of'. El elemento 'xsl:template' se aplicará a los elementos que se llamen 'biblioteca', es este caso el elemento 'root'. El elemento 'xsl:value-of' con el atributo 'select' esta seleccionando el atributo 'nombre' como el valor a mostrar. Veamos las tablas de ambos elementos:
<xsl:template>
|
match
|
Define con sintaxis XPath los nodos a los que se debe aplicar este modelo.
|
|
name
|
Define un nombre por el cual un elemento 'xsl:call-template' puede invocarlo.
|
|
mode
|
Define un nombre con el cual se pueden diferenciar varios modelos a aplicar sobre el mismo nodo.
|
|
priority
|
Define la prioridad con un número. Este atributo solo se tendrá en cuenta cuando varios modelos tengan la misma prioridad por defecto.
|
<xsl:value-of>
|
select
|
Define la expresión XPath que se debe evaluar y mostrar.
|
|
disable-output-escaping
|
Define si se debe deshabilitar la sustitución automática de símbolos reservados. Solo es aplicable si <xsl:output method='html'> o <xsl:output method='xml'>. { yes, no }
|
Si procesamos la nueva hoja de estilo obtendremos:
Documento resultante 14.5
<?xml version="1.0" encoding="UTF-8"?>Biblioteca Municipal
|
¿Que ha pasado?. Realmente el proceso ha salido bien, pero no esta el listado que esperábamos obtener. Las transformaciones que el procesador XSLT realiza por defecto afectan a elementos que no estén definidos en la hoja de estilo, al definir que se debe hacer con el elemento 'biblioteca' los elementos hijos ya no sufren las transformaciones por defecto, salvo que se defina explícitamente que el contenido del elemento 'biblioteca' debe aparecer:
Hoja de estilo 14.6
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="biblioteca">
<xsl:value-of select="@nombre"/>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
|
El contenido del elemento 'biblioteca' incluye todo el contenido entre las etiquetas, lo que incluye los hijos 'libro' y 'revista', el procesador transforma por defecto los elementos hijo mostrando su contenido:
Documento resultante 14.7
<?xml version="1.0" encoding="UTF-8"?>Biblioteca Municipal
Matemáticas
Historia
Ciencia
OVNI
|
Ahora supongamos que queremos obtener un archivo de texto plano, es decir sin la declaración XML:
Hoja de estilo 14.8
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="biblioteca">
<xsl:value-of select="@nombre"/>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
|
Hemos utilizado el elemento 'xsl:output' para definir que tipo de archivo resultante queremos. Este elemento es muy completo e iremos hablando de él a lo largo del mini como.
<xsl:output>
|
method
|
Define el tipo de documento resultante. { xml, html, text }
|
|
version
|
Define el valor del atributo 'version' de la declaración XML o HTML en el documento resultante. Solo es aplicable si method='html' o method='xml'.
|
|
encoding
|
Define el valor del atributo 'encoding' de la declaración XML en el documento resultante. Solo es aplicable si method='xml'. { UTF-8, ISO-8859-1, ISO-8859-15 }
|
|
omit-xml-declaration
|
Define si se debe omitir la declaración XML en el documento resultante. Solo es aplicable si method='xml'. { yes, no }
|
|
standalone
|
Define el valor del atributo 'standalone' de la declaración XML en el documento resultante. Solo es aplicable si method='xml'. { yes, no }
|
|
doctype-public
|
Define el valor del atributo 'PUBLIC' de la declaración DOCTYPE en el documento resultante. Solo es aplicable si method='html' o method='xml'.
|
|
doctype-system
|
Define el valor del atributo 'SYSTEM' de la declaración DOCTYPE en el documento resultante. Solo es aplicable si method='html' o method='xml'.
|
|
cdata-section-elements
|
Define un listado de elementos que deben ser escritos como secciones CDATA en el documento resultante. Solo es aplicable si method='xml'.
|
|
indent
|
Define si se debe hacer una sangría con las etiquetas en el documento resultante. Solo es aplicable si method='html' o method='xml'. { yes, no }
|
|
media-type
|
Define el tipo MIME del documento resultante. { text/xml, application/xml, text/html, text/xsl }
|
Con la hoja de estilo 14.8 obtenemos el listado que buscábamos:
Documento resultante 14.9
Biblioteca Municipal
Matemáticas
Historia
Ciencia
OVNI
|
En el anterior capítulo hemos visto como hacer unas simples transformaciones con unos pocos elementos, pero para obtener resultados más interesantes deberemos utilizar más elementos. Pero antes definamos un documento XML más completo:
Documento XML 15.1
<?xml version="1.0"?>
<biblioteca nombre="Biblioteca Municipal">
<datos>
<publicos>
<direccion>Calle Mayor, 54</direccion>
<telefono>111222333</telefono>
<fax>111222000</fax>
</publicos>
<privados>
<personal cargo="Oficial Administrativo">Don Pedro</personal>
<personal cargo="Técnico Superior de Biblioteca">Don Alberto</personal>
</privados>
</datos>
<documentos>
<libro paginas="1256">Matemáticas</libro>
<libro paginas="345">Historia</libro>
<revista paginas="54">Ciencia</revista>
<revista paginas="90">OVNI</revista>
</documentos>
</biblioteca>
|
En la próxima hoja de estilo vamos a definir varios modelos, de tal modo que unos llamen a otros y poder controlar mejor el resultado.
Hoja de estilo 15.2
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="biblioteca">
<xsl:value-of select="@nombre"/>.
<xsl:apply-templates select="documentos/*"/>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select="position()"/>. <xsl:value-of select="text()"/>.
</xsl:template>
</xsl:stylesheet>
|
En esta hoja de estilo hay dos modelos: el primero afecta al elemento 'biblioteca' y el segundo a todos los elementos. Por prioridad se procesa el modelo que afecta a 'biblioteca' primero y este con el elemento 'apply-templates' llama a cualquier modelo que afecte a los elementos hijo de 'documentos'.
<xsl:apply-templates>
|
select
|
Define una expresión XPath que selecciona los nodos a los que se debe aplicar los modelos. Si no se define se seleccionan todos los elementos hijos del nodo actual.
|
|
mode
|
Define un nombre con el cual sólo permite aplicar elementos 'xsl:template' cuyo atributo 'mode' sea igual.
|
Dentro de 'documentos' existen dos tipos de elementos 'libro' y 'revista', ambos serán procesados con el segundo modelo. Este segundo modelo obtiene la posición del elemento con la función XPath 'position()', escribe un punto y un espacio, muestra el contenido de texto del elemento con la función XPath 'text()' y escribe otro punto. De este modo obtenemos este listado:
Documento resultante 15.3
Biblioteca Municipal.
1. Matemáticas.
2. Historia.
3. Ciencia.
4. OVNI.
|
Hay otra forma de utilizar modelos y es llamándolos directamente. Vamos a utilizar esta forma para mostrar los datos de la biblioteca al principio del listado.
Hoja de estilo 15.4
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="biblioteca">
<xsl:call-template name="titulo"/>
<xsl:apply-templates select="documentos/*"/>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select="position()"/>. <xsl:value-of select="text()"/>.
</xsl:template>
<xsl:template name="titulo">
<xsl:value-of select="@nombre"/>.
Dirección: <xsl:value-of select="datos/publicos/direccion"/>.
Tlf: <xsl:value-of select="datos/publicos/telefono"/>.
Fax: <xsl:value-of select="datos/publicos/fax"/>.
</xsl:template>
</xsl:stylesheet>
|
Vemos que hemos creado un nuevo modelo, pero este tiene un nombre definido con el atributo 'name'. Cuando en la hoja de estilo aparezca un elemento 'xsl:call-template' con un atributo 'name' con el mismo nombre se procesará su contenido.
<xsl:call-template>
|
name
|
Define un nombre con el cual invoca al elemento 'xsl:template' cuyo atributo 'name' sea igual.
|
Este método permite mostrar un contenido concreto en un punto exacto, y simplemente con hacer otra llamada al mismo modelo podemos mostrar el mismo contenido en varias zonas del documento resultante pudiendo ahorrar mucho código.
Documento resultante 15.5
Biblioteca Municipal.
Dirección: Calle Mayor, 54.
Tlf: 111222333.
Fax: 111222000.
1. Matemáticas.
2. Historia.
3. Ciencia.
4. OVNI.
|
Añadamos un paréntesis a la lista especificando el número de páginas:
Hoja de estilo 15.6
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="biblioteca">
<xsl:call-template name="titulo"/>
<xsl:apply-templates select="documentos/*"/>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select="position()"/>. <xsl:value-of select="text()"/>.
(<xsl:value-of select="format-number(@paginas, '#,##0')"/> pags.)
</xsl:template>
<xsl:template name="titulo">
<xsl:value-of select="@nombre"/>.
Dirección: <xsl:value-of select="datos/publicos/direccion"/>.
Tlf: <xsl:value-of select="datos/publicos/telefono"/>.
Fax: <xsl:value-of select="datos/publicos/fax"/>.
</xsl:template>
</xsl:stylesheet>
|
Hemos añadido una función XSLT 'format-number()' para que nos coloque la puntuación necesaria si el número de paginas es superior a mil. Veamos el resultado:
Documento resultante 15.7
Biblioteca Municipal.
Dirección: Calle Mayor, 54.
Tlf: 111222333.
Fax: 111222000.
1. Matemáticas.
(1,256 pags.)
2. Historia.
(345 pags.)
3. Ciencia.
(54 pags.)
4. OVNI.
(90 pags.)
|
Lo ha hecho bien, pero siguiendo la puntuación anglosajona. Además sería más cómodo que el número de teléfono tuviese también algún tipo de formato. Para ello deberemos añadir lo siguiente:
Hoja de estilo 15.8
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:decimal-format grouping-separator="."/>
<xsl:decimal-format name="tel" grouping-separator="-"/>
<xsl:template match="biblioteca">
<xsl:call-template name="titulo"/>
<xsl:apply-templates select="documentos/*"/>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select="position()"/>. <xsl:value-of select="text()"/>.
(<xsl:value-of select="format-number(@paginas, '#.##0')"/> pags.)
</xsl:template>
<xsl:template name="titulo">
<xsl:value-of select="@nombre"/>.
Dirección: <xsl:value-of select="datos/publicos/direccion"/>.
Tlf: <xsl:value-of select="format-number(datos/publicos/telefono, '#-##0', 'tel')"/>.
Fax: <xsl:value-of select="format-number(datos/publicos/fax, '#-##0', 'tel')"/>.
</xsl:template>
</xsl:stylesheet>
|
En esta hoja de estilo aparecen dos elementos 'xsl:decimal-format', el primero no tiene atributo 'name' con lo cual se convierte en el formato por defecto. El segundo si tiene y sólo se aplicará cuando sea llamado expresamente. En la línea en la que se formatea el número de páginas sólo ha cambiado el patrón, sustituyendo la coma anglosajona por el punto. En las líneas en las que aparecen los números de teléfono se ha añadido la función 'format-number()' con un patrón distinto y utilizando el formato definido por el segundo elemento 'xsl:decimal-format'.
<xsl:decimal-format>
|
name
|
Define un nombre para el formato definido.
|
|
decimal-separator
|
Define el separador decimal. { . }
|
|
grouping-separator
|
Define el separador de grupos (mil). { , }
|
|
infinity
|
Define el símbolo a utilizar para representar infinito. { Infinity }
|
|
minus-sign
|
Define el signo negativo. { -, #x2D }
|
|
NaN
|
Define el símbolo a utilizar cuando el valor no es un número. { NaN }
|
|
percent
|
Define el símbolo a utilizar para representar porcentajes. { % }
|
|
per-mille
|
Define el símbolo a utilizar para representar unidades por millar. { #x2030 }
|
|
zero-digit
|
Define el símbolo a utilizar en el patrón para representar un dígito, incluyendo los ceros a la izquierda y decimales. { 0 }
|
|
digit
|
Define el símbolo a utilizar en el patrón para representar un dígito, sin incluir los ceros a la izquierda y decimales. { # }
|
|
pattern-separator
|
Define el símbolo a utilizar en el patrón para separar el subpatrón positivo del negativo. { ; }
|
Veamos el resultado de la transformación:
Documento resultante 15.9
Biblioteca Municipal.
Dirección: Calle Mayor, 54.
Tlf: 111-222-333.
Fax: 111-222-000.
1. Matemáticas.
(1.256 pags.)
2. Historia.
(345 pags.)
3. Ciencia.
(54 pags.)
4. OVNI.
(90 pags.)
|
Hasta ahora hemos visto como extraer y dar formato a cierta información contenida en un archivo XML y mostrarla en un documento de texto plano. Supongamos que se nos pide un documento XML, pero con ciertas modificaciones respecto al original (el mismo que hemos utilizado en el capítulo anterior).
Hoja de estilo 16.1
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="biblioteca">
<xsl:copy/>
</xsl:template>
</xsl:stylesheet>
|
Con esta hoja de estilo vamos a copiar el elemento 'biblioteca' utilizando el elemento 'xsl:copy'.
<xsl:copy>
|
use-attribute-sets
|
Define una lista de elementos 'attribute-set' que deben usarse por este elemento.
|
Veamos el resultado:
Documento resultante 16.2
<?xml version="1.0" encoding="UTF-8"?><biblioteca/>
|
Hemos obtenido un documento XML y hemos copiado el elemento 'biblioteca', pero no su contenido. Supongamos que queremos obtener una copia del documento original, pero sin los datos privados.
Hoja de estilo 16.3
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="biblioteca">
<xsl:copy>
<xsl:copy-of select="datos/publicos"/>
<xsl:copy-of select="documentos"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
|
Con esta hoja de estilo copiamos el elemento 'biblioteca' y dentro hacemos una copia completa de los elementos que nos interesan con el elemento 'xsl:copy-of'.
<xsl:copy-of>
|
select
|
Define una expresión XPath que selecciona que nodos deben copiarse al documento resultante.
|
Aquí tenemos el resultado:
Documento resultante 16.4
<?xml version="1.0" encoding="UTF-8"?><biblioteca><publicos>
<direccion>Calle Mayor, 54</direccion>
<telefono>111222333</telefono>
<fax>111222000</fax>
</publicos><documentos>
<libro paginas="1256">Matemáticas</libro>
<libro paginas="345">Historia</libro>
<revista paginas="54">Ciencia</revista>
<revista paginas="90">OVNI</revista>
</documentos></biblioteca>
|
Hemos obtenido la copia, pero hay dos pegas. La primera es que la copia no es tan clara como el original (una etiqueta por línea), pero como nos encontramos ante un documento XML esto no influye en absoluto. La segunda es que el elemento 'datos' no se ha copiado. Una posible solución a ambas pegas sería:
Hoja de estilo 16.5
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="biblioteca">
<xsl:copy>
<xsl:element name="datos">
<xsl:copy-of select="datos/publicos"/>
</xsl:element>
<xsl:copy-of select="documentos"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
|
<xsl:element>
|
name
|
Define el nombre de este elemento.
|
|
namespace
|
Define la URI del 'namespace' de este elemento.
|
|
use-attribute-sets
|
Define una lista de elementos 'attribute-set' que deben usarse por este elemento.
|
Veamos el nuevo resultado:
Documento resultante 16.6
<?xml version="1.0" encoding="UTF-8"?>
<biblioteca>
<datos>
<publicos>
<direccion>Calle Mayor, 54</direccion>
<telefono>111222333</telefono>
<fax>111222000</fax>
</publicos>
</datos>
<documentos>
<libro paginas="1256">Matemáticas</libro>
<libro paginas="345">Historia</libro>
<revista paginas="54">Ciencia</revista>
<revista paginas="90">OVNI</revista>
</documentos>
</biblioteca>
|
Ya hemos solucionado las dos pegas anteriores, pero ahora que se ve claro nos damos cuenta de que al elemento 'biblioteca' le falta el atributo 'nombre'. Y además deberíamos avisar de que este documento es una copia y que en poco tiempo estará desactualizado.
Hoja de estilo 16.7
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="biblioteca">
<xsl:copy>
<xsl:attribute name="nombre">
<xsl:value-of select="@nombre"/>
<xsl:text> (Listado de 29-2-2002)</xsl:text>
</xsl:attribute>
<xsl:element name="datos">
<xsl:copy-of select="datos/publicos"/>
</xsl:element>
<xsl:comment>Atención!!! Listado de 29-2-2002</xsl:comment>
<xsl:copy-of select="documentos"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
|
Para añadir el atributo con el nombre de la biblioteca utilizamos el elemento 'xsl:attribute' y en su interior obtenemos con 'xsl:value-of' el nombre y le añadimos información extra con el elemento 'xsl:text'. Hasta ahora hemos añadido texto directamente a la hoja, pero para tener mayor control es preferible incluirlo dentro de un elemento 'xsl:text'. Por ultimo, hemos añadido una comentario con el elemento 'xsl:comment'.
<xsl:attribute>
|
name
|
Define el nombre de este atributo.
|
|
namespace
|
Define la URI del 'namespace' de este atributo.
|
<xsl:text>
|
disable-output-escaping
|
Define si se debe deshabilitar la sustitución automática de símbolos reservados. Solo es aplicable si <xsl:output method='html'> o <xsl:output method='xml'>. { yes, no }
|
<xsl:comment>
|
SIN ATRIBUTOS
|
Veamos el resultado final:
Documento resultante 16.8
<?xml version="1.0" encoding="UTF-8"?>
<biblioteca nombre="Biblioteca Municipal (Listado de 29-2-2002)">
<datos>
<publicos>
<direccion>Calle Mayor, 54</direccion>
<telefono>111222333</telefono>
<fax>111222000</fax>
</publicos>
</datos>
<!--Atención!!! Listado de 29-2-2002-->
<documentos>
<libro paginas="1256">Matemáticas</libro>
<libro paginas="345">Historia</libro>
<revista paginas="54">Ciencia</revista>
<revista paginas="90">OVNI</revista>
</documentos>
</biblioteca>
|
El último elemento de este capítulo es 'xsl:processing-instruction' el cual simplemente define un nombre y un contenido, y los muestra una vez transformado entre '<? ... ?>'.
<xsl:processing-instruction>
|
name
|
Define el nombre de esta instrucción.
|
En este capítulo vamos a definir elementos que nos permitan definir condiciones y que hacer en cada caso. Vamos a definir un documento XML que contiene los datos de préstamo de los libros:
Documento XML 17.1
<?xml version="1.0"?>
<prestamo hoy="10-03-2002">
<usuario u_id="u00432">
<prestado fecha="09-03-2002" doc_id="doc00123"/>
<prestado fecha="10-03-2002" doc_id="doc01007"/>
</usuario>
<usuario u_id="u03406">
<prestado fecha="02-03-2002" doc_id="doc00978"/>
</usuario>
<restaurador r_id="r00004">
<prestado fecha="01-03-2002" doc_id="doc00101"/>
<prestado fecha="03-03-2002" doc_id="doc00775"/>
<prestado fecha="03-03-2002" doc_id="doc00067"/>
</restaurador>
</prestamo>
|
Supongamos que queremos que el bibliotecario tenga acceso a estos datos vía pagina html (voy a dar por supuesto un conocimiento básico de las etiquetas HTML) y que le señale los prestamos que han superado el periodo máximo (7 días).
Hoja de estilo 17.2
<?xml version="1.0" encoding="ISO-8859-15"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="ISO-8859-15"/>
<xsl:template match="prestamo">
<html>
<head><title>Listado de Préstamo</title></head>
<body>
<h2>Listado de Préstamo</h2>
<ul>
<xsl:apply-templates select="*/prestado"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="prestado">
<li>
<xsl:value-of select="@doc_id"/>
<xsl:text> lleva </xsl:text>
<xsl:value-of select="substring-before(/prestamo/@hoy,'-')-substring-before(@fecha,'-')"/>
<xsl:text> días prestado.</xsl:text>
<xsl:if test="substring-before(/prestamo/@hoy,'-')-substring-before(@fecha,'-')>7">
<xsl:text> [Multa]</xsl:text>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
|
Lo primero que hemos hecho ha sido elegir la codificación 'ISO-8859-15' para no tener problemas con las tildes de nuestro idioma. También hemos definido el documento resultantes como HTML y con la misma codificación. El resto del modelo nos debería resultar familiar, quizás nos asuste un poco "substring-before(/prestamo/@hoy,'-')-substring-before(@fecha,'-')", que simplemente calcula los días que el documento lleva prestado. La función 'substring-before()' selecciona la subcadena anterior a '-', es decir el día. Y lo que hacemos es restar el día del atributo 'hoy' con el día del atributo 'fecha'. Señalar que hemos simplificado el problema asumiendo que el mes y el año son iguales.
La novedad de esta hoja de estilo está en el elemento 'xsl:if' que define una condición en su atributo 'test' y solo cuando se cumple se procesa su contenido. La condición es que lleve más de 7 días prestado, téngase en cuenta que para representar el signo '>' hemos tenido que substituirlo por '>'.
<xsl:if>
|
test
|
Define una condición, si se cumple se procesará el interior del elemento.
|
Veamos el resultado:
Documento resultante 17.3
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-15">
<title>Listado de Préstamo</title>
</head>
<body>
<h2>Listado de Préstamo</h2>
<ul>
<li>doc00123 lleva 1 días prestado.</li>
<li>doc01007 lleva 0 días prestado.</li>
<li>doc00978 lleva 8 días prestado. [Multa]</li>
<li>doc00101 lleva 9 días prestado. [Multa]</li>
<li>doc00775 lleva 7 días prestado.</li>
<li>doc00067 lleva 7 días prestado.</li>
</ul>
</body>
</html>
|
El listado es correcto, pero hay que definir casos especiales para cuando los días sean 0 y 1. Además 'doc00101' esta prestado a un restaurador, ellos no tienen límite de tiempo y no tiene sentido ponerle una multa.
Hoja de estilo 17.4
<?xml version="1.0" encoding="ISO-8859-15"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="ISO-8859-15"/>
<xsl:template match="prestamo">
<html>
<head><title>Listado de Préstamo</title></head>
<body>
<h2>Listado de Préstamo</h2>
<ul>
<xsl:apply-templates select="*/prestado"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="prestado">
<li>
<xsl:value-of select="@doc_id"/>
<xsl:choose>
<xsl:when test="name(..)='restaurador'">
<xsl:text> está en restauración.</xsl:text>
</xsl:when>
<xsl:when test="substring-before(/prestamo/@hoy,'-')-substring-before(@fecha,'-')=0">
<xsl:text> se ha prestado hoy.</xsl:text>
</xsl:when>
<xsl:when test="substring-before(/prestamo/@hoy,'-')-substring-before(@fecha,'-')=1">
<xsl:text> lleva 1 día prestado.</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text> lleva </xsl:text>
<xsl:value-of select="substring-before(/prestamo/@hoy,'-')-substring-before(@fecha,'-')"/>
<xsl:text> días prestado.</xsl:text>
<xsl:if test="substring-before(/prestamo/@hoy,'-')-substring-before(@fecha,'-')>7">
<xsl:text> [Multa]</xsl:text>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</li>
</xsl:template>
</xsl:stylesheet>
|
Para definir todos los casos hemos utilizado el elemento 'xsl:choose' que