Transformación documentos
XML
Jose Emilio Labra Gayo
Departamento de Informática
Hojas de estilos para XML
Antecedentes
SGML tenía DSSSL (Document Style Semantics and
Specification Language)
Para XML se optó por crear XSL (XML Stylesheet
Language)
Posteriormente se dividió en 3 partes:
XSLT: Transformación de documentos XML
XPath: Especificar caminos y expresiones XML
XSL-FO: Objetos de formateo
XSLT
Lenguaje de plantillas
Recorre el árbol recursivamente encajando plantillas
Version 1.0 (1999)
Versión más popular
Incluido en navegadores
Versión 2.0 (2007)
Basada en Xpath 2.0
Facilidades para agrupación y tipos de datos
Creación de funciones
Múltiples documentos de salida
Problema: No soportada en navegadores ni en algunos sistemas
vacia.xsl
Estructura básica de XSLT
Espacio de nombres
http://www.w3.org/1999/XSL/Transform
Elemento raíz:
stylesheet
Aunque no se definan plantillas, se recorre el árbol,
mostrando elementos por defecto
Ejemplo: Hoja de estilos vacía:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--…plantillas… -->
</xsl:stylesheet>
Ejemplo de generación de HTML
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <body> <h1>Pedido</h1> <xsl:apply-templates /> </body> </html> </xsl:template> <xsl:template match="producto"> <p><xsl:value-of select="nombre" /></p> </xsl:template> </xsl:stylesheet> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido> <html> <body> <h1>Pedido</h1> <p>Grapadora</p> <p>Rotulador</p> </body> </html>Lenguaje XSLT
Lenguaje declarativo basado en plantillas: “templates”
Varias plantillas predefinidas: recorren el árbol
mostrando los elementos
Encaje de plantillas
El atributo
match
de una plantilla es una expresión XPath
Funcionamiento:
El procesador recorre el árbol
Si encuentra una plantilla que encaja con el nodo actual
Mete los elementos que hay dentro de la plantilla en la salida
<xsl:template match="/"> <html> <body> <h1>Pedido</h1> </body> </html> </xsl:template>
Aplicando plantillas
“
apply-templates
” indica al procesador que continúe
aplicando plantillas
Por defecto, continúa recursivamente a partir del nodo actual
Mediante el atributo
select
se pueden otras partes del árbol
El atributo
select
toma una expresión XPath
<xsl:template match="/"> <html> <body> <h1>Pedido</h1> <xsl:apply-templates /> </body> </html> </xsl:template> <xsl:template match="/"> <html> <body> <h1>Pedido</h1> <xsl:apply-templates select=“//producto[2]”/> </body> </html> </xsl:template>
Obteniendo valores
“
value-of
” permite obtener un valor
El valor a obtener se indica mediante el atributo select
Admite cualquier una expresión XPath
<xsl:template match="producto"> <p> <xsl:value-of select="nombre" /> </p> </xsl:template> <xsl:template match="producto"> <p> <xsl:value-of select="nombre" />, <xsl:value-of select="@codigo" /> </p> </xsl:template>
Asociar XSLT a XML
En un documento XML se puede incluir:
<?xml-stylesheet
type="text/xsl"
href="documento.xsl" ?>
Transforma el documento "al vuelo" en el navegador
NOTA: Chrome no realiza la transformación en ficheros locales por motivos de seguridad
Modos de recorrido
Mediante el atributo “mode” se pueden indicar diferentes
modos de recorrido
Útil para generar tablas de contenido
<xsl:template match="/"> <html> <body> <h1>Pedido</h1> <p>Productos: <xsl:apply-templates mode="nombres" /> </p> <h2>Detalle</h2> <xsl:apply-templates /> </body> </html> </xsl:template> <xsl:template match="producto" mode="nombres"> <xsl:value-of select="nombre" /> | </xsl:template> <xsl:template match="producto"> <p><xsl:value-of select="nombre" />, <xsl:value-of select="@codigo" />, <xsl:value-of select="cantidad" /> </p> </xsl:template>
Plantillas predefinidas
Las plantillas predefinidas recorren el árbol y muestran el
texto y ignorando el resto
<xsl:template match="text()|@*"> <xsl:value-of select="." />
</xsl:template>
<xsl:template match="*|/"> <xsl:value-of apply-templates /> </xsl:template>
<xsl:template match="processing-instruction()
|comment()" />
Nodos de texto y atributos: los muestra
Elementos y nodo raíz: Continúa recorrido recursivo
Comentarios e instrucciones de procesamiento:
Árbol de resultado
XSLT va generando un árbol de resultado
Se incluyen todos los elementos de un espacio de
nombres distinto al de XSLT
Se añaden las declaraciones de espacios de nombres
correspondientes
Se puede controlar el proceso mediante:
exclude-result-prefixes
:
namespace-alias
extension-element-prefixes
xsl:output
permite indicar el tipo de salida
method
puede ser "xml", "html", "text"
Transformar XML a XML
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" /> <xsl:template match="/"> <codigos> <xsl:apply-templates /> </codigos> </xsl:template> <xsl:template match="producto"> <codigo><xsl:value-of select="@codigo" />
</codigo> </xsl:template> </xsl:stylesheet> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido> <codigos> <codigo>G23</codigo> <codigo>R15</codigo> </codigos>
Transformar XML a Texto (CSV)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" />
<xsl:template match="producto"> <xsl:value-of select="@codigo" />,<xsl:value-of select="nombre" />,<xsl:value-of select="cantidad" /> </xsl:template> </xsl:stylesheet> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido> G23,Grapadora,20 R15,Rotulador,10
De XML a Gráficos vectoriales (SVG)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg"> <xsl:template match="/"> <svg:svg><xsl:apply-templates /></svg:svg> </xsl:template> <xsl:template match="producto"><svg:text y="{position()*20}" x="10" font-size="20"> <xsl:value-of select="nombre" />
</svg:text>
<svg:rect y="{position()*20-10}" x="100"
width="{cantidad * 10}" height="10" fill="blue"/> </xsl:template> </xsl:stylesheet> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido>
De XML a PDF (a través de FO)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:template match="/"> <fo:root><fo:layout-master-set> <fo:simple-page-master master-name="maestro"> <fo:region-body margin="2cm"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="maestro"> <fo:flow flow-name="xsl-region-body"> <xsl:apply-templates /> </fo:flow> </fo:page-sequence> </fo:root></xsl:template> <xsl:template match="producto"><fo:block><xsl:value-of select="nombre" /></fo:block>
</xsl:template> </xsl:stylesheet> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido> Grapadora Rotulador
Creación de elementos
2 formas
<xsl:template match="producto">
<p>
<xsl:value-of select="nombre" />
</p>
</xsl:template>
<xsl:template match="producto">
<xsl:element name="p">
<xsl:value-of select="nombre" />
</xsl:element> </xsl:template> Inclusión literal Mediante xsl:element <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <p> Grapadora</p>
Creación de atributos
2 formas
<xsl:template match="producto">
<p id="{@codigo}">
<xsl:value-of select="nombre" />
</p> </xsl:template> <xsl:template match="producto"> <p> <xsl:attribute name="id"> <xsl:value-of select="@codigo" /> </xsl:attribute> <xsl:value-of select="nombre" /> </p> </xsl:template> Mediante { } Mediante xsl:element <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <p id="G23">Grapadora</p>
Creación de texto
Mediante
xsl:text
<xsl:template match="producto"> <p> <xsl:value-of select="nombre" /> <xsl:text> </xsl:text> <xsl:value-of select="cantidad" /> </p> </xsl:template> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <p> Grapadora 20 </p>Creación de comentarios
Mediante
xsl:comment
<xsl:template match="producto">
<xsl:comment>
Identificador: <xsl:value-of select="@codigo" /> </xsl:comment> <p> <xsl:value-of select="nombre" /> </p> </xsl:template> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <!-- Identificador: G23 --> <p> Grapadora </p>
Creación de Instrucciones de procesamiento
Mediante
xsl:processing-instruction
<xsl:template match="producto"> <xsl:processing-instruction name="PROD"> <xsl:value-of select="@codigo" /> </xsl:processing-instruction> <p> <xsl:value-of select="nombre" /> </p> </xsl:template> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <?PROD G23> <p> Grapadora </p>Copiar contenido
2 formas
xsl:copy
: copia un nodo
xsl:copy-of:
copia un fragmento del árbol
<xsl:template match="producto"> <item> <xsl:copy-of select="." /> </item> </xsl:template> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <item> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> </item>
Condicional: if
Mediante xsl:if se pueden indicar condiciones
<xsl:template match="producto"> <p>
<xsl:value-of select="nombre" />.
<xsl:if test="cantidad > 15"> Superior a 15 </xsl:if> </p> </xsl:template> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <p> Grapadora. Superior a 15 </p>
Condicional: choose
xsl:choose
permite definir varias condiciones
<xsl:template match="producto"><p>
<xsl:value-of select="nombre" />.
<xsl:choose>
<xsl:when test="cantidad > 15"> Superior a 15
</xsl:when>
<xsl:when test="cantidad >= 1"> Entre 1 y 15 </xsl:when> <xsl:otherwise> Cantidad incorrecta </xsl:otherwise> </xsl:choose> </p> </xsl:template> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <p> Grapadora. Superior a 15 </p>
Repetición: for-each
xsl:for-each
repite el procesamiento sobre un conjunto
<xsl:template match="/">
<codigos>
<xsl:for-each select="//producto"> <codigo>
<xsl:value-of select="@codigo" />
</codigo> </xsl:for-each> </codigos> </xsl:template> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido> <codigos> <codigo>G23</codigo> <codigo>R15</codigo> </codigos>
Variables
Mediante xsl:variable pueden declararse variables
Se accede mediante $vble
Los valores de las variables no pueden modificarse
XSLT = Lenguaje declarativo
<xsl:template match="/">
<xsl:variable name="total"
select="sum(//cantidad)" /> <pedido>
<xsl:for-each select="//producto">
<producto>
<xsl:value-of select="@codigo" />.
<xsl:value-of select="cantidad" /> de
<xsl:value-of select="$total" />.
</producto> </xsl:for-each> </pedido> </xsl:template> </xsl:stylesheet> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido> <pedido> <producto>G23. 20 de 30</producto> <producto>R15. 10 de 30</producto> </pedido>
Parámetros
Se declaran con
xsl:param
Toman valores por defecto que pueden alterarse en la invocación
Similares a las variables
<xsl:param name="ponerTotal">SI</xsl:param>
<xsl:template match="/">
<xsl:if test="$ponerTotal = 'SI'">
Total = <xsl:value-of select='sum(//cantidad)' />
</xsl:if> …continuar procesando </xsl:template> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido> Total = 30 …continuar procesando
Plantillas con nombre
Similares a funciones que pueden ser invocadas
<xsl:template match="/">
<xsl:call-template name="suma">
<xsl:with-param name="a" select="2" />
<xsl:with-param name="b" select="3" />
</xsl:call-template> </xsl:template>
<xsl:template name="suma">
<xsl:param name="a" />
<xsl:param name="b" />
<xsl:value-of select="$a + $b" />
</xsl:template>
…cualquier documento XML
Recursividad
Es posible realizar invocaciones recursivas
XSLT = lenguaje Turing completo
<xsl:template name="factorial">
<xsl:param name="n" />
<xsl:choose>
<xsl:when test="$n = 0">1</xsl:when>
<xsl:otherwise>
<xsl:variable name="f">
<xsl:call-template name="factorial">
<xsl:with-param name="n" select="$n - 1" />
</xsl:call-template> </xsl:variable> <xsl:value-of select="$n * $f" /> </xsl:otherwise> </xsl:choose> </xsl:template>
En otro lenguaje sería: def factorial(n) if n == 0 1 else f = factorial (n-1) n * f end end
Ordenación
xsl:sort permite ordenar los resultados
<xsl:template match="/">
<codigos>
<xsl:for-each select="//producto">
<xsl:sort data-type="number"
select="cantidad" order="ascending" />
<codigo>
<xsl:value-of select="@codigo" />
</codigo> </xsl:for-each> </codigos> </xsl:template> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido> <codigos> <codigo>R15</codigo> <codigo>G23</codigo> </codigos>
Numeración automática
xsl:number permite insertar numeración automática
Es posible modificar el formato del número
<xsl:template match="/"> <codigos> <xsl:for-each select="//producto"> <codigo> <xsl:number />.-<xsl:value-of select="nombre" /> </codigo> </xsl:for-each> </codigos> </xsl:template> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido> <codigos> <codigo>1.-Grapadora</codigo> <codigo>2.-Rotulador</codigo> </codigos>
Acceso a otros documentos
La función document permite acceder a otros
documentos XML
<xsl:template match="/"><xsl:for-each select="//producto">
<xsl:variable name="cod" select="@codigo" />
<xsl:value-of select="nombre" />,
<xsl:value-of select="document('precios.xml')//producto[@codigo = $cod]/@precio" /> </xsl:for-each>
</xsl:template> <pedido fecha="3/2/2011"> <producto codigo="G23"> <nombre>Grapadora</nombre> <cantidad>20</cantidad> </producto> <producto codigo="R15"> <nombre>Rotulador</nombre> <cantidad>10</cantidad> </producto> </pedido> <codigos> <codigo>G23, 15</codigo> <codigo>R15, 6</codigo> </codigos> <precios>
<producto codigo="R15" precio="6" /> <producto codigo="G23" precio="15" /> <producto codigo="S56" precio="26" /> </precios>