When to use XSL-FO over RTF
RTF templates are excellent for most reports. Use XSL-FO (XSLT Formatting Objects) when you need:
- Pixel-perfect multi-column layouts
- Complex running headers/footers that differ by page
- Fixed-position elements (watermarks, background images)
- Reports that mix portrait and landscape sections
- Precise control over pagination
XSL-FO basics
XSL-FO is an XML vocabulary for describing page layouts. BIP processes it using the Apache FOP engine:
<?xml version="1.0" encoding="UTF-8"?>
<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="A4"
page-height="29.7cm" page-width="21cm"
margin-top="2cm" margin-bottom="2cm"
margin-left="2.5cm" margin-right="2.5cm">
<fo:region-body margin-top="1cm" margin-bottom="1cm"/>
<fo:region-before extent="1cm"/>
<fo:region-after extent="1cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4">
<fo:static-content flow-name="xsl-region-before">
<!-- Header content -->
<fo:block font-size="10pt" color="grey">
Company Confidential — <fo:inline><xsl:value-of select="//REPORT_DATE"/></fo:inline>
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<!-- Main content -->
<xsl:for-each select="//EMPLOYEES/EMPLOYEE">
<fo:block font-size="11pt">
<xsl:value-of select="NAME"/>
</fo:block>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
BIP’s simplified XSL syntax
BIP supports its own simplified tag syntax that can be embedded in XSL-FO:
<?for-each:EMPLOYEES?> ... <?end for-each?>
<?EMPLOYEE_NAME?>
<?xdofx:to_char(AMOUNT, '$999,999')?>
These are preprocessed by BIP before being passed to the FO processor.
Tables in XSL-FO
<fo:table width="100%">
<fo:table-column column-width="30%"/>
<fo:table-column column-width="40%"/>
<fo:table-column column-width="30%"/>
<fo:table-header>
<fo:table-row>
<fo:table-cell><fo:block font-weight="bold">Employee</fo:block></fo:table-cell>
<fo:table-cell><fo:block font-weight="bold">Department</fo:block></fo:table-cell>
<fo:table-cell><fo:block font-weight="bold">Salary</fo:block></fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<?for-each:EMPLOYEES?>
<fo:table-row>
<fo:table-cell><fo:block><?EMPLOYEE_NAME?></fo:block></fo:table-cell>
<fo:table-cell><fo:block><?DEPT_NAME?></fo:block></fo:table-cell>
<fo:table-cell text-align="right"><fo:block><?SALARY?></fo:block></fo:table-cell>
</fo:table-row>
<?end for-each?>
</fo:table-body>
</fo:table>