Category Archives: Tutorial

Generate dynamic documents

A howto on generating dynamic documents with Java / JEE.

PDF
Using FOP of Apache PDF documents can be generated. For this you need a XSL-FO. A .fo file can be migrated to a XSL-FO file by including it’s content in a stylesheet:

<?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"
xmlns:html="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="xsl">

<xsl:template match="/">
<! -- Content FO file (fo:root)-->
</xsl:template>

Following a example of a XSL-FO file for a A4 letter. Copying the complete content of the fo:root node will result in a .fo file. For all regions templates are defined which can be implemented through the templates. In the following example a difference can be made on the position (first page or the rest of the page).

<?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"
xmlns:html="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="bi">

< !--  elements without a namespace-prefix in the input xml need to be matched as local-name() to work in the studio and in a
deployed app! -->

< !-- $debug='true' shows errors in not matching placeholders-->
<xsl:param name="debug">false</xsl:param>

< !-- attributes used to fill placeholders-->
<xsl:template match="bi:attribute-set-document-part"/>

<xsl:template match="bi:label"/>

<xsl:template match="bi:document-data">
< !-- margins -->
<xsl:param name="page-height-cm" select="'29.7'"/>
<xsl:param name="page-width-cm" select="'21'"/>

<xsl:param name="page-margin-top-cm" select="'2'"/>
<xsl:param name="page-margin-bottom-cm" select="'1'"/>
<xsl:param name="page-margin-left-cm" select="'2'"/>
<xsl:param name="page-margin-right-cm" select="'0'"/>

<xsl:param name="body-margin-top-cm" select="'0'"/>
<xsl:param name="body-margin-bottom-cm" select="'1'"/>
<xsl:param name="body-margin-left-cm" select="'0'"/>
<xsl:param name="body-margin-right-cm" select="'0'"/>

<!-- calculated margins -->
<xsl:variable name="body-width-cm" select="$page-width-cm -
($body-margin-left-cm + $body-margin-right-cm +
$page-margin-left-cm + $page-margin-right-cm)"/>
<xsl:variable name="body-height-cm" select="$page-height-cm -
($body-margin-top-cm + $body-margin-bottom-cm +
$page-margin-top-cm + $page-margin-bottom-cm)"/>

< !-- page layout -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="first" margin-right="{$page-margin-right-cm}cm"
margin-left="{$page-margin-left-cm}cm"
margin-bottom="{$page-margin-bottom-cm}cm"
margin-top="{$page-margin-top-cm}cm"
page-width="{$page-width-cm}cm"
page-height="{$page-height-cm}cm">
<fo:region-body margin-right="{$body-margin-right-cm}cm"
margin-left="{$body-margin-left-cm}cm"
margin-bottom="{$body-margin-bottom-cm}cm"
margin-top="{$body-margin-top-cm}cm"/>
<fo:region-before region-name="xsl-region-before-first" extent="{$body-margin-top-cm}cm"/>
<fo:region-after extent="{$body-margin-bottom-cm}cm"/>
<fo:region-start extent="{$body-margin-left-cm}cm"/>
<fo:region-end extent="{$body-margin-right-cm}cm"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="rest" margin-right="{$page-margin-right-cm}cm"
margin-left="{$page-margin-left-cm}cm"
margin-bottom="{$page-margin-bottom-cm}cm"
margin-top="{$page-margin-top-cm}cm"
page-width="{$page-width-cm}cm"
page-height="{$page-height-cm}cm">
<fo:region-body margin-right="{$body-margin-right-cm}cm"
margin-left="{$body-margin-left-cm}cm"
margin-bottom="{$body-margin-bottom-cm}cm"
margin-top="{$body-margin-top-cm}cm"/>
<fo:region-before region-name="xsl-region-before" extent="{$body-margin-top-cm}cm"/>
<fo:region-after extent="{$body-margin-bottom-cm}cm"/>
<fo:region-start extent="{$body-margin-left-cm}cm"/>
<fo:region-end extent="{$body-margin-right-cm}cm"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="a4">
<fo:repeatable-page-master-alternatives>
<fo:conditional-page-master-reference page-position="first"
master-reference="first"/>
<fo:conditional-page-master-reference page-position="rest"
master-reference="rest"/>
</fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="a4" force-page-count="no-force" initial-page-number="1"  format="1">

< !-- static content-->
<fo:static-content flow-name="xsl-region-before-first">
<fo:block>
<xsl:apply-templates select="." mode="header_first">
<xsl:with-param name="body-width-cm" select="$body-width-cm"/>
</xsl:apply-templates>
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-before">
<fo:block>
<xsl:apply-templates select="." mode="header">
<xsl:with-param name="body-width-cm" select="$body-width-cm"/>
</xsl:apply-templates>
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
<fo:block>
<xsl:apply-templates select="." mode="footer">
<xsl:with-param name="body-width-cm" select="$body-width-cm"/>
</xsl:apply-templates>
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-start">
<fo:block>
<xsl:apply-templates select="." mode="left-margin">
<xsl:with-param name="body-height-cm" select="$body-height-cm"/>
</xsl:apply-templates>
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-end">
<fo:block>
<xsl:apply-templates select="." mode="right-margin">
<xsl:with-param name="body-height-cm" select="$body-height-cm"/>
</xsl:apply-templates>
</fo:block>
</fo:static-content>

<fo:flow flow-name="xsl-region-body" font-size="9pt">
< !-- body -->

<fo:block id="last-page"/>
</fo:flow>

</fo:page-sequence>
</fo:root>
</xsl:template>

< !-- default static content, these templates can be overruled in letter-specific stylesheets-->
<xsl:template match="bi:document-data" mode="header"/>
<xsl:template match="bi:document-data" mode="header_first"/>
<xsl:template match="bi:document-data" mode="left-margin"/>
<xsl:template match="bi:document-data" mode="right-margin"/>

<xsl:template match="bi:document-data" mode="footer">
<xsl:param name="body-width-cm"/>
<xsl:variable name="column-width" select="$body-width-cm div 2"/>
< !-- CONTENT -->
</xsl:template>

Images
Images can be inserted as a jpg through converting the image to base64 with the following converter:
 http://www.askapache.com/online-tools/base64-image-converter/

Ant script
Developing a XSL-FO can be very time consuming. Therefore you should be to test the stylesheet rapidly. This can be done through testing the stylesheet against a sample XML file and processing this with a Ant script. A command line call can also be used.

The following Ant script has one target for processing a *.fo file and one for processing a XML against a XSL-FO file.

<?xml version="1.0"?>
<project name="xslfo-gen" default="generate-pdf" basedir=".">

<!-- source: http://xmlgraphics.apache.org/fop/0.95/anttask.html -->
<property name="fop.home.1.0" value="C:\CORNERS\PROGRAMS\fop\fop-1.0"/>
<property name="fop.home.0.20.5" value="C:\CORNERS\PROGRAMS\fop\fop-0.20.5"/>

<property name="docroot" value="C:\CORNERS\PROJECTDOCUMENTS\BeInformed"/>

<taskdef name="fop"
classname="org.apache.fop.tools.anttasks.Fop">
<classpath>
<fileset dir="${fop.home.1.0}/lib">
<include name="*.jar"/>
</fileset>
<fileset dir="${fop.home.1.0}/build">
<include name="fop.jar"/>
<include name="fop-hyph.jar" />
</fileset>
</classpath>
</taskdef>

<target name="generate-pdf-from-fo" description="Generates a single PDF file">
<fop format="application/pdf"
fofile="C:\CORNERS\PROGRAMS\fop\fop-1.0\examples\fo\basic\border.fo"
outfile="c:\pdfDocument.pdf" />
</target>

<target name="generate-pdf-from-xml" description="Generates a single PDF file from XML">
<java classname="org.apache.fop.apps.Fop" fork="yes" >
<classpath>
<fileset dir="${fop.home.0.20.5}">
<include name="*.jar"/>
</fileset>
</classpath>
<arg line="-d"/>
<arg line="-xsl C:\CORNERS\PROJECTDOCUMENTS\BeInformed\XML\StylesheetOntvangsbevestiging.xsl"/>

<arg line="-xml C:\CORNERS\PROJECTDOCUMENTS\BeInformed\XML\ontvangsbevestiging.xml"/>
<arg line="-pdf C:\CORNERS\PROJECTDOCUMENTS\BeInformed\generated.pdf"/>
</java>
</target>
</project>

Word
Generate WordXml from the Microsoft Word application and include this in a xsl(t) stylesheet. Replace the dynamic parts with XPath queries based on a XML file.

The following primer can be used;
# http://rep.oio.dk/Microsoft.com/officeschemas/wordprocessingml_article.htm

== Ant script ==
The following Ant script a target for processing a WordXML file against an XML file. The lib in the fileset of the classpath needs to contain the xalan libraries.


<target name="generateXalanWordDocument">
 <java classname="org.apache.xalan.xslt.Process" fork="yes" >
 <classpath>
 <fileset dir="C:\CORNERS\IDE\ECLIPSE\WORKSPACE\eintake_4.12-development\lib">
 <include name="*.jar"/>
 </fileset>
 </classpath>

<!-- WORD -->
 <arg line="-xsl C:\CORNERS\PROJECTDOCUMENTS\BeInformed\XML\StylesheetWordOntwerpbeschikking.xsl"/>
 <arg line="-in C:\CORNERS\PROJECTDOCUMENTS\BeInformed\XML\xmlontwerpbeschikking.xml"/>
 <arg line="-out C:\CORNERS\PROJECTDOCUMENTS\BeInformed\test.doc"/>
 </java>

</target>

= Excel =
JExcel api; for reading and writing excel documents

= OpenOffice =
ODF4J which has been superseeded by ODFDOM.

= Sources =
# http://xmlgraphics.apache.org/fop/
# http://jexcelapi.sourceforge.net/
# http://odftoolkit.org/projects/odfdom/pages/Home
# http://wiki.services.openoffice.org/wiki/Odf4j
# http://xmlgraphics.apache.org/fop/1.0/anttask.html