Dado que los documentos de los clientes de la empresa están en formato XML, Juan les plantea una nueva posibilidad para su página web. Dar la posibilidad a los clientes de consultar sus datos en la empresa a través de su página web.
Aunque a Félix y a María no les parece una idea muy seductora inicialmente, debido a que no consideran que el formato de los documentos XML sea el más atractivo para los clientes de la misma, deciden pedir consejo.
Una vez más, Juan les explica que mediante un sistema XSL se pueden transformar y formatear los contenidos almacenados en documentos XML. Se podrían presentar los datos en distintos formatos como XHTML, HTML o incluso PDF.
Félix escucha atentamente las explicaciones de Juan sobre las posibilidades que da la transformación de documentos.
Gracias a ellas acaba de pensar que, inicialmente se permitirá a los clientes consultar los datos a través de la web de la empresa, pero que en un futuro también puede servirles para generar informes en formato PDF, que pueden utilizar para la comunicaciones con sus clientes, bien a través del correo ordinario o del electrónico.
José Antonio Molina Bautista. Transformaciones XSL(GNU/GPL)
Extensible Stylesheet Language (XSL) es un lenguaje que interpreta hojas de estilo. Una hoja de estilo XSL describen cómo se debe mostrar un documento XML, algo parecido a lo que hace un archivo CSS (Cascading Style Sheets) con un archivo HTML.
La especificación XSL define unas características y una sintaxis que se agrupan en tres partes:
XSL Transformation Language (XSLT: Un lenguaje para la transformación de documentos XML.
XML Path Language (XPath): Un lenguaje de consulta de elementos en un documento XML.
XSL Formatting Object (XSL-FO): Un vocabulario XML para especificar la semántica del formato, es decir, indicar dónde debe aparecer cada elemento, con qué espaciado, con qué colores, con qué tipo de letra, ...
Para realizar las transformaciones se utilizan unos programas llamados procesadores XSL o parser XSL. A estos programas se les debe indicar los archivos de entrada XML y XSL. Una vez procesados si no tienen errores se generará el archivo deseado en el formato indicado por las instrucciones XSL.
XSLT fue diseñado para realizar transformaciones usando el vocabulario XML especificado por XSL-FO pero también para usarse con independencia de XSL y dicho vocabulario.
A nivel académico podemos realizar transformaciones de documentos XML a documentos HTML u otros XML de estructura diferente sin usar XSL-FO. En esta unidad usaremos XSLT y XPath de esta forma para evitar toda la complejidad añadida.
María empieza a convencerse de que el proyecto puede suponer una ventaja al permitir exponer la información de la empresa en múltiples formatos. Juan le dice que en lo que a intercambio de información se refiere si es así.
Su pregunta ahora es, ¿de qué modo van a lograr seleccionar partes de la información que tienen en sus extensos archivos XML? ¿cada cliente solamente querrá ver la información que le corresponde?
Juan les explica que para eso existe un lenguaje llamado XPath, cuya sintaxis se asemeja a la que se usa para desplazarse a través de un árbol de directorios pero añadiéndole condiciones y funciones extras.
XML Path Language (XPath) es un lenguaje de consulta de elementos en un documento XML. Diseñado inicialmente para ser usado con XSLT (eXtensible Stylesheet Language for Transformations) y XPointer (XML Pointer Language). En versiones posteriores también es usado por XQuery como veremos en próximas unidades.
El consorcio W3C (The World Wide Web Consortium) aprobó su primera versión XPath 1.0 en noviembre de 1999. XPath usa una sintaxis compacta y sin etiquetas por lo que no se asemeja a XML. Su nombre surge por el uso de las rutas en la navegación a través de estructuras jerárquicas dentro de los documentos XML.
XPath modela los documentos XML en árboles de nodos.
Un árbol es una estructura abstracta muy usada en informática que representa una serie de elementos (nodos) unidos por líneas (vértices). Además entre dos nodos cualesquiera sólo existe un único camino y ninguno de los caminos forma un bucle.
El nombre de esta estructura le viene porque tiene forma de copa de árbol invertida. Partiendo de un nodo raíz van añadiéndose ramas que contienen nodos hijos. A los nodos que tiene al menos un nodo hijo se le llama nodo padre. A los nodos que no tienen nodos hijos se les llama nodos hoja. Los los nodos que comparten padre se les llaman nodos hermanos.
En XPath existen distintos tipos de nodos que recogen los distintos tipos de información de los documentos XML. Los siete distintos tipos de nodos que podemos tener serán utilizadas posteriormente como 'selectores de nodos' en los 'pasos de localización'.
Los tipos de nodos son los siguientes:
Nodo raíz: Es el primer nodo del árbol, es único y el único que no tiene padre. No confundir el nodo raíz con el elemento raíz del documento XML. El nodo raíz tiene como hijos al elemento raíz y en su caso los comentarios y las instrucciones de procesamiento que formen el prólogo del documento XML.
Nodo elemento: Hay un nodo elemento por cada elemento XML del documento. Todos los nodos elemento tiene un sólo padre que puede ser otro nodo elemento o el nodo raíz. Los nodos elemento pueden tener un identificador único (ID). Para ser así debe estar declarado de tipo ID en su DTD o en el XML Schema asociado.
Nodo atributo: Los atributos de un documento XML se almacenan en nodos atributo. Un nodo atributo estará asociado a un único nodo elemento que será el padre de este. Pero desde el punto de vista del nodo elemento no se considerará a sus atributos como nodos hijos. Los nodos atributo son nodos hoja, es decir, no pueden tener nodos hijos.
Nodo texto (o contenido): Los valores alfanuméricos de los contenidos de los elementos de un documento XML serán almacenados en nodos texto. Los nodos texto son nodos hoja, es decir, no pueden tener nodos hijos. Nótese que los valores de los atributos no se almacenan en nodos texto sino en los propios identificadores de dichos nodos.
Nodo comentario: Los comentarios de un documento XML son almacenados en nodos comentario. El nodo almacenará el contenido del comentario sin incluir el inicio .
Nodo espacio de nombres: Cada nodo elemento puede tener un conjunto asociado de nodos espacio de nombres, uno para cada uno de los distintos prefijos de espacio de nombres incluyendo si es el caso el espacio de nombres por defecto. Tienen un funcionamiento parecido a los atributos. Un nodo espacio de nombres tiene un único nodo elemento como padre. Pero desde el punto de vista del nodo elemento no son considerados como nodos hijos de este. Los nodos espacio de nombres son nodos hoja, es decir, no pueden tener nodos hijos.
Nodo instrucción de procesamiento: Hay un nodo instrucción de procesamiento para cada instrucción de procesamiento. No incluye la terminación ?>.
Además se establece un orden entre los nodos que se corresponde con el orden en el que están escritos en el documento. De modo que el nodo raíz será el primer nodo. Los nodos elemento aparecerán antes de sus hijos. Por tanto, el orden del documento ordena los nodos elemento en el orden de aparición de sus etiquetas de apertura en el documento XML (tras la expansión de entidades). Los nodos atributo y los nodos espacio de nombres de un elemento aparecen antes que los hijos del elemento. Los nodos espacio de nombres aparecen por definición antes que los nodos atributo.
El nodo raíz y los nodos elemento tienen una lista ordenada de nodos hijo. Los nodos nunca comparten hijos, es decir, cada nodo tiene un único padre excepto el nodo raíz que no tiene padre.
En la ejemplo anterior de un documento XML que almacena una agenda podemos ver el árbol de nodos que crea la aplicación BaseX. Podemos observar a la izquierda el documento XML y a la derecha el árbol creado. Esta aplicación no resalta los distintos tipos de nodos de ninguna forma especial todos los muestra con su identificador.
El nodo raíz está indicado con el nombre del documento XML: arbol_nodos_ejemplo.xml. Nótese que no se corresponde con el elemento raíz que en este caso sería 'agenda'. Es importante no confundir nodo raíz y elemento raíz. El primero se refiere al árbol de nodos y el segundo al documento XML.
Los nodos elementos son los más abundantes: agenda, contacto, nombre y teléfono.
Los nodos texto o contenido son los contenidos de los elementos nombre y teléfono es decir: José, 600102030, Pizzería Roma y 600302010. Estos nodos siempre serán nodos hoja. Es decir, que no tendrán nodos hijos. Nótese que los valores que toman los atributos no se recogen en nodos texto sino que aparecen junto al identificador del atributo.
Los nodos atributos que recogen el identificador y el valor. En nuestro ejemplo: tipo="personal" y tipo="empresa"
También podemos ver en nuestro ejemplo dos nodos comentarios uno al inicio y otro dentro del segundo elemento contacto: Ejemplo de agenda y añadir dirección web.
descendant: contiene los descendientes del nodo contexto; un descendiente es un hijo o el hijo de un hijo, etc; de este modo descendant nunca contiene nodos atributo o espacio de nombres
José Antonio Molina Bautista. Eje descendant(GNU/GPL)
descendant-or-self: contiene el nodo contexto y sus descendientes.
José Antonio Molina Bautista. Eje descendant or self(GNU/GPL)
parent: contiene el padre del nodo contexto, si lo hay.
ancestor: contiene los ancestros del nodo contexto; los ancestros del nodo contexto consisten en el padre del nodo contexto y el padre del padre, etc; así, ancestor siempre incluirá al nodo raíz, salvo que el nodo contexto sea el nodo raíz.
José Antonio Molina Bautista. Eje ancestor(GNU/GPL)
ancestor-or-self: contiene el nodo contexto y sus ancestros; así, ancestor-or-self siempre incluirá el nodo raíz.
José Antonio Molina Bautista. Eje ancestor or self(GNU/GPL)
preceding: contiene todos los nodos del mismo documento que el nodo contexto que están antes de este según el orden del documento, excluyendo los ancestros y excluyendo nodos atributo y nodos espacio de nombres.
José Antonio Molina Bautista. Eje preceding(GNU/GPL)
preceding-sibling: contiene todos los hermanos precedentes del nodo contexto; si el nodo contexto es un nodo atributo o un nodo espacio de nombres, el eje preceding-sibling está vacío.
José Antonio Molina Bautista. Eje preceding-sibling(GNU/GPL)
following: contiene todos los nodos del mismo documento que el nodo contexto que están después de este según el orden del documento, excluyendo los descendientes y excluyendo nodos atributo y nodos espacio de nombres.
José Antonio Molina Bautista. Eje following(GNU/GPL)
following-sibling: contiene todos los siguientes hermanos del nodo contexto; si el nodo contexto es un nodo atributo o un nodo espacio de nombres, el eje following-sibling está vacío.
José Antonio Molina Bautista. Eje following-sibling(GNU/GPL)
Por simplificar el gráfico no se han incluido nodos atributos ni nodos de espacios de nombre. Las relaciones con esos nodos son las siguiente:
attribute: contiene los atributos del nodo contexto. Esta relación será vacía si el nodo contexto no es un nodo elemento ya que es el único que puede tener nodos atributo.
namespace: contiene los nodos espacio de nombres del nodo contexto. Esta relación será vacía si el nodo contexto no es un nodo elemento ya que es el único que puede tener nodos espacio de nombres.
José Antonio Molina Bautista. Árbol jerárquico(GNU/GPL)
La sintaxis de XPath no usa etiquetas por lo que no se asemeja a XML. Como su utilidad es realizar búsquedas en un árbol de nodos se utiliza una sintaxis parecida a la que se usa en los árboles de directorios y archivos de los sistemas operativos.
Un ejemplo de expresión XPath puede ser el siguiente 'camino de localización' (location paths):
Aunque se suele utilizar, siempre que se puede, su versión simplificada. El ejemplo anterior quedaría de la siguiente forma.
Versión simplificada:
//curso[1]/grupo[2]/alumno[last()]/nombre/text()
Además en las expresiones XPath se pueden utilizar llamadas a funciones, operaciones matemáticas simples y operaciones lógicas.
Cuando un programa evalúa un camino de localización XPath devolverá el resultado en uno de los siguientes cuatro tipos básicos:
Conjunto de nodos (Node-Set): una colección desordenada de nodos sin duplicados. Nótese que este conjunto de nodos puede ser vacío y no contener ningún nodo o también contener un único nodo.
Utilizaremos este documento XML para desarrollar ejemplos. En él guardamos información de un colegio donde hay una estructura de /colegio/curso/grupo/alumno.
Documento colegio.xml (xml - 3.4 KB) utilizado en el ejemplo.
a) ¿Cómo localizamos al alumnado de la clase de 2 ESO A?
b) ¿Cómo localizamos a todas las alumnas llamadas Ana?
c) ¿Cómo se llama el/la alumno/a con la nota más alta?
Aunque los caminos de localización no son la construcción gramatical más general en el lenguaje XPath sí son la construcción más importante.
Todo camino de localización se puede expresar utilizando una sintaxis completa aunque algo extensa. Existen también ciertas abreviaturas sintácticas que permiten expresar los casos más frecuentes de forma más concisa.
A esta expresiones se le llama 'camino de localización' (location paths). Estos caminos están compuestos por trozos separados por barras (/). A estos trozos se les llama 'paso de localización'(location steps).
Cadapaso de localización, a su vez, está separado en dos partes por dos puntos dobles (::). A la primera parte se le conoce como 'eje' (axe) y a la segunda parte como 'selector de nodos' (node test).
José Antonio Molina Bautista. Camino de localización(GNU/GPL)
En algunospasos de localizaciónhay instrucciones entre corchetes [ ] después del selector de nodos. Estas instrucciones entre corchetes son 'predicados'.
Además en los caminos de localización se pueden utilizar llamadas a funciones, operaciones matemáticas simples y operaciones lógicas.
sum(//nota_media) div count(//nota_media)
substring(/child::colegio/child::comment(),12,4)
Los caminos de localización pueden ser relativos o absolutos:
Un camino de localización es absoluto si comienza por el nodo raíz. Esto se puede reconocer fácilmente ya que el camino de localización comenzará con una barra " / ".
Si no comienza por el nodo raíz será un camino de localización relativo, es decir relativo al nodo contexto que esté posicionado en un determinado lugar. En el siguiente ejemplo el nodo contexto estaría posicionado en un elemento grupo
child::grupo/attribute::*
Se puede usar el operador | (unión) para unir el resultado de dos caminos de localización que devuelvan conjuntos de nodos.
Estos caminos de localización pueden estar compuestos por uno o más pasos de localización. Cada paso de localización irá refinando la búsqueda de la información que deseemos localizar. Los pasos de localización están separados unos de otros por una barra (/).
José Antonio Molina Bautista. Paso de localización(GNU/GPL)
Un paso de localización tiene tres partes:
Un eje, que especifica la relación jerárquica entre los nodos seleccionados por el paso de localización y el nodo contextual,
Un selector de nodos o prueba de nodos, que especifica el tipo de nodo de los nodos seleccionados por el paso de localización
Cero o más predicados, que usan expresiones lógicas para refinar aún más el conjunto de nodos seleccionado por el paso de localización.
La sintaxis del paso de localización es el nombre de eje y el selector de nodos separados por dos puntos dobles, seguido de cero o más predicados, cada uno entre corchetes.
Por ejemplo, en el siguiente paso de localización:
child::<span>grupo[</span>position()=2]
child es el nombre del eje, <span>grupo</span> es la selector de nodos y <span>[</span>position()=2] es un predicado.
El conjunto de nodos seleccionado por un paso de localización es el que resulta de generar un conjunto de nodos inicial a partir del eje y el selector de nodos, y a continuación filtrar dicho conjunto por cada uno de los predicados sucesivamente. El conjunto de nodos final es el conjunto de nodos seleccionado por el paso de localización.
José Antonio Molina Bautista. Árbol de nodos(GNU/GPL)
Los ejes se corresponden con las relaciones entre nodos de un árbol de nodos que vimos en los apartados anteriores.
Estos trece ejes son:
self: nodo contexto.
child: hijos del nodo contexto.
descendant: descendientes del nodo contexto.
descendant-or-self: nodo contexto y sus descendientes
parent: padre.
ancestor: ancestros del nodo contexto.
ancestor-or-self: nodo contexto y sus ancestros.
preceding: nodos anteriores.
preceding-sibling: hermanos anteriores.
following: nodos posteriores
following-sibling: hemanos posteriores
attribute: atributos
namespace: espacio de nombres. En XPath 2.0 se dejó de utilizar.
Recordar que para seleccionar atributos o espacios de nombres hay que utilizar de forma explícita sus ejes correspondientes. Por ejemplo, el eje child de un nodo elemento no contendrá sus atributos ni sus espacios de nombres.
Los selectores de nodos utilizan los distintos tipos de nodos que vimos al estudiar los árboles de nodos. Cada eje tiene un tipo principal de nodos. Si un eje puede contener elementos, entonces el tipo principal de nodo es elemento; en otro caso, será el tipo de los nodos que el eje contiene. Así,
Para el eje attribute, el tipo de nodo principal son los atributos.
Para el eje namespace, el tipo de nodo principal son los espacios de nombres.
Para los demás ejes, el tipo de nodo principal son los elementos.
Los selectores de nodos son los siguientes:
Nombre cualificado: nombre del objeto que se está buscando.
Todos (*)
text()
comment()
processing-instruction()
node()
En versiones posteriores de XPath se añadieron los siguientes selectores:
Un selector de nodos que sea un nombre cualificado (QName) es cierto si los tipos de nodos se corresponden y tiene un identificador igual al especificado por el nombre cualificado. Por ejemplo,child::alumnoselecciona los elementosalumnohijos del nodo contexto; si el nodo contexto no tiene ningún hijoalumno, seleccionará un conjunto de nodos vacío. Otro ejemplo:attribute::nivelselecciona el atributoniveldel nodo contexto; si el nodo contexto no tiene atributonivel, seleccionará un conjunto de nodos vacío.
Un selector de nodos*es cierto para cualquier nodo del tipo principal de nodo. Por ejemplo,child::* seleccionará todo elemento hijo del nodo contexto yattribute::*seleccionará todos los atributos del nodo contexto.
El selector de nodostext()es cierto para cualquier nodo de texto. Por ejemplo,child::text()seleccionará los nodos de texto hijos del nodo contexto.
Análogamente, el selector de nodoscomment()es cierto para cualquier nodo comentario, y el selector de nodosprocessing-instruction()es cierto para cualquier instrucción de procesamiento. La pruebaprocessing-instruction() puede tener un argumento que sea literal; en este caso, será verdadera para cualquier instrucción de procesamiento que tenga un nombre igual al valor del literal.
Un selector de nodosnode()es cierto para cualquier nodo de cualquier tipo que sea.
Ejemplos:
Selector nombre cualificado: /descendant-or-self::alumno/child::nombre
La abreviatura más importante es que child::puede ser omitida en los pasos de localización. A efectos prácticos,childes el eje por defecto. Por ejemplo, un camino de localización/colegio/cursoes abreviatura dechild::colegio/child::curso.
Hay también una abreviatura para atributos: attribute:: puede abreviarse como @. Por ejemplo, un camino de localización grupo[@orden="A"] es abreviatura de child::grupo[attribute::orden="A"] y por tanto selecciona hijos grupo con un atributo orden con valor igual a A.
// es abreviatura de descendant-or-self::node() . Por ejemplo,//alumno es abreviatura de /descendant-or-self::node()/child::alumno y por tanto seleccionará cualquier elemento alumno en el documento; curso//alumno es abreviatura de child::curso/descendant-or-self::node()/child::alumno y por tanto seleccionará todos los descendientes alumno de hijos curso.
Un paso de localización.es abreviatura de<span> </span>self::node(). Esto es particularmente útil en conjunción con//. Por ejemplo, el camino de localización.//grupoes abreviatura de
y por tanto seleccionará todos los descendientes elementosgrupodel nodo contexto.
Análogamente, un paso de localización..es abreviatura deparent::node(). Por ejemplo,../apellidoses abreviatura deparent::node()/child::apellidosy por tanto seleccionará los hijosapellidosdel padre del nodo contexto.
En resumen:
Si se omite el eje: estamos usando el eje por defecto child.
@ : estamos usando el eje attribute.
// : paso de localización descendant-or-self::node().
.. : paso de localización parent::node().
. : paso de localización self::node().
Ejemplos:
descendant-or-self::node()/child::nota_media se abrevia en //nota_media
Un predicado filtra un conjunto de nodos con respecto a un eje y un selector de nodos para producir un nuevo conjunto de nodos. El resultado de la expresión contenida en el predicado será de tipo booleano. Los predicados se escriben dentro de unos corchetes. Un paso de localización puede tener cero, uno o más predicados en cascada. Si existen más de un predicado estos se comprobarán de izquierda a derecha.
Si estamos evaluando un valor numérico el predicado será cierto si el número es igual a la posición contextual y se convertirá en falso en otro caso. Así un camino de localización grupo[2] es equivalente a grupo[position()=2] .
Las operaciones que ponemos usar en los predicados son las siguientes:
Todas las implementaciones del lenguaje XPath 1.0 deben incluir las siguientes funciones que se podrán usar para evaluar expresiones.
Vamos a especificar cada función con un prototipo de función, que da el tipo devuelto, el nombre de la función y el tipo de los argumentos: número, string (cadena de caracteres), booleano o node-set (conjunto de nodos). Si un tipo de argumento es seguido por un signo de interrogación, entonces el argumento es opcional; en otro caso, el argumento es obligatorio.
Estas funciones las podemos clasificar en cuatro grupos:
Funciones de conjuntos de nodos
Funciones de cadenas de caracteres
Funciones lógicas
Funciones numéricas
Funciones de conjuntos de nodos:
last(): devuelve el número total de nodos del contexto seleccionado.
número last()
position(): devuelve la posición del nodo actual dentro de los nodos del contexto seleccionado. Esta posición se enumera desde el 1 no desde el 0 como en otros lenguajes de programación.
número position()
count(): devuelve el número de nodos del conjunto de nodos pasado como argumento.
número count(nodo-set)
name(): devuelve una cadena de caracteres con el nombre cualificado de un nodo del conjunto de nodos pasado como argumento. Formado por el URI del espacio de nombres y el nombre local. Si no se pasa el argumento tomará los nodos contexto como argumentos. Si no se declaran espacios de nombres dará el mismo resultado que la función local-name().
string name(nodo-set?)
local-name(): devuelve el nombre local, sin URI del espacio de nombres de un nodo del conjunto de nodos pasados como argumento. Si no se pasa el argumento tomará los nodos contexto como argumentos. Si no se declaran espacios de nombres dará el mismo resultado que la función name().
string local-name(node-set?)
namespace-uri(): devuelve el URI del espacio de nombres, sin el nombre local, de un nodo del conjunto de nodos pasados como argumento. Si no se pasa el argumento tomará los nodos contexto como argumentos.
string namespace-uri(nodo-set?)
id(): selecciona elementos mediante su identificador único. Los nodos deben estar declarados con el tipo ID en el DTD o XML Schema correspondiente.
string(): convierte un objeto en cadena de caracteres. Si no se incluye argumentos toma un conjunto de nodos con el nodo contexto como único miembro.
string string(object?)
concat(): devuelve la concatenación de argumentos
string concat(string, string, string*)
starts-with(): devuelve verdadero si la primera cadena argumento empieza con la segunda cadena argumento, devuelve falso en caso contrario.
boolean starts-with(string, string)
contains(): devuelve verdadero si la primera cadena argumento contiene a la segunda cadena argumento, devuelve falso en caso contrario.
boolean contains(string, string)
substring-before(): devuelve la subcadena de la primera cadena argumento que precede a la primera aparición de la segunda cadena argumento en la primera cadena argumento, o la cadena vacía si la primera cadena argumento no contiene a la segunda cadena argumento. Si el segundo argumento es la cadena vacía, entonces se devuelve la cadena vacía.
string substring-before(string, string)
substring-after(): La función substring-after devuelve la subcadena de la primera cadena argumento que sigue a la primera aparición de la segunda cadena argumento en la primera cadena argumento, o la cadena vacía si la primera cadena argumento no contiene a la segunda cadena argumento. Si el segundo argumento es la cadena vacía, entonces se devuelve la primera cadena argumento.
string substring-before(string, string)
substring(): La función substring devuelve la subcadena del primer argumento que comienza en la posición especificada en el segundo argumento y tiene la longitud especificada en el tercer argumento. Si no se especifica el tercer argumento, devuelve la subcadena que comienza en la posición especificada en el segundo argumento y continúa hasta el final de la cadena. Se considera que cada caracter en la cadena tiene una posición numérica: la posición del primer carácter es 1, la posición del segundo carácter es 2 y así sucesivamente.
string substring(string, number, number?)
string-length(): devuelve el número de caracteres en la cadena. Si se omite el argumento, toma por defecto el nodo contexto convertido en cadena de caracteres.
number string-length(string?)
normalize-space(): devuelve la cadena argumento con el espacio en blanco normalizado mediante la eliminación del que se encuentra al principio y al final y la substitución de secuencias de caracteres de espacio en blanco por un solo espacio. Si se omite el argumento, toma por defecto el nodo contexto convertido en cadena de caracteres.
string normalize-space(string?)
translate(): devuelve la cadena primer argumento con las apariciones de caracteres del segundo argumento substituidas por los caracteres en las posiciones correspondientes de la tercera cadena argumento.
not(): devuelve verdadero si su argumento es falso, y falso en otro caso.
boolean not(boolean)
true(): devuelve verdadero.
boolean true()
false(): devuelve falso.
boolean false()
lang(): devuelve verdadero o falso dependiendo de si el lenguaje del nodo contextual tal como se especifica por los atributos xml:lang es el mismo que, o es un sublenguaje de, el lenguaje especificado por la cadena argumento.
boolean lang(string)
Funciones numéricas
number(): convierte su argumento en un número. Si se omite el argumento, toma por defecto un conjunto de nodos con el nodo contexto como único miembro.
número number(object?)
sum(): devuelve la suma, a lo largo de todos los nodos del conjunto de nodos argumento, del resultado de convertir los valores de las cadena de caracteres de los distintos nodos en números.
número sum(node-set)
floor(): redondea hacia abajo. Devuelve el mayor número entero que sea menor o igual al argumento.
número floor(number
ceiling(): redondea hacia arriba. Devuelve el menor número entero que sea mayor o igual al argumento.
número ceiling(number)
round(): redondea. Devuelve el número que esté más próximo al argumento y que sea entero.
Queremos saber el grupo del alumno que se apellida 'Bellido Bravo'. Primero buscamos en la estructura de nuestro documento XML la posición del atributo y del elemento que se indican en el enunciado.
A continuación sabemos que el resultado debe ser el número de orden, es decir, nuestro camino de localización debe acabar en este atributo. Ese será nuestro punto de partida. Podemos probar esa consulta colegio/curso/grupo/<span style="text-decoration: underline;"><strong>@orden</strong></span> antes de filtrar el el apellido dado.
orden="A"
orden="B"
orden="A"
orden="B"
Para posicionar el predicado podemos utilizar varias estrategias. Una de ellas puede ser poner le predicado en el primer elemento padre común. En nuestro ejemplo sería grupo.
Si probamos esta consulta obtendremos el grupo que buscábamos. Pero nos devuelve todo el grupo no solamente su orden.
Si mezclamos ambos caminos de localización en el elemento común que habíamos determinado antes obtendremos lo buscado. Es decir usaremos el camino de localización del atributo que queremos mostrar con el predicado que situaremos en el elemento común
Cuando trabajamos con información en distintos niveles de nuestra estructura es importante no utilizar la doble barra en la mitad de los caminos de localización ya que la búsqueda la reiniciará desde el elemento raíz y no con el predicado ya establecido. Si probáis la siguiente sentencia veréis la diferencia.
Vemos también la utilidad de usar el . (nodo actual) cuando necesitamos bajar niveles de jerarquía y .. (nodo padre) cuando queremos subir niveles.
Consultas anidadas
En ocasiones necesitamos hacer varias consultas anidadas, es decir, que necesitamos el resultado de una consulta para realizar una segunda consulta.
Por ejemplo, si queremos saber la nota media de los/as alumnos/as que tienen una nota media menor que la del/a alumno/a que se apellida 'Abad Álvarez'.
Tendremos que hacer dos consultas:
La primera para saber la nota media de 'Abad Álvarez' y la otra para saber los/s alumnos/as que tienen una nota media inferior a un número cualquier, por ejemplo 5.
* Se usa la función number() para evitar la comparación de orden alfabético lo que haría que 10 sea menor que 6.5. Ya que alfabéticamente la letra '6' esta después (es mayor) de la letra '1'.
Expresión para evitar elementos repetidos
En ocasiones queremos mostrar todos los elementos de un determinado tipo pero sin que salgan repetidos. Gracias al eje <strong><span style="text-decoration: underline;">preceding</span></strong> podemos hacer lo una forma sencilla. Recordad que este eje no tiene abreviación por lo que su notación es la completa.
María ya tiene claro que es posible seleccionar distintos elementos de los documentos XML con los que trabajan en su empresa. Pero el formato de salida no es nada legible. Los usuarios están acostumbrados a ver la información en formatos más visuales como HTML.
Félix está interesado en mostrar la información en la web pero no quiere realizar trabajo extra.
Juan les explica que esto es posible. El lenguaje XSLT permite crear documentos HTML con la información aportada por documentos XML. Que en dichos documentos HTML se puede seleccionar y filtrar la información que se desee y presentar en todos los formatos que HTML permita.
Además gracias a las plantillas se puede estandarizar las distintas páginas web y crear un estilo homogéneo y más profesional.
El lenguaje de Transformaciones XSL (Extensible Stylesheet Language Transformations - XSLT) es una recomendación aprobada por el consorcio W3C. Su versión 1.0 fue aprobada el 16 de noviembre de 1999. El mismo día que la recomendación XPath 1.0.
Gracias a este lenguaje los procesadores XSLT pueden transformar un documento XML en otros documentos XML, HTML o de texto plano con estructuras y contenidos distintos de los originales. Esta transformación se realiza gracias al uso de hojas de estilos (<strong>xsl:stylesheet</strong>). El lenguaje XSLT establece la sintaxis y la semántica para construir dichas hojas de estilos.
El lenguaje XSLT es un lenguaje derivado de XML por lo que podremos comprobar si un documento XSLT está bien formado (well-formed) y si es válido frente a un vocabulario.
Una transformación expresada en XSLT describe reglas para transformar un árbol de nodos origen en un árbol de nodos resultado.
La transformación se logra asociando patrones definidos en la plantilla (<strong>xsl:template</strong>). Un patrón, expresado mediante XPath, se compara con los elementos del árbol de origen. Si cumplen con alguna de las reglas de la plantilla estos pasan a formar parte del árbol de nodos resultados. Es importante resaltar que el árbol de nodos resultado es distinto del árbol de nodos origen. Además la estructura del árbol de resultado puede ser completamente diferente de la estructura del árbol de origen. Al construir el árbol de resultado los elementos del árbol de origen se pueden filtrar y reordenar, y se puede agregar una estructura arbitraria.
A la hora de ir creando el árbol de nodos destino que generará el documento de salida podemos usar los siguientes elementos:
Elementos del espacio de nombres asociado al URI: http://www.w3.org/1999/XSL/Transform. Se suele usar el prefijo <strong>xsl</strong>. Son las instrucciones que usa el lenguaje XSLT. Ejemplos: <strong>xsl:stylesheet, xsl:template, xsl:value-of, xsl:for-each,</strong>...
Elementos de extensión. Se utilizan como mecanismos implementados por los distintos desarrolladores para aportar funcionalidades extra. Cada desarrollador determinará su uso. No los usaremos en esta unidad.
Elementos de resultado literal (LRE, literal result element). Son elementos que se añaden al árbol de nodos resultado que no pertenecen al espacio de nombre xsl. Por ejemplo cuando incluimos elementos HTML o texto entre la información obtenida del documento XML.
El lenguaje XSLT no especifica cómo se asociar una hoja de estilos XSLT a un documento XML. Para eso se utiliza un mecanismo propio del estándar XML, las instrucciones de procesamiento. Debe tenerse en cuenta que algunos navegadores por seguridad bloquean estas instrucciones de procesamiento. Un ejemplo de documento XML asociado a una hoja de estilos XSLT podría ser el siguiente:
José Antonio Molina Bautista. Hojas de estilos XSLT(CC BY-NC-SA)
En este ejemplo utilizamos la instrucción de procesamiento xml-stylesheet indicando en el atributo type el tipo de archivo con la nomenclatura MIME (text/xml o text/xsl) y en el atributo href la ubicación de la hoja de estilos a utilizar.
Esta instrucción de procesamiento no es obligatoria, ya que al ejecutar el procesador XSLT se le puede indicar como parámetros los documentos XML y XSL sobre los que queremos realizar la transformación.
Para crear una hoja de estilos utilizamos la instrucción xsl:stylesheet. Para usar esta instrucción necesitamos declarar el espacio de nombres del lenguaje XSLT que se corresponde con la URI: http://www.w3.org/1999/XSL/Transform. Se suele asociar dicho espacio de nombres al prefijo xsl:. Además esta instrucción tiene un atributo obligatorio, version, en el que indicaremos la versión del lenguaje XSLT en la que hemos codificado nuestra hoja de estilos.
Normalmente cada hoja de estilos se creará en un archivo de texto plano con extensión .xsl. Como dijimos anteriormente el lenguaje XSLT es derivado de XML por lo que será necesario incluir en la primera línea el prólogo XML. Posteriormente declararemos nuestra hoja de estilos como en el siguiente ejemplo:
XSLT permite una sintaxis simplificada para las hojas de estilo que consten de una plantilla para el nodo raíz. La sintaxis simplificada permite omitir la estructura de xsl:stylesheet cuando se trate de un elemento de contenido literal. Además en lugar de declarar una plantilla xsl:template esta se sustituirá directamente por dicho elemento de contenido literal. Desde este contenido literal se podrá acceder a las instrucciones del espacio de nombres xsl: como si se hubiera seleccionado como patrón el nodo raíz / del árbol de nodos origen.
En este caso de simplificación dicho elemento literal debe tener el atributo xsl:version. Para utilizar dicho atributo y si se quiere utiliza además alguna instrucción del espacio de nombres xsl: se deberá añadir dicho espacio de nombres al citado elemento literal. Este elemento que actúa de plantilla no podrá contener instrucciones de nivel superior.
Con nuestro documento de ejemplo colegio.xml podemos realizar la siguiente transformación:
En esta simplificación observamos que el elemento de contenido literal html contiene la declaración del espacio de nombres xmlns del lenguaje XSLT y el atributo obligatorio version. Posteriormente haciendo uso del prefijo xsl: podemos utilizar instrucciones que no sean de nivel superior como xsl:value-of.
Si consideramos un documento XSLT como un documento XML el elemento raíz será un elemento xsl:stylesheet o xsl:transform. Los elementos de nivel superior son aquellos del espacio de nombres xsl: que son hijos directos de alguno de estos dos elementos. Tienen un tratamiento especial ya que su ámbito de aplicación es toda la hoja de estilos que estamos declarando.
Los elementos de nivel superior más utilizados y que veremos con más detalle son:
xsl:template
xsl:variable y xsl:param
xsl:output
Otros elementos de nivel superior son:
xsl:import y xsl:include sirven para añadir contenido a las hoja de estilo que estamos desarrollando. Los contenido añadidos mediante xsl:import tienen menor preferencia que los desarrollados en nuestra hoja de estilos. La preferencia de los contenidos añadidos mediante xsl:include es la misma que los desarrollados en nuestra hoja de estilos. Ambos elementos tienen un atributo href que indica dónde se encuentra los contenidos a añadir.
xsl:strip-space y xsl:preserve-space: sirven para indicar al procesador XSLT como debe actuar al normalizar los espacios en blanco.
xsl:key: sirve para declarar un elemento como clave de modo que pueda usarse como los tipos de datos ID, IDREF y IDREFS. Declara una clave con nombre que se puede usar en cualquier otro lugar de la hoja de estilos con la función key().
xsl:decimal-format: define el formato que se utilizará para convertir números en cadenas de caracteres.
xsl:namespace-alias: sirve para definir un prefijo alternativo para un espacio de nombres.
xsl:attribute-set: se utiliza para crear grupos de atributos que se pueden reutilizar en los elementos xsl:element y xsl:copy mediante el atributo use-attribute-sets.
Estos elementos de nivel superior pueden aparecer varias veces o no aparecer. El orden de aparición no es relevante excepto para xsl:import que debe aparecer en primer lugar. Además estos elementos de nivel superior no pueden usarse dentro de otros elementos excepto xsl:variable y xsl:param.
Las plantillas (xsl:template) constan de dos partes: un patrón, expresado mediante XPath en el atributo match, que se compara con los nodos del árbol de origen y unas instrucciones que se aplicarán a los nodos seleccionados. Con la aplicación de esas instrucciones y la incorporación de elementos de contenido literal podremos ir construyen los nodos que necesitemos en el árbol de nodos resultado. Esto permite que una hoja de estilo sea aplicable a distintos documentos XML siempre que tengan la misma estructuras.
El atributo match es obligatorio a no ser que exista un atributo name. El atributo name sirve para hacer referencia a una plantilla mediante la instrucción xsl:call-template. El valor del atributo match no puede incluir el uso de variables.
El contenido del elemento xsl:template serán las reglas que se ejecutarán cuando la plantilla sea utilizada.
En una hoja de estilos podemos tener más de una plantilla. La ejecución de plantillas tiene una serie de abreviaciones que si no se tienen en cuentas pueden llegar a confundir. Cada plantilla se puede hacer coincidir con un determinado nodo de nuestra estructura. Veamos unos ejemplos de distintas construcciones de plantillas:
Plantillas vacías: Si tenemos una plantilla que se corresponde con un nodo de nuestra estructura y esta plantilla no tiene contenido entonces al recorrer esos nodos no mostrará nada.
Nodos sin plantillas asociadas: Si de un determinado nodo de nuestra estructura no creamos plantilla por simplificación mostrará el contenido textual de ese determinado nodo. Pero no mostrará el valor de los atributos.
En el siguiente ejemplo tenemos una plantilla asociada a los nodos de tipo 'alumno' pero está vacía es decir cuando recorra esos nodos mostrará el contenido de esa plantilla que es nada. Además en nuestra estructura tenemos otros nodos que no tienen correspondencia con el atributo match de ninguna plantilla (colegio, nombre, teléfono, curso y grupo) por lo que por simplificación mostrará el contenido textual de esos nodos sin plantilla.
<?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"/>
<xsl:template match="//alumno">
<!-- No hacer nada -->
</xsl:template>
</xsl:stylesheet>
En ocasiones cuando tenemos más de una plantilla vemos que no funciona tal como esperábamos. Por ejemplo, si tenemos una plantilla para 'alumno' que nos muestra el 'nombre' y otra plantilla para 'apellidos' que nos vuestra el propio elemento '.' vemos que no funciona correctamente:
El resultado es solamente lo que muestra la primera plantilla:
<?xml version="1.0" encoding="UTF-8"?>
Cervantes
900102030
Ana
Beatriz
Carlos
Ana
Benito
Carmen
Pero esto a qué es debido. El motivo es el recorrido del árbol de nodos origen. Cuando recorremos en la primera plantilla los elementos 'alumno' podemos mostrar perfectamente su nombre. Pasamos al siguiente 'alumno' y volvemos a mostrar su 'nombre' y así hasta el último 'alumno'. Cuando vamos a aplicar la segunda plantilla ya hemos terminado de recorrer todo el árbol de nodos origen y no podemos volver hacia detrás. Ya veremos que esto puede funcionar pero necesitamos de la instrucción xsl:apply-templates.
Sabiendo esto comprendemos porque el siguiente ejemplo sí muestra ambos valores: nombre y apellidos, ya que los recorre cuando nos encontramos en el nodo 'alumno'.
Una forma habitual de simplificar el uso de las plantillas es usar una única plantilla que acceda al elemento raíz. Dentro de esta única plantilla podremos utilizar expresiones XPath para seleccionar las partes de documento XML que queramos e instrucciones de recorrido xsl:for-each y selección xsl:if para construir la estructura que deseemos. Por ejemplo esta estructura con llamadas anidadas mediante el uso de plantillas:
Una variable es un nombre que se vincula a un valor. El valor de la variable puede ser de los distintos tipos que devuelven las expresiones y funciones XPath. Hay dos elementos que utilizan esta vinculación de valores xsl:variable y xsl:param.
Tanto xsl:variable como xsl:param tienen un atributo name obligatorio. En el momento de utilizar el contenido de la variable hay que especificar el nombre del atributo name con un simbolo $ delante.
El otro atributo de estos elementos es select que si se le especifica una expresión XPath almacenará su resultado en la variable.
La diferencia es que el valor de xsl:param es un valor predeterminado que se usa normalmente pero puede ser sobreescrito cuando se invoca a una plantilla o una hoja de estilos mediante un elemento xsl:with-param que tenga el mismo nombre (name) pero distinto valor que el predeterminado.
Con esta instrucción especificamos el formato de salida deseado. Esta instrucción se puede omitir ya que el procesador XSLT devolverá el resultado como secuencias de caracteres. El uso de este elemento nos facilita poder especificar características de la salida. Los atributos más usados son:
method que especifica el formato de salida. Tiene los siguiente valores predetermindados: xml, html y text.
version con el que podemos especificar la versión del método de salida.
indent para especificar si se deben añadir espacios en blanco adicionales. Los posibles valores son: yes o no.
encoding para especificar la codificación.
standalone para especificar si el documento tendrá relación con otros documentos. Los posibles valores son: yes o no.
Otros atributos son: media-type, doctype-system, doctype-public, omit-xml-declaration, cdata-section-elements.
xsl:copy: con esta instrucción podemos añadir el nodo actual al árbol de nodos destino. Al copiar un elemento también se copia sus nodos espacio de nombre pero no se copian sus nodos atributos ni sus elementos hijos. Este elemento puede usar su atributo use-attribute-sets para añadir conjuntos de atributos declarados anteriormente. Sólo se puede usar esta instrucción con nodos que puedan tener atributos o elementos hijos, es decir, nodo raíz y nodos elemento.
xsl:copy-of: con esta instrucción podemos añadir un fragmento completo del árbol de nodos origen en el árbol de nodos destino. No es necesario convertir ese fragmento a cadenas de caracteres. Tiene un atributo obligatoria select donde debe indicarse una expresión XPath con el fragmento de árbol a copiar. Cuando se copia un elemento se copia el propio elemento y también sus nodos atributo, sus nodos espacio de nombres y sus elementos hijos.
xsl:apply-imports: Sirve para indicar cuándo realizar una importación para sobreescribir una regla de plantillas.
xsl:message: Se utiliza para enviar mensajes al procesador XSLT. Tiene un atributo terminate que puede tomar los valores: yes o no que se utilizar para indicar al procesador XSLT que interrumpa el procesamiento de la hoja de estilos.
xsl:fallback: Su función es establecer una secuencia ordenada de ejecución.
Como vimos con la instrucción xsl:template cuando comparamos el árbol de nodos origen con las expresiones match, por defecto, no se continua buscando más plantillas recorriendo los elementos hijo. Es decir se pasa al siguiente elemento hermano que coincide con la expresión match.
Con la instrucción xsl:apply-templates podemos indicar que sí queremos que se continúe la búsqueda de plantillas en los elementos hijos. Esta instrucción tiene un atributo select. En dicho atributo podemos indicar, mediante una expresión XPath, el conjunto de nodos hijos que queremos que se continúe recorriendo y buscando plantillas que se correspondan con ellos. Si no usamos en atributo select estaremos indicando que se recorran todos los elementos hijos en busca de plantillas.
Como contenido de la instrucción xsl:apply-template puede aparecer la instrucción xsl:sort que nos ordenará los resultados antes de aplicar la plantilla que corresponda. También podemos encontrar la instrucción xsl:with-param que nos permite pasar valores a la plantilla. Estos valores sobreescribirán los valores por defecto indicados por una instrucción xsl:param.
En el siguiente ejemplo vemos el uso de xsl:apply-template. Vemos como se van invocando a los elementos desde el elementos raíz hacia los elementos hijo. En unos casos usando el atributo select y en otros no. En la segunda plantilla al no indicar select aplica a todos los elementos hijo (nombre, apellidos, anno_nac y nota_media). Estos elementos al no tener plantillas, por defecto, mostrarán su contenido textual. Excepto el elemento anno_nac que sí tiene plantilla específica que en lugar de mostrar su contenido muestra el texto 'privado'.
Una forma habitual de simplificar el uso de las plantillas es usar una única plantilla que acceda al elemento raíz. Dentro de esta única plantilla podremos utilizar expresiones XPath para seleccionar las partes de documento XML que queramos e instrucciones de recorrido xsl:for-each y selección xsl:if para construir la estructura que deseemos. Por ejemplo la estructura anterior con llamadas anidadas a distintas plantillas se puede simplificar a una sola plantilla con expresiones XPath e instrucciones xsl:for-each y xsl:if.
Con esta instrucción podemos hacer un bloque repetitivo que recorra de uno en uno todos los nodos indicados mediante una expresión XPath en el atributo select. Dicho atributo es obligatorio. El valor indicado deben ser un conjunto de nodos. El recorrido de los nodos se hace en el orden en el que son procesados a no ser que se utilice la instrucción xsl:sort.
xsl:if
Con esta instrucción podemos hacer un bloque condicional. De modo que sólo ejecutemos una parte de la plantilla si se cumple una determinada condición. Esta condición debe indicarse en el atributo test. La expresión de la condición se evaluará y se convertirá al tipo de dato boolean. Si el resultado es true entonces se ejecutará el contenido del elemento xsl:if. Si el resultado no es true se pasará a la siguiente instrucción después del elemento xsl:if.
Vamos a realizar una transformación en la que vamos a ordenar los alumnos por orden de apellido descendente y de cada uno de ellos mostraremos su nombre y su fecha de nacimiento o su nota media dependiendo de si su posición es par o impar.
<html>
<body>
<ol>
<li>Carmen. Fecha de nacimiento: 2017</li>
<li>Carmen. Nota media: 4</li>
<li>Carlos. Fecha de nacimiento: 2017</li>
<li>Carmen. Nota media: 10</li>
<li>Beatriz. Fecha de nacimiento: 2018</li>
<li>Beatriz. Nota media: 8.25</li>
<li>Benito. Fecha de nacimiento: 2018</li>
<li>Benito. Nota media: 2.25</li>
<li>Ana. Fecha de nacimiento: 2017</li>
<li>Ana. Nota media: 7.5</li>
<li>Alejando. Fecha de nacimiento: 2018</li>
<li>Ana. Nota media: 6.5</li>
</ol>
</body>
</html>
xsl:choose, xsl:when y xsl:otherwise
Esta instrucción es parecida a la instrucción xsl:if pero permite evaluar más de un caso posible. Consiste en una secuencia de elementos xsl:when seguidos de un elemento xsl:otherwise opcional. Cada elemento xsl:when tiene un único atributo test, que especifica una expresión. Cuando se procesa un elemento xsl:choose, cada uno de los elementos xsl:when es evaluado en orden. Sólo se ejecutará el primer y solo el primer elemento xsl:when que haya devuelto un resultado true . Si no hay ningún xsl:when con resultado true se ejecutará el contenido del elemento xsl:otherwise. Si ningún elemento xsl:when es verdadero y no se ha indicado ningún elemento xsl:otherwise no se ejecutará nada.
xsl:sort
Con esta instrucción se pueden ordenar los elementos seleccionados por las instrucciones xsl:apply-templates o xsl:for-each. Debemos agregar xsl:sort como elemento hijo de alguna de las instrucciones anteriores. Podemos agregar más de un elemento xsl:sort. Si se agregan más de uno la ordenación se realizará en el orden de aparición. Si xsl:sort se aplica a un bucle xsl:for-each deberá aparecer como primer hijo de ese elemento. En el atributo select se indicará una expresión que devuelva una cadena de caracteres que servirá como clave de ordenación del conjunto de nodos seleccionados. El valor por defecto de este atributo es el nodo actual (.)
Otros atributos son:
order: especifica el orden, puede tomar los valores: ascending o descending.
lang: especifica el lenguaje de la clave de ordenación (alfabeto).
data-type: especifica el tipo de dato. Puede tomar los valores: text, number o un nombre cualificado.
case-order Especifica casos especiales. Puede tomar los valores: upper-first, lower-first para los data-type="text".
Vamos a realizar una transformación que muestre una tabla con los alumnos ordenados por apellidos con las filas de distintos colores según las notas medias obtenidas. Recordando un poco de HTML+CSS, en este ejemplo queremos asignar dinámicamente con un xsl:choose el valor del atributo class del elemento tr para dar uno de los tres estilos creados en la cabecera.
Este elemento se utiliza para generar texto ya sea extraído del árbol de nodos origen, generado por una expresión XPath o insertando el valor de una variable. El elemento xsl:value-of creará un nodo text en el árbol de nodos destino. Tiene un atributo obligatorio select en el que se indicará una expresión que será evaluada y su resultado se convertirá a una cadena de caracteres. Si queremos añadir un conjunto de nodos, es decir, elementos con sus elementos hijos al árbol de nodos destino deberíamos utilizar xsl:copy-of en su lugar.
<?xml version="1.0" encoding="UTF-8"?>
<!--Esto es un saludo-->
<saludo idioma="español">Hola, bienvenido al colegio Cervantes</saludo>
xsl:number
Este elemento se utiliza para insertar un número formateado en el árbol de nodos resultado. El número que se va a insertar se debe especificar en el atributo value mediante una expresión. La expresión se evaluará y el objeto resultante se convertirá a un número. El número se redondeará a un entero y después se convertirá a una cadena de caracteres. Si no se especifica el atributo value el número añadido estará basado en la posición del nodo contexto. Los siguientes atributos controlarán como se realizará la numeración:
level: especificará que niveles del árbol de nodos origen se utilizarán. Sus valores pueden ser single, multiple o any. Por defecto será single.
count: será un patrón que especifique qué nodos serán contados en esos niveles. Por defecto se contarán los nodos semejantes al nodo contexto.
from: es un patrón que especifica dónde se empieza a contar.
Para especificar el formato se utilizar el atributo opcional format, al que se le indicará un patrón con una combinación de los siguientes caracteres:
Un token que acabe en 1: Formará una secuencia numérica. Por ejemplo 1 formará la secuencia 1, 2, 3, ... y 001 formará la secuencia 001, 002, 003, ...
Letra A: formará la secuencia A, B, C, ..., AA, AB, ...
Letra a: formará la secuencia a, b, c, ..., aa, ab, ...
Letra I: formará la secuencia I, II, III, IV, ...
Letra i: formará la secuencia i, ii, iii, iv, ...
Otras numeraciones especificadas en unicode: ア イ ๑ א ა α а
El patrón por defecto es 1.
xsl:element
Este elemento permite crear un elemento con el nombre indicado por el atributo obligatorio name. También se le puede indicar un espacio de nombres de forma opcional con el atributo namespace. El contenido de este elemento podrá ser, por ejemplo, elementos xsl:attribute, otros elementos xsl:element hijos, comentarios xsl:comment, etc.
xsl:attribute
Este elemento puede ser usado para añadir atributos a los elementos creados en una plantilla mediante el elemento xsl:element o directamente escribiendo las etiquetas de apertura y cierre (LRE). El nombre del atributo será indicado mediante el atributo obligatorio name. También se le puede indicar un espacio de nombres de forma opcional con el atributo namespace. El contenido de este elemento será el valor del atributo.
Al igual que un elemento se puede crear mediante (LRE), los atributos también pueden construirse mediante el uso de llaves {}, a esto se le llama attribute value templates. Consiste en escribir el atributo dentro de su correspondiente etiqueta y cuando se quiere introducir el valor indicarlo mediante una expresión entre llaves {}.
Si un elemento tiene varios atributos o un atributo que se quiere reutilizar se puede utilizar la instrucción attribute-set.
xsl:text
Este elemento se utiliza para crear nodos texto en el árbol de nodos resultado. Los nodos de texto adyacentes se simplificarán en uno solo. Este elemento aplicará lo especificado en los elementos de nivel superior xsl:strip-space y xsl:preserve-space en lo referente al manejo de espacios en blanco.
xsl:comment
Este elemento creará un nodo comentario en el árbol de nodos destino. Su contenido será una cadena de texto.
xsl:processing-instruction
Este elemento creará un nodo instrucción de procesamiento en el árbol de nodos destino. En el atributo obligatorio name se deberá especificar el nombre o clase de la instrucción de procesamiento.
A partir de nuestro documento colegio.xml vamos a crear otro documento XML que contenga un listado de alumnos ordenado por notas cuyo nombre comience por 'A'.
document(): Permite el acceso a otros documentos XML distintos del original. Tiene dos parámetros el primero indicará la URI o lugar donde estará el documento a añadir. Si no se indica este parámetro por defecto se tomará el documento actual. El segundo parámetro opcional nos permite seleccionar parte de ese nuevo documento mediante una expresión XPath. Esta función devuelve el conjunto de nodos.
node-set document(object, node-set?)
key(): esta función es similar a id() de XPath. El primer parámetro es el nombre de la clave que debe ser un nombre cualificado indicado en un elemento xsl:key. El segundo argumento debe ser el valor para dicha clave. Devuelve el conjunto de nodos del documento que cumplen estas condiciones.
node-set key(string, object)
format-number(): Convierte el primer parámetro a una cadena de caracteres siguiendo el patrón indicado en el segundo parámetro. Si existen un tercer argumento indicará el nombre del xsl:decimal-format que se utilizará. Si no se indica este tercer argumento se cogerá el valor por defecto. Los patrones del segundo parámetro son los de la clase DecimalFormat de JDK.
string format-number(number, string, string?)
current(): devuelve el valor del nodo contexto. Normalmente se sustituye por su versión abreviada, <xsl:value-of select="current()"/> equivale a <xsl:value-of select="."/>.
node-set current()
generate-id(): genera un identificador único para el conjunto de nodos pasado como parámetro. si no se indica este parámetro se tomará el nodo contexto actual. Devuelve una cadena de caracteres con dicha identificación.
string generate-id(node-set?)
Otras funciones XSLT son: unparsed-entity-uri(), unparsed-entity-uri(), system-property(), element-available() y function-available().
En este caso generamos una clave por nombre de alumno, recorremos los nombres de alumnos que al generar de nuevo la clave es igual a la primera ya creada. Realizamos la media agrupando por el nombre que tenemos seleccionado. Otra forma podría haber sido utilizar el eje preceding para evitar elementos repetidos.
Un procesador XSLT es una aplicación que realiza una transformación partiendo de un documento XML y siguiendo las reglas indicadas en otro documento XSLT. El resultado será un documento en uno de los formatos permitidos; XML, HTML y texto plano.
José Antonio Molina Bautista. Transformación XSLT(GNU/GPL)
Como ya hemos comentado a lo largo de este unidad el procesador XSLT cuando lee el archivo XML inicial y crea una árbol de nodos origen. A continuación va procesando las instrucciones de la hoja de estilos recogida en el documento XSLT. Esta hoja de estilos contendrá una o varias plantillas. Cada plantilla tendrá una expresión de emparejamiento. Estas expresiones serán buscada en el archivo XML original y si encuentra elementos compatibles se ejecutan las instrucciones oportunas. Estas instrucciones irán generando un árbol de nodos destino. Una vez recorridas todas las plantillas y generado todo el árbol de nodos destino este será escrito en un archivo de salida.
También hay que tener en cuenta que el consorcio W3C publica sus recomendaciones sobre el lenguaje XSLT pero no se encarga de implementar los procesadores XSLT. Existen varias empresas software que se dedican a ello.
Algunas de las empresas de software que tienen procesadores XSLT son:
Saxon: desarrolla su procesador XSLT llamado saxon con las recomendaciones W3C más recientes: XSLT 3.0, XPath 3.1. Se distribuye como librerías de programación para varios lenguajes: Java, .NET, C/C++, PHP, Python y JavaScript aunque también se puede utilizar en la línea de comandos gracias al empaquetado de aplicaciones java .jar. El fundador de esta empresa es Michael Kay una persona que participa en las recomendaciones del consorcio W3C.
Gnome: tiene una implementación de las recomentaciones XSLT 1.0 y XPath 1.0 en una librería llamada libxslt. Esta librería tiene una utilidad de línea de comandos llamada xsltproc. Gnome tiene otra librería relacionada con XML llamada libxml2 que permite trabajar y validar documentos XML. Libxml2 tiene una utilidad de líneas de comandos llamada xmllint.
Apache: desarrolló un procesador XSLT muy utilizado llamado Xalan. Este procesador XSLT implementabla las recomendaciones XSLT 1.0 y XPath 1.0. Se distribuía como librerías para los lenguajes Java y C++. Su última versión estable la 2.7.1 es de noviembre de 2007. Dentro de la empresa Apache existe un proyecto hermano Xerces que permite trabajar y validar documentos XML.
Microsoft: desarrolló una librería con funciones XML llamada MSXML (Microsoft XML Core Services) que implementaba XML 1.0, XML Schema 1.0 (2ª edición), XPath 1.0 y XSLT 1.0. Su última versión es la 6.
La forma de utilizar estos procesadores XSLT varían según las necesidades.
Podemos encontrar procesadores XSLT que se ejecutan en la línea de comandos de nuestro sistema operativo (xsltproc, saxonb-xslt, xalan), como librerías de distintos lenguajes de programación, en páginas web accesibles con nuestro navegador (http://xsltransform.net/,https://xslttest.appspot.com/) o integrados en editores específicos de XML (XML Copy Editor, Oxygen XML Editor, Altova XMLSpy, Liquid XML Studio, Stylus Studio) o generales (Netbeans, Visual Studio, IntelliJ IDEA, Eclipse).
Vamos a realizar una transformación desde la línea de comandos con la librería saxon. En este caso utilizaremos la última versión con mantenimiento la 10.8 en su edición Home (HE) empaquetada como librería java. Esta edición 'Home Edition' es open source y puede descargarse gratis. Para poder ejecutar esta librería es necesario tener instalado al menos la versión Java SE 8 o el JDK 1.8.
Para comprobar que tenemos instalada la máquina virtual de java ejecutaremos en nuestra línea de comandos:
java --versión
En Windows un solo guión.
Una vez descargada la librería SaxonHE10-8J.zip la descomprimiremos en una carpeta. En la línea de comandos nos posicionaremos en dicha carpeta y probaremos que la librería es accesible con:
java -jar saxon-he-10.8.jar -t
con -t indicaremos a saxon que nos muestra información sobre su versión
Saxon-HE 10.8J from Saxonica
Java version 11.0.15
No source file name
Usage: see http://www.saxonica.com/documentation/index.html#!using-xsl/commandline
Format: net.sf.saxon.Transform options params
Options available: -? -a -catalog -config -cr -diag -dtd -ea -expand -explain -export -ext -im -init -it -jit -l -lib -license -m -nogo -now -ns -o -opt -or -outval -p -quit -r -relocate -repeat -s -sa -scmin -strip -t -T -target -TB -threads -TJ -Tlevel -Tout -TP -traceout -tree -u -val -versionmsg -warnings -x -xi -xmlversion -xsd -xsdversion -xsiloc -xsl -y --?
Use -XYZ:? for details of option XYZ
Params:
param=value Set stylesheet string parameter
+param=filename Set stylesheet document parameter
?param=expression Set stylesheet parameter using XPath
!param=value Set serialization parameter
Por simplificar la configuración en esa carpeta también pondremos los archivos para crear nuestra transformación, por ejemplo colegio.xsl y colegio.xml. Y ejecutaremos la transformación con:
Otro procesador de línea de comandos es xsltproc de la librería Gnome LibXSLT. Una vez instalado el paquete xsltproc, podemos realizar la transformación de la siguiente forma:
xsltproc colegio.xml colegio.xsl -o colegio.html
De igual forma instalando el paquete xalan podemos realizar nuestra transformación con el comando:
Algunos editores tienen la funcionalidad de depuración de código. Esta funcionalidad permite ejecutar paso a paso las instrucciones de forma que facilita enormemente encontrar y corregir errores. Además suelen permitir mostrar los valores que van tomando las distintas variables o estructuras de datos. También permiten establecer puntos de parada (breakpoint) o ejecución hasta el cursor de modo que podemos ejecutar el código de forma normal hasta encontrar dichos puntos de parada o la posición de nuestro cursor en el editor donde el depurador de código cambiará a ejecución paso a paso. Otra funcionalidad muy útil es mostrar paso a paso los resultados que va generando nuestro código.
Esta funcionalidad de depuración puede estar incluida o no en los distintos editores. Normalmente en los editores gratuitos no suele estar presente.
Entre los editores genéricos con versión open source y que tengan esta funcionalidad de depuración tenemos:
Materiales desarrollados inicialmente por el Ministerio de Educación, Cultura y Deporte y actualizados por el profesorado de la Junta de Andalucía bajo licencia Creative Commons BY-NC-SA.
Antes de cualquier uso leer detenidamente el siguenteAviso legal