Convertir XML en PDF utilizando XSL-FO y FOP

En este artículo vamos a ver como podemos utilizar el FOP y el lenguaje de objetos de formateo XSL-FO para generar documentos en formato PDF a partir de nuestros documentos XML.

XSL

La XSL es una especificación desarrollada dentro del W3c para aplicar formato a los documentos XML de forma estandarizada. La XSL es un lenguaje para escribir hojas de estilo que consta de dos partes:

  • XSLT, que es un lenguaje de transformación, mediante el cual se puede transformar un documento XML en otro XML.
  • XSL-FO, un lenguaje de formateo, que no es más que un vocabulario XML para especificar objetos de formateo (FO).

El lenguaje XSLT ya es más que conocido (es una recomendación del W3C desde el 16 Noviembre 1999) y en estas páginas de Programación en castellano ya le hemos dedicado algunos artículos en los que hemos explicado como utilizarlo para por ejemplo generar HTML o SVG.

Por tanto en este artículo vamos a centrarnos en el lenguaje XSL-FO (candidato a recomendación desde el 21 de Noviembre del 2000) y sobre todo en como utilizar una aplicación denominada FOP mediante la cual podremos convertir nuestros documentos XML en formato PDF.

XSL-FO (Objetos de Formateo)

Mediante los objetos de formateo (Formatting Objects -FO-) y sus propiedades podemos describir cómo se van a visualizar los componentes de un documento. Con estos objetos definimos:

  • Las características de la página.
  • Los párrafos.
  • Las listas.
  • Las tablas.
  • Los enlaces.
  • etc.

La especificación XSL indica el vocabulario XML que define estos objetos de formateo.

El siguiente código hola.fo es un pequeño ejemplo de fichero XSL-FO:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!--  ================================================
      Hola.fo
      Joaquin Bravo Montero
      (c)Programacion en Castellano
         http://www.programacion.net
      ================================================ -->

<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">

  <fo:layout-master-set>
  
    <fo:simple-page-master master-name="simple"
                  page-height="29.7cm" 
                  page-width="21cm"
                  margin-top="1cm" 
                  margin-bottom="2cm" 
                  margin-left="2.5cm" 
                  margin-right="2.5cm">
      <fo:region-body margin-top="3cm"/>
      <fo:region-before extent="3cm"/>
      <fo:region-after extent="1.5cm"/>
    </fo:simple-page-master>
  </fo:layout-master-set>
  
  <fo:page-sequence master-name="simple">

    <fo:flow flow-name="xsl-region-body">

      <fo:block font-size="18pt" 
            font-family="sans-serif" 
            line-height="24pt"
            space-after.optimum="15pt"
            text-align="center"
            padding-top="3pt">
        Mi primer XSL-FO
      </fo:block>


      <fo:block font-size="12pt" 
                font-family="sans-serif" 
                line-height="15pt"
                space-after.optimum="3pt"
                text-align="justify">
                Hola este es mi primer XSL-FO.
      </fo:block>


    </fo:flow>
  </fo:page-sequence>
</fo:root>

En el que podemos observar:

  • Que se trata de un vocabulario XML, en el que todos los elementos van precedidos del namespace 'fo', y que por tanto al escribir el elemento raiz del documento XML debemos declararlo de la siguiente manera:
  • <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  • Que esta formado por un conjunto de elementos: fo:simple-page-master, fo:flow, fo:block, etc. mediante los cuales y sus propiedades (definidas en los atributos): font-size, font-family, etc. describimos como se visualizan de forma genérica los componentes de un documento. La especificación define por tanto todos estos elementos y sus propiedades y como deben expresarse mediante un vocabulario XML.

Procesadores XSL-FO

Un procesador XSL es la aplicación que procesa un documento XML compuesto de XSL-FOS y lo presenta de manera que una persona lo pueda leer facilmente.

Flujo de proceso

En los últimos meses han sido muchos los procesadores de XSL-FO que han aparecido. Estos son algunos de los más significativos:

  • XEP, desarrollado por RenderX. Es sin duda alguna el más avanzado. El único inconveniente es que se trata de una aplicación comercial aunque nos podemos bajar una versión demo evidentemente limitada en sus funcionalidades. Es recomendable darse una vuelta por su Web y visulizar los espectaculares ejemplos que han desarrollado. En Java.
  • PassiveTex. Es una librería de macros en Tex que pueden ser usadas para procesar documentos XML formados por XSL-FO. Ejecutando PassiveTex con pdfTex se pueden generar facilmente documentos PDF. Lo mejor de estas librerias es el buen soporte para MathML que poseen.
  • XSL Formatter, de Antenna House Inc. Consiste en un procesador de XSL-FO acompañado de un interfaz de usuario. Necesita la MSXML3.0 como procesador de XSLT y funciona sobre plataforma Windows.
  • Unicorn Formatting Objects (UFO), que es un procesador de XSL-FO implementado en C++. La salida de esta herramienta es TeX y a partir de este formato podemos generar PostScript, PDF, etc.
  • FOP, que es un procesador de XSL-FO desarrollado en Java por Apache XML Project. Es el primero que aparecio, es totalmente gratuito y aunque no es tan potente como el XEP es sin duda alguna el más utilizado en la actualidad (es gratuito). Entre sus ventajas cabe destacar que permite trabajar con documentos SVG.

FOP

El FOP (Formatting Object to PDF) es el primer procesador de objetos de formateo XSL que aparecio. Empezó a ser desarrollada en solitario por James Tauber pero posteriormente se incorporo al "Apace XML Project" lo que está acelerando su desarrollo.

En el momento de escribir estas lineas la versión actual del FOP es la 0.18.1 que es la que utilizaremos en nuestros ejemplos. Exactamente hemos utilizado la versión: Fop-0.18.1-DEV-src.zip que se puede obtener en la siguiente direccion: http://xml.apache.org/dist/fop/.

Prerequisitos

Como ya hemos dicho es una aplicación en Java por lo que para poder utilizarla el único requisito necesario es tener instalado la máquina virtual Java. Según la documentación basta con el Java 1.1.x o superior. Recomiendo tener como mínimo la versión 1.1.2 del JDK, ya que para las versiones 1.1.x hay algunos ejemplos que dan problemas.

No hace falta nada más ya que esta distribución viene con todos los archivos .jar que le hacen falta para poder funcionar. Fijaros que el fichero .zip ocupa 9.289 KB.

Instalacion

La instalación es muy sencilla. Simplemente tenemos que descomprimir el fichero y veremos que nos crea una gran cantidad de directorios con todo lo necesario para empezar a trabajar y ver su funcionamiento: ejemplos, documentación, ficheros bat, etc.

Funcionamiento

Para probar que todo nos funciona correctamente podemos realizar los siguientes pasos:

  • Dentro de la carpeta raiz del FOP nos situamos en el subdirectorio docs/examples/
  • Desde linea de comandos ejecutamos el fichero runtests.bat, el cual:
    • Crea un directorio tests.
    • Dentro del cual se generaran en formato PDF los ficheros XSL-FO que se encuentran en el directorio fo.

Si todo el proceso anterior ha funcionado correctamente significara que ya tenemos todo perfectamente instalado para trabajar con el FOP.

Y para convertir nuestro documento hola.fo, lo colocamos en el directorio raiz de la aplicación y ejecutamos el fichero Fop.bat de la siguiente manera:

Fop hola.fo hola.pdf

Lo cual nos genera el siguiente fichero PDF:

Hola.fo en formato PDF

Pero con la anterior expresión sólo hemos ejecutado la opción más sencilla que nos ofrece la aplicación. También podríamos utilizar el FOP directamente como browser de ficheros XSL-FO. No tendríamos más que ejecutar el comando anterior de la siguiente manera:

Fop hola.fo -awt

Obteniendo el siguiente resultado:

Hola.fo visualizado en browser del FOP.

También podriamos convertir al formato MIF, TXT, etc.

Para terminar esta sección simplemente un comentario. Es importante que os fijéis que el documento PDF lo hemos generado directamente desde el fichero hola.fo. Para el ejemplo lo he escrito directamente a mano. Pero como ya he dicho anteriormente se trata de un fichero XML que podríamos haber generado desde otro fichero XML mediante una XSLT. Es decir, la conversión de nuestro XML original a PDF hubiese constado de dos partes:

  1. Conversión XML original a XSL-FO mediante XSLT y un procesador XSLT.
  2. Conversión de XSL-FO a PDF mediante el procesador FOP.

El FOP nos permite también realizar esta acción en un único paso (el FOP lleva incorporado el procesador XSLT Xalan). Si suponemos que nuestro documento inicial se llama hola.xml, mediante la siguiente instrucción lo hubiesemos podido realizar:

Fop -xsl hola.xsl -xml hola.xml -pdf hola.pdf

Generando nuestro documento XML en formato PDF

A continuación vamos a escribir un ejemplo completo en el que transformaremos a PDF el documento gastrono.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<direcciones>
 <tema>Mis direcciones de gastronomía</tema>
 <intro>Recopilación de mis direcciones de gastronomía favoritas.</intro>

 <direccion>
  <titulo>A fuego lento</titulo>
  <url>http://www.bongust.com/</url>
  <descripcion>Portal sobre el mundo de la 
   gastronomía creado por Koldo Royo.</descripcion>
 </direccion>
 ....
 ....
</direcciones>

Que ya hemos utilizado en otros artículos.

Para ello, en primer lugar debemos escribir una XSLT que nos convierta dicho documento al vocabulario XSL-FO. A esta XSLT la llamaremos gastronofo.xsl.

<?xml version="1.0" encoding="ISO-8859-1"?>

<!--  ================================================
      gastronofo.xsl
      Joaquin Bravo Montero
      (c)Programacion en Castellano
         http://www.programacion.net
      ================================================ -->

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

<xsl:template match="direcciones">

	<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">

  <fo:layout-master-set>
  
    <fo:simple-page-master master-name="simple"
                  page-height="29.7cm" 
                  page-width="21cm"
                  margin-top="1cm" 
                  margin-bottom="2cm" 
                  margin-left="2.5cm" 
                  margin-right="2.5cm">
      <fo:region-body margin-top="3cm"/>
      <fo:region-before extent="3cm"/>
      <fo:region-after extent="1.5cm"/>
    </fo:simple-page-master>
  </fo:layout-master-set>
  
  <fo:page-sequence master-name="simple">

    <fo:flow flow-name="xsl-region-body">
     <xsl:apply-templates/>
    </fo:flow>
  </fo:page-sequence>
</fo:root>	

</xsl:template>

<xsl:template match="tema">

	<fo:block font-size="20pt" 
            font-family="sans-serif" 
            line-height="24pt"
            space-after.optimum="15pt"
            text-align="center"
            padding-top="3pt">
        <xsl:value-of select="."/>
  </fo:block>

</xsl:template>

<xsl:template match="intro">
	<fo:block font-size="12pt" 
            font-family="sans-serif" 
            line-height="15pt"
            space-after.optimum="3pt"
            text-align="justify">
      <xsl:value-of select="."/> 
  </fo:block>
</xsl:template>

<xsl:template match="direccion">
	<fo:block space-after.optimum="3pt"
            space-before.optimum="4pt">	
	    <xsl:apply-templates/>
	</fo:block>
</xsl:template>

<xsl:template match="titulo">
	<fo:block font-size="12pt" 
            font-weight="bold"
            font-family="sans-serif" 
            line-height="13pt"
            space-after.optimum="2pt"
            text-align="justify">
       <xsl:value-of select="."/>
  </fo:block>
</xsl:template>

<xsl:template match="url">
   <fo:block font-size="9pt">
     <fo:basic-link color="#0060A0" external-destination="{.}">
       <xsl:value-of select="."/>
     </fo:basic-link>
   </fo:block>	
</xsl:template>

<xsl:template match="descripcion">
	<fo:block font-size="9pt"
            start-indent="3pt"		 
            font-family="sans-serif" 
            line-height="12pt"
            space-after.optimum="3pt"
            text-align="justify">
         <xsl:value-of select="."/>
  </fo:block>
</xsl:template>

</xsl:stylesheet>

A partir de aqui tenemos dos posibilidades:

  • Generar el PDF en dos pasos:
    1. Transformar el fichero gastrono.xml el formato XSL-FO mediante la XSLT anterior y cualquier porcesador XSLT. Si por ejemplo utilizamos el XT
    2. xt gastrono.xml gastronofo.xsl gastrono.fo
    3. Transformar el resultado a PDF utilizando el FOP como ya sabemos:
    4. Fop gastrono.fo gastronopdf.pdf
  • O generarlo en un único paso utilizando el FOP de la siguiente manera:
  • Fop -xsl gastronofo.xsl -xml gastrono.xml -pdf gastronopdf.pdf

En cualquiera de los dos casos el resultado es el siguiente documento PDF:

Documento gastrono.xml en formato PDF.

Direcciones

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO