Transformación documentos XML Jose Emilio Labra Gayo Departamento de Informática Universidad de Oviedo
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 Versión 3.0 (en desarrollo)
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" vacia.xsl xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <!-- plantillas --> </xsl:stylesheet> xsltproc vacia.xsl documento.xml
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> <p><xsl:value-of select="nombre" /></p> </xsl:stylesheet> <pedido fecha="3/2/2011"> <producto codigo="r15"> <nombre>rotulador</nombre> <cantidad>10</cantidad> </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 Una transformación se basa en declarar nuevas plantillas
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>
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 match="/"> <html> <body> <h1>pedido</h1> <xsl:apply-templates select= //producto[2] /> </body> </html>
Obteniendo valores value-of permite obtener un valor El valor a obtener se indica mediante el atributo select Admite cualquier una expresión XPath <p> <xsl:value-of select="nombre" /> </p> <p> <xsl:value-of select="nombre" />, <xsl:value-of select="@codigo" /> </p>
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 match="producto" mode="nombres"> <xsl:value-of select="nombre" /> <p><xsl:value-of select="nombre" />, <xsl:value-of select="@codigo" />, <xsl:value-of select="cantidad" /> </p>
Plantillas predefinidas Las plantillas predefinidas recorren el árbol y muestran el texto y ignorando el resto Nodos de texto y atributos: los muestra <xsl:template match="text() @*"> <xsl:value-of select="." /> Elementos y nodo raíz: Continúa recorrido recursivo <xsl:template match="* /"> <xsl:value-of apply-templates /> Comentarios e instrucciones de procesamiento: los ignora <xsl:template match="processing-instruction() /> comment()"
Á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" encoding indica el tipo de codificación
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> <codigo> <xsl:value-of select="@codigo" /> </codigo> </xsl:stylesheet> <pedido fecha="3/2/2011"> <producto codigo="r15"> <nombre>rotulador</nombre> <cantidad>10</cantidad> </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:value-of select="@codigo" />,<xsl:value-of select="nombre" />,<xsl:value-of select="cantidad" /> <pedido fecha="3/2/2011"> <producto codigo="r15"> <nombre>rotulador</nombre> <cantidad>10</cantidad> </pedido> </xsl:stylesheet> 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> <svg:text y="{position()*20}" x="10" font-size="20"> <xsl:value-of select="nombre" /> </svg:text> <pedido fecha="3/2/2011"> <producto codigo="r15"> <nombre>rotulador</nombre> <cantidad>10</cantidad> </pedido> <svg:rect y="{position()*20-10}" x="100" width="{cantidad * 10}" height="10" fill="blue"/> </xsl:stylesheet>
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> <fo:block><xsl:value-of select="nombre" /></fo:block> </xsl:stylesheet> <pedido fecha="3/2/2011"> <producto codigo="r15"> <nombre>rotulador</nombre> <cantidad>10</cantidad> </pedido> Grapadora Rotulador Requiere procesador de XSL-FO
Creación de elementos 2 formas Inclusión literal <p> <xsl:value-of select="nombre" /> </p> Mediante xsl:element <xsl:element name="p"> <xsl:value-of select="nombre" /> </xsl:element> <p> Grapadora</p>
Creación de atributos 2 formas Mediante { } <p id="{@codigo}"> <xsl:value-of select="nombre" /> </p> Mediante xsl:element <p> <xsl:attribute name="id"> <xsl:value-of select="@codigo" /> </xsl:attribute> <xsl:value-of select="nombre" /> </p> <p id="g23">grapadora</p>
Creación de texto Mediante xsl:text <p> <xsl:value-of select="nombre" /> <xsl:text> </xsl:text> <xsl:value-of select="cantidad" /> </p> <p> Grapadora 20 </p>
Creación de comentarios Mediante xsl:comment <xsl:comment> Identificador: <xsl:value-of select="@codigo" /> </xsl:comment> <p> <xsl:value-of select="nombre" /> </p> <!-- Identificador: G23 --> <p> Grapadora </p>
Creación de Instrucciones de procesamiento Mediante xsl:processing-instruction <xsl:processing-instruction name="prod"> <xsl:value-of select="@codigo" /> </xsl:processing-instruction> <p> <xsl:value-of select="nombre" /> </p> <?PROD G23> <p> Grapadora </p>
Copiar contenido 2 formas xsl:copy: copia un nodo xsl:copy-of: copia un fragmento del árbol <item> <xsl:copy-of select="." /> </item> <item> </item>
Condicional: if Mediante xsl:if se pueden indicar condiciones <p> <xsl:value-of select="nombre" />. <xsl:if test="cantidad > 15"> Superior a 15 </xsl:if> </p> <p> Grapadora. Superior a 15 </p>
Condicional: choose xsl:choose permite definir varias condiciones <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> <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> <pedido fecha="3/2/2011"> <producto codigo="r15"> <nombre>rotulador</nombre> <cantidad>10</cantidad> </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 <pedido fecha="3/2/2011"> <xsl:template match="/"> <xsl:variable name="total" select="sum(//cantidad)" /> <pedido> <xsl:for-each select="//producto"> <producto codigo="r15"> <producto> <nombre>rotulador</nombre> <xsl:value-of select="@codigo" />. <cantidad>10</cantidad> <xsl:value-of select="cantidad" /> de <xsl:value-of select="$total" />. </pedido> </xsl:for-each> <pedido> </pedido> <producto>g23. 20 de 30 <producto>r15. 10 de 30 </xsl:stylesheet> </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 <pedido fecha="3/2/2011"> <producto codigo="r15"> <nombre>rotulador</nombre> <cantidad>10</cantidad> </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> cualquier documento XML <xsl:template name="suma"> <xsl:param name="a" /> <xsl:param name="b" /> <xsl:value-of select="$a + $b" /> 5
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> 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> <pedido fecha="3/2/2011"> <producto codigo="r15"> <nombre>rotulador</nombre> <cantidad>10</cantidad> </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 <pedido fecha="3/2/2011"> <xsl:template match="/"> <codigos> <xsl:for-each select="//producto"> <codigo> <producto codigo="r15"> <xsl:number />.- <nombre>rotulador</nombre> <xsl:value-of select="nombre" /> <cantidad>10</cantidad> </codigo> </xsl:for-each> </pedido> </codigos> <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> <pedido fecha="3/2/2011"> <producto codigo="r15"> <nombre>rotulador</nombre> <cantidad>10</cantidad> </pedido> <precios> <producto codigo="r15" precio="6" /> <producto codigo="g23" precio="15" /> <producto codigo="s56" precio="26" /> </precios> <codigos> <codigo>g23, 15</codigo> <codigo>r15, 6</codigo> </codigos> precios.xml
Valoración de XSLT Es un lenguaje de programación Turing-completo Lenguaje declarativo (sin asignación destructiva) 4 tipos de datos (enteros, booleanos, strings y conjuntos de nodos Sin chequeo estático de tipos Seguridad? Eficiencia? (no son objetivos de diseño) XSLT 2.0 pretende incluir tipos de datos de XML Schema Flexible: La sintaxis de XPath se adapta a posibles cambios en la estructura. No se valida el documento Bueno para hacer tareas sencillas rápidamente Empotrado en navegadores Los programas XSLT son documentos XML La sintaxis es poco amigable para el programador Necesidad de buenas herramientas de autor