Introducción al módulo XML::XSLT para perl

ArticleCategory: [Choose a category for your article]

Applications

AuthorImage:[Here we need a little image form you]

[Photo of the Author]

TranslationInfo:[Author and translation history]

original in en Egon Willighagen
en to es Javier Palacios

AboutTheAuthor:[A small biography about the author]

Se unió al equipo holandés de _LF_ en 1999, y a principios de este año ha pasado a ser el segundo editor del mismo. Estudia informational chemistry Universidad de Nijmegen. Le gusta jugar al baloncesto y disfruta caminando.

Abstract:[Here you write a little summary]

En este artículo se presenta el módulo XML::XSLT para perl. Muestra las capacidades del estandar XSLT del W3C y como puede ser utilizado para administrar y publicar documentos XML en la web.

ArticleIllustration:[This is the title picture for your article]

[Illustration]

ArticleBody:[The article body]

Introducción

Transformaciones XSL (XSLT, XSL Transformations) es una recomendacion del W3C, por lo que puede considerarse un estándar. XSLT es parte de XSL, que significa Lenguaje de Hojas de estilo para XML. Su propósito es, como indica su nombre, organizar la estructura de un documento XML. El formateo de objetos juega un papel principal en XSL a la hora de mostar la información, pero a lo largo de ese proceso la transformación de los datos se hace a menudo necesaria. Y ahí es donde entra XSLT.

Al contrario de lo que sucede con el propioo XSL, XSLT es ya una recomendación estable. Varios procesadores XSLT se encuentran en desarrollo, usando varios lenguajes de programación. Los más maduros están escritos en C (XT, de James Clark) y java (Xalan, inicialmente de Lotus Inc. y actualmente por la fundación Apache). Pero también existen dos proyectos que usan perl: XML::XSLT y XML::Sabotron. El primero es el más antiguo, y está completamente escrito en perl, mientras que el segundo es un interfaz para un procesador XSLT en C++.

XML::XSLT module

La versión actual es 0.21 y se puede descargar del CPAN. Recientemente el proceso se ha convertido en SourceForge, por lo que está disponible el árbol CVS. A pesar de ello, éste artículo está basado en la versión 0.21. El módulo de perl es desarrollado por Geert Josten, un estudiante de química en la Universidad de Nijmegen, pero en estos momentos mucha otra gente contribuye al desarrollo. Con la aparición del árbol CVS, se espera que el desarrollo de XML::XSLT se vea lanzado. Lo más importante es acelerar la implementación del borrador de trabajo del W3C sobre XSLT.

Este código de perl muestra cómo se usa el módulo:

#!/usr/bin/perl
use XML::XSLT;

my $xmlfile = "example.xml";
my $xslfile = "example.xsl";

my $parser = XML::XSLT->new ($xslfile, "FILE");

$parser->transform_document ($xmlfile, "FILE");
$parser->print_result();

El ejemplo muestra cómo un documento XML (example.xml) se transforma basándose en un fichero XSLT (example.xsl). Pero las hojas de estilo también pueden basarse en un arbol DOM:

#!/usr/bin/perl
use XML::XSLT;
use XML::DOM;

my $domparser = new XML::DOM::Parser;
my $doc = $domparser->parsefile ("file.xml");

my $parser = XML::XSLT->new ($doc, "DOM");

o una simple cadena:

#!/usr/bin/perl
use XML::XSLT;

my $xsl_string = qq{
<?xml version="1.0"?>
<xsl:stylesheet>
  <xsl:template match="/">
    <html>
      <xsl:apply-templates/>
    </body>
  </xsl:template>
</xsl:stylesheet>
};

my $parser = XML::XSLT->new ($xsl_string, "STRING");

Estos tres tipos están disponibles para la función transform_document() mostrada en el primer ejemplo.

Aquí está un script que transforma un fichero XML basándose en uns hoja de estilo XSLT. Necesita dos argumentos en la línea de comandos, que son los nombres del fichero XSLT y el XML. El script hace uso del mecanismo "FILE".

Ahora que sabemos cómo usar un procesador XSLT bajo perl para convertir documentos XML, podemos echar un vistazo al estándar XSLT.

El estándar de transformación XSL

Las transformaciones XSL fueron diseñadas para facilitar la publicación de la información almacenada en XML. Mientras que el formateo XSL se usa para layout and design, XSLT se usa para realizar transformaciones básicas de los datos XML, como puede se ordenarlos, seleccionar información, o combinar información de varias fuentes. Sin embargo, en la vida real, se hace patente que XSLT por sí mismo es también adecuado para layout and design.

XML::XSLT no abarca aún todos los comandos XSLT, pero sí los que usaremos en éste artículo.

Los documentos XSLT definen cómo se debe transformar un documento XML. Lo hace definiendo un template para cada elemento. Debajo hay varios ejemplos de documentos XSLT que se usan con un documento XML que contiene una hoja de cálculo de Gnumeric (la aplicación GNOME para hojas de cálculo). De modo que ahora ya sabes que el formato de archivado que usa Gnumeric es XML. Usualmente están comprimidas: prueba a descomprimir un fichero *.gnumeric y verás.

Si observas la hoja de cálculo, verás que además de los datos puros, también almacenan información sobre layout. Por ejemplo, el layout de la página, y la altura y anchura de la celda. Construiremos varias hojas de estilo XSLT para hacer tareas específicas como:

Presentaremos los fundamentos del XSLT escribiendo una hoja XSLT para hacer un sumario muy simple (verysimple.xsl):

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="*">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="text()"/>

  <xsl:template match="Item">
    <xsl:value-of select="./name"/> : <xsl:value-of select="./val-string"/>
  </xsl:template>

</xsl:stylesheet>

El primer template encaja con todos los elementos del documento XML. El segundo encaja con todos los CDATA del documento XML. Y el último es el que de hecho hace lo que queremos: da a cada Item en el Sumario del documento Gnumeric el valor (CDATA) de sus elementos hijos name y val-string. ¡Comprobémoslo! Comparemos la salida y lo que veamos si es lo que esperarías en base al documento XML.

Pero Item ya encaja con el primer template, ¿no es así? Entonces, ¿por qué aplica el tercer template y no el primero? Lo hace porque el último sobreescribe al primero. Los templates quedan de esta forma ordenados de generales a específicos.

Notemos que XML::XSLT imprime montones de espacios en blanco que se originan desde la hoja XSLT. No creo que exista ningún mecanismo en la versión actual capaz de solventar esto. Pero dado que la salida será XHTML, no nos preocuparemos demasiado por ello en estos momentos. El siguiente ejemplo tiene la misma funcionalidad, pero añade partes de HTML para que podamos visulizarlo con un navegador convencional (simple.xsl):

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="*">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="text()"/>

  <xsl:template match="Item">
    <b><xsl:value-of select="./name"/></b>: <i><xsl:value-of select="./val-string"/></i><br />
  </xsl:template>

  <xsl:template match="/">
    <html>
      <head>
        <title>Summary Gnumeric File</title>
      </head>
      <body bgcolor="white">
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

Disponemos ahora de un template adicional para el elemento raíz (/). Esto hace posible colocar código XHTML alrededor del resto de la salida; la salida que obtuvimos en el primer ejemplo se coloca ahora en el cuerpo. ¿Por qué? Cuando XML::XSLT empieza a procesar, busca un template que encaje con el elemento raíz. Entonces imprime el código XHTML hasta la apertura con la etiqueta body. Entonces sigue aplicando templates a todos los elementos hijos. Cuando se han acabado continúa con el template raíz de nuevo, imprimiendo las etiquetas body y html de cierre.

También hay algo de código XHTML adicional en el template Item. Notemos que se pueden mezclar comandos XSLT con la salida de datos. Un procesador de XSLT toma como salida cada elemento que no se encuentra en el espacio de nombres xsl.

A partir de ahora los ejemplos sólo contendrán los templates nuevos o modificados. En la hoja de estilo final deberemos enlazarlos todos. Para finalizar nuestro primer ejemplo, añadiremos una cabecera mediante una segunda instancia del comando apply-templates (finalsimple.xsl):

  <xsl:template match="Summary">
    <h2>Summary</h2>
    <ul>
      <xsl:apply-templates/>
    </ul>
  </xsl:template>

El comando for-each

El comando xsl:for-each nos da mayor control sobre el procesado del documento XML, especialmente en combinación con xsl:sort, aunque ese comando aún no está implementado en XML::XSLT.

Para añadir información sobre las hojas de cálculo de Gnumeric, usaremos xsl:for-each (foreach.xsl):

  <xsl:template match="Sheets">
    <xsl:for-each select="Sheet">
      <h2><xsl:value-of select="Name"/></h2>
      <ul>
        Rows: <xsl:value-of select="MaxRow"/><br />
        Cols: <xsl:value-of select="MaxCol"/><br />
      </ul>
    </xsl:for-each>
  </xsl:template>

El documento XML consta de una sóla hoja de cálculo. Puedes intentar probar con un fichero de Gnumeric con más de una hoja de cálculo.

Como mencionamos más arriba, no podemos ordenar elementos con XML::XSLT en el momento actual. Lo que es una pena, dado que los datos XML en el fichero Gnumeric no están ordenados. Si podemos ordenarlos, seremos capaces de generar una tabla XHTML que nos de el contenido exacto de la hoja de cálculo, pero eso no es posible aún. A pesar de ello, lo que sí podemos hacer es listar toda la información de una cierta fila o columna, tal y como se hace en el siguiente ejemplo.

El comando if

Para listar los datos de la tercera columna (que contiene los sueldos de los estudiantes en Holanda), podemos hacer uso del comando xsl:if (if.xsl):

  <xsl:template match="Sheets">
    <xsl:for-each select="Sheet">
      <h2><xsl:value-of select="Name"/></h2>
      <ul>
        Rows: <xsl:value-of select="MaxRow"/><br />
        Cols: <xsl:value-of select="MaxCol"/><br />
        <xsl:apply-templates select="Cells"/><br />
      </ul>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="Cells">
    Content of Col 3:
    <xsl:for-each select="Cell">
      <xsl:if test="@Col='3'">
        <xsl:value-of select="Content"/><xsl:text>, </xsl:text>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

Dado que Sheets no es capaz, tendremos que decirle que use el template Cells sobre sus hijos. Usando el parámetro select en combinación con el comando xsl:apply-templates, podemos forzarle a aplicar tan sólo el template Cells.

El template Cells actúa sobre todos los elementos Cell hijos (nuevamente, hay que asegurarse de esto en la fuente XML!), pero sólo imprime el valor si la propiedad Col tiene el valor "3". Hay que notar the el signo "@" ser refiere a las propiedades, mientras que la omisión del mismo se refiere a los elementos.

Según se van complicando los templates, se va complicando averiguar cual es el elemento actual. Dentro del documento no existe ningún foco, pero una vez que se aplica un template aparece un foco. Por ejemplo, al aplicar el template Cells el procesador focaliza en una instancia de dicho elemento. Al seleccionar información se utiliza este foco: select="." dentro del template Cells ser refiere al elemento Cells. El select="Cell" del comando xsl:for-each seleccionaría todos los elementos Cell, pero una vez dentro del bucle, el foco quedaría cada vez en uno de esos elementos Cell. Notemos que test="@Col" se refiere a la propiedad de Cell y no de Cells. Desde dentro del bucle podemos referirnos a las propiedades de Cells con select="../@name", si dejamos de lado el hecho de que Cells no tiene propiedades.

El comando xsl:text se asegura de que el texto es enviado íntegro a la salida. Normalmente el espacio de la secuencia ", " sería tomado como un espacio en blanco y por tanto una parte poco importante de la salida. Usando xsl:text podemos asegurarnos de que todo el texto será enviado correctamente.

Conclusión

Aún queda mucho más sobre XSLT y el módulo XML::XSLT. Este breve artículo trata de ser simplemente una introducción al módulo. Posiblemente plantea más preguntas de las que responde, pero eso es bueno. Podemos probar con la página de talkback o las listas de correo del sitio web de XML::XSLT.

Referencias

Glosario

CDATA
CDATA es un dato tipo carácter y puede ser cualquier secuencia de caracteres que no contengan "]]>". Se puede ver en la recomendación XML.

DOM (Document Object Model)
Un interface que puede usarse para acceder a documentos, por ejemplo, documentos XML. Se puede mirar en el sitio web de DOM.

Gnumeric
Un programa de hoja de cálculo para Gnome.