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