Introducción
Un documento XSL-FO es un documento XML en el que se especifica cómo se van a formatear unos datos para presentarlos en pantalla, papel u otros medios.
El objetivo de este lenguaje es parecido al de CSS, definir la forma en la que deberá mostrarse un documento XML por pantalla (o papel).
Flujo de trabajo con XSL-FO
¿Qué extensión deben tener los ficheros XSL-FO?
Estructura de un documento XSL-FO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="A4">
<!-- La plantilla de la hoja va aquí -->
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4">
<!-- El contenido de la página va a aquí -->
</fo:page-sequence>
</fo:root>
- Espacio de nombres:
http://www.w3.org/1999/XSL/Format
- Elemento raíz:
fo:root
- Organización visual del documento:
- Modelos de página: “páginas maestras”
- Se definen dentro de
fo:layout-master-set
- Sólo un tipo de página maestra,
fo:simple-page-master
, que es una página rectangular.
- Se definen dentro de
- Las páginas del documento harán referencia a las páginas maestras que se hayan definido, y heredarán sus propiedades.
- Modelos de página: “páginas maestras”
Elemento fo:simple-page-master
Atributos del elemento fo:simple-page-master
:
master-name
page-height
page-width
margin-left
,margin-top
,margin-right
,margin-bottom
Diagrama atributos elemento fo:simple-page-master
Ejemplo:
1
2
3
4
5
6
<fo:layout-master-set>
<fo:simple-page-master master-name="pagina-normal" page-height="29.7cm"
page-width="21cm" margin-left="3cm" margin-right="3cm" margin-top="2cm"
margin-bottom="2cm">
</fo:simple-page-master>
</fo:layout-master-set>
Elemento fo:page-sequence
Representa una secuencia de páginas y hace referencia a modelo de página.
Recuerda que el atributo
master-reference
debe haberse definido enlayout-master-set
.
Elementos hijo de fo:page-sequence
:
fo:title
(opcional): Título de la páginafo:static-content
: Texto que se repite en todas las páginas. También puede contener elementos que se repiten aunque se calculen en cada una (como el número de página).fo:flow
: Contenidos de las páginas, se incluyen en secuencia
Tiene 8 atributos opcionales para indicar cómo se pagina la secuencia:
fo:initial-page-number
fo:force-page-count
fo:format
fo:letter-value
fo:country
fo:language
fo:grouping-separator
fo:grouping-size
Regiones
region-body
(requerido): Cuerpo de la página.region-before
(opcional): Cabecera de la página.region-after
(opcional): Pie de la página.region-start
(opcional): Columna izquierda de la página.region-end
(opcional): Columna derecha de la página.
Ejemplo:
1
2
3
4
5
6
7
8
9
<fo:layout-master-set>
<fo:simple-page-master master-name="pagina-normal" page-height="29.7cm"
page-width="21cm" margin-left="3cm" margin-right="3cm" margin-top="2cm"
margin-bottom="2cm">
<fo:region-before extent="1cm"/>
<fo:region-body margin-top="1cm" margin-bottom="1cm"/>
<fo:region-after extent="1cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
Modelo de formateo
Cajas rectangulares, llamadas áreas, que pueden contener:
- Texto
- Espacio vacío
- Imágenes
- Otros objetos de formateo
Las cajas tienen bordes y márgenes.
Hay 4 tipos de áreas, representados en el siguiente diagrama:
Estructura de las áreas
Elemento fo:flow
Contiene el “contenido real” de las páginas. Es una secuencia de elementos fo:block
, fo:block-container
, fo:table-and-caption
, fo:table
, y fo:list-block
.
Atributo flow-name
: Indica en qué región de la página va el contenido. Valores posibles:
xsl-region-body
xsl-region-before
xsl-region-after
xsl-region-start
xsl-region-end
Elemento fo:static-content
El contenido aparecerá en cada secuencia de página.
Ejemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="miPágina"
margin="2cm">
<fo:region-body margin="2cm" />
<fo:region-before extent="2cm" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="miPágina">
<fo:static-content flow-name="xsl-region-before"
font-style="italic" font-size="10pt" font-family="Times">
<fo:block text-align="start"
background-color="blue" color="white"> Página <fo:page-number />
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block>Hola con cabecera</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
Resultado:
Salida usando fo:static-content
Listas
Ejemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<fo:list-block>
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>Primer elemento</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>Segundo elemento</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
Resultado:
Salida de lista
Tablas
Ejemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<fo:table border="0.5pt solid"
text-align="center"
table-layout="fixed">
<fo:table-column column-width="5cm" />
<fo:table-column column-width="5cm" />
<fo:table-body>
<fo:table-row>
<fo:table-cell padding="6pt" border="0.5pt solid">
<fo:block> Uno . Uno </fo:block>
</fo:table-cell>
<fo:table-cell padding="6pt" border="0.5pt solid">
<fo:block> Uno . Dos </fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell padding="6pt" border="0.5pt solid">
<fo:block> Dos . Uno </fo:block>
</fo:table-cell>
<fo:table-cell padding="6pt"
border="0.5pt solid">
<fo:block> Dos . Dos </fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
Resultado:
Salida de tabla
Mantener el formato
Para mantener el formato podemos usar el bloque CDATA
como se ve en el siguiente ejemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
<fo:block
font-family="monospace"
white-space-collapse="false"
wrap-option="no-wrap"
linefeed-treatment="preserve"
white-space-treatment="preserve">
<![CDATA[
<pedido> <producto id="G34">
<nombre>Grapadora</nombre>
</producto>
</pedido>
]]>
</fo:block>
Salida:
1
2
3
4
5
<pedido>
<producto id="G34">
<nombre>Grapadora</nombre>
</producto>
</pedido>
Enlaces e imágenes
Enlaces:
1
2
<fo:basic-link external-destination="..." />
<fo:basic-link internal-destination="valorID" />
Cada bloque puede tener un atributo ID.
Referencias a páginas:
1
<fo:page-number-citation ref-id="valorID" />
Gráficos:
1
<fo:external-graphic src="url('smile.gif')" content-height="1em" content-width="1em"/>
Otras características
- Notas a pie de página:
footnote
- Marcadores (
marker
,retrieve-marker
). Por ejemplo, incluir nombre del capítulo en la cabecera. - Líneas guía:
fo:leader
- Elementos
fo:float
, sin posición absoluta - Orientación de escritura:
reference-orientation
- Bidireccionalidad (izqda a dcha y dcha a izqda)
Ejemplos XSL-FO
Ejemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="ejemploHolaMundo">
<fo:region-body margin="1in" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="ejemploHolaMundo">
<fo:flow flow-name="xsl-region-body">
<fo:block>Hola mundo!</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
Otro ejemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
<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-reference="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 segundo 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 segundo XSL-FO.
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
Procesadores XSL-FO
Se recomienda usar Apache™ FOP.
En GNU/Linux con variables de entorno configuradas:
Si quieres saber que son las variables de entorno y como se configuran, lee el artículo Tutorial: La variable de entorno Path
Si no tenemos las variables de entorno configuradas el ejecutable
fop
ofop.bat
deberá estar en la misma carpeta donde esté<docExistente.fo>
.
1
$fop -fo <docExistente.fo> -pdf <docGenerado.pdf>
En GNU/Linux sin variables de entorno configuradas:
1
$./fop -fo <docExistente.fo> -pdf <docGenerado.pdf>
En Windows con variables de entorno configuradas:
1
fop.bat -fo <docExistente.fo> -pdf <docGenerado.pdf>
En Windows sin variables de entorno configuradas :
1
./fop.bat -fo <docExistente.fo> -pdf <docGenerado.pdf>
XSLT + XSL-FO
XSLT y XSL-FO pueden trabajar conjuntamente como se muestra en la siguiente imagen:
Funcionamiento de XSLT y XLS-FO en secuencia
- Con el procesador XSLT generamos un fichero XSL-FO.
- El fichero XSL-FO es procesado por el procesador XSL-FO generando un documento que puede ser leído cómodamente por una persona.
Utilizaríamos un comando para generar el XLS-FO de los datos XML:
1
java -jar "C:\Program Files\SaxonHE12-4J\saxon-he-12.4.jar" -xsl:xslt.xsl -s:datos.xml -o:xslfo.xsl
Para luego generar el PDF con Apache FOP:
1
fop.bat -fo xslfo.xsl -pdf pdf.pdf
Estos dos pasos se pueden condensar en uno de la siguiente manera:
1
fop -xml datos.xml -xsl xslt.xsl -pdf pdf.pdf