With the report capabilities of Imixs Workflow it is possible to generate PDF files from a process instance using the XML and Rest API. A description and examples of how to generate a PDF Template can be found here.
With the latest Version of the Imixs Rest API it is now also possible to embed HTML output into a PDF file generated using xsl-fo. The Report-Plugin from Imixs-Workflow now preserve embedded HTML and XML structures in a workitem property if the name of the property starts with ‘html’ or ‘xml’.
To transform the HTML block (which have to be well formed XHTML) inside xsl-fo for each html tag a fo template can be applied in the xsl template.
This is a short example how to use this template technique:
<?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:output encoding="UTF-8" method="xml" indent="yes" /> <xsl:strip-space elements="*" /> <xsl:param name="font-size" select="''" /> <xsl:param name="font.symbol" select="'Arial Unicode MS'" /> <xsl:template match="/"> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> <fo:simple-page-master master-name="A4" page-width="210mm" page-height="297mm"> <fo:region-body region-name="xsl-region-body" margin="20mm" /> </fo:simple-page-master> <fo:simple-page-master master-name="A4-landscape" page-width="297mm" page-height="210mm"> <fo:region-body region-name="xsl-region-body" margin="20mm" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4"> <fo:flow flow-name="xsl-region-body"> <fo:block space-after="20mm"> <fo:block text-align="end" font-size="16pt" font-weight="bold"> <fo:inline> HTML - PDF - Example </fo:inline> </fo:block> </fo:block> <fo:block> <fo:block font-weight="bold">Text Output:</fo:block> <fo:block> <xsl:value-of select="/collection/entity[normalize-space(item[name = 'txtworkflowgroup']/value) = 'Frage']/item[name='txtname']/value" /> </fo:block> <!-- format html output --> <fo:block font-weight="bold">HTML Output:</fo:block> <fo:block> <xsl:apply-templates select="/collection/entity[normalize-space(item[name = 'txtworkflowgroup']/value) = 'Frage']/item[name='htmlanswer']/value" /> </fo:block> </fo:block> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="/collection/entity[normalize-space(item[name = 'txtworkflowgroup']/value) = 'Frage']/item[name='htmlanswer']/value"> <xsl:apply-templates /> </xsl:template> <!-- html format --> <xsl:template match="p"> <fo:block> <fo:inline> <xsl:text disable-output-escaping="yes"> <xsl:apply-templates /> </xsl:text> </fo:inline> </fo:block> </xsl:template> <xsl:template match="b|strong"> <fo:inline font-weight="bold"> <xsl:apply-templates /> </fo:inline> </xsl:template> <xsl:template match="table"> <fo:table table-layout="auto" width="100%"> <fo:table-body> <xsl:apply-templates /> </fo:table-body> </fo:table> </xsl:template> <xsl:template match="tr"> <fo:table-row> <xsl:apply-templates /> </fo:table-row> </xsl:template> <xsl:template match="td"> <fo:table-cell> <fo:block> <xsl:apply-templates /> </fo:block> </fo:table-cell> </xsl:template> <xsl:template match="address"> <fo:block font-style="italic"> <xsl:apply-templates /> </fo:block> </xsl:template> <xsl:template match="blockquote"> <fo:block space-before="1em" space-after="1em" start-indent="3em" end-indent="3em"> <xsl:apply-templates /> </fo:block> </xsl:template> <xsl:template match="caption"> <fo:block keep-with-next="always" text-align="center"> <xsl:apply-templates /> </fo:block> </xsl:template> <xsl:template match="center"> <fo:block text-align="center"> <xsl:apply-templates /> </fo:block> </xsl:template> <xsl:template match="div|multicol|noembed|noframes |nolayer|noscript"> <fo:block> <xsl:apply-templates /> </fo:block> </xsl:template> <xsl:template match="h1"> <fo:block font-size="180%" font-weight="bold"> <xsl:apply-templates /> </fo:block> </xsl:template> <xsl:template match="h2"> <fo:block font-size="160%" font-weight="bold"> <xsl:apply-templates /> </fo:block> </xsl:template> <xsl:template match="h3"> <fo:block font-size="140%" font-weight="bold"> <xsl:apply-templates /> </fo:block> </xsl:template> <xsl:template match="h4"> <fo:block font-size="120%" font-weight="bold"> <xsl:apply-templates /> </fo:block> </xsl:template> <xsl:template match="h5"> <fo:block font-size="110%" font-weight="bold"> <xsl:apply-templates /> </fo:block> </xsl:template> <xsl:template match="br"> <fo:block white-space="pre"> <xsl:text disable-output-escaping="yes"> </xsl:text> </fo:block> </xsl:template> <xsl:template match="ol"> <fo:list-block provisional-label-separation=".2em" provisional-distance-between-starts="{string-length(count(li))*.9+.6}em"> <xsl:apply-templates /> </fo:list-block> </xsl:template> <xsl:template match="ol/li"> <fo:list-item> <fo:list-item-label end-indent="label-end()"> <fo:block text-align="end"> <xsl:variable name="value"> <xsl:choose> <xsl:when test="@value"> <xsl:value-of select="@value" /> </xsl:when> <xsl:otherwise> <xsl:number /> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="@type='I'"> <xsl:number format="I" value="$value" /> </xsl:when> <xsl:when test="@type='A'"> <xsl:number format="A" value="$value" /> </xsl:when> <xsl:when test="@type='i'"> <xsl:number format="i" value="$value" /> </xsl:when> <xsl:when test="@type='a'"> <xsl:number format="a" value="$value" /> </xsl:when> <xsl:when test="parent::ol/@type='I'"> <xsl:number format="I" value="$value" /> </xsl:when> <xsl:when test="parent::ol/@type='I'"> <xsl:number format="A" value="$value" /> </xsl:when> <xsl:when test="parent::ol/@type='I'"> <xsl:number format="i" value="$value" /> </xsl:when> <xsl:when test="parent::ol/@type='I'"> <xsl:number format="a" value="$value" /> </xsl:when> <xsl:otherwise> <xsl:number format="1" value="$value" /> </xsl:otherwise> </xsl:choose> <xsl:text>.</xsl:text> </fo:block> </fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> <xsl:apply-templates /> </fo:block> </fo:list-item-body> </fo:list-item> </xsl:template> <xsl:template match="ul|menu"> <fo:list-block provisional-label-separation=".2em" provisional-distance-between-starts="1.6em"> <xsl:apply-templates /> </fo:list-block> </xsl:template> <xsl:template match="ul/li|menu/li"> <fo:list-item> <fo:list-item-label end-indent="label-end()"> <fo:block text-align="end"> <fo:inline font-family="{$font.symbol}"> <xsl:choose> <xsl:when test="@type='square'"> <xsl:text disable-output-escaping="yes">▪</xsl:text> </xsl:when> <xsl:when test="@type='circle'"> <xsl:text disable-output-escaping="yes">○</xsl:text> </xsl:when> <xsl:when test="parent::ul/@type='square'"> <xsl:text disable-output-escaping="yes">▪</xsl:text> </xsl:when> <xsl:when test="parent::ul/@type='circle'"> <xsl:text disable-output-escaping="yes">○</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text disable-output-escaping="yes">•</xsl:text> </xsl:otherwise> </xsl:choose> </fo:inline> </fo:block> </fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> <xsl:apply-templates /> </fo:block> </fo:list-item-body> </fo:list-item> </xsl:template> <xsl:template match="font"> <fo:inline> <xsl:choose> <xsl:when test="@size=1"> <xsl:attribute name="font-size">xx-small</xsl:attribute> </xsl:when> <xsl:when test="@size=2"> <xsl:attribute name="font-size">x-small</xsl:attribute> </xsl:when> <xsl:when test="@size=3"> <xsl:attribute name="font-size">small</xsl:attribute> </xsl:when> <xsl:when test="@size=4"> <xsl:attribute name="font-size">medium</xsl:attribute> </xsl:when> <xsl:when test="@size=5"> <xsl:attribute name="font-size">large</xsl:attribute> </xsl:when> <xsl:when test="@size=6"> <xsl:attribute name="font-size">x-large</xsl:attribute> </xsl:when> <xsl:when test="@size=7"> <xsl:attribute name="font-size">xx-large</xsl:attribute> </xsl:when> </xsl:choose> <xsl:if test="@face"> <xsl:attribute name="font-family"><xsl:value-of select="@face" /></xsl:attribute> </xsl:if> <xsl:apply-templates /> </fo:inline> </xsl:template> <xsl:template match="small"> <fo:inline font-size="smaller"> <xsl:apply-templates /> </fo:inline> </xsl:template> <xsl:template match="span"> <xsl:choose> <xsl:when test="self::node()[contains(@style,'underline')]"> <fo:inline text-decoration="underline"> <xsl:apply-templates /> </fo:inline> </xsl:when> <xsl:otherwise> <fo:inline> <xsl:apply-templates /> </fo:inline> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="sub"> <fo:inline baseline-shift="sub"> <xsl:apply-templates /> </fo:inline> </xsl:template> <xsl:template match="sup"> <fo:inline baseline-shift="super"> <xsl:apply-templates /> </fo:inline> </xsl:template> <xsl:template match="ins|u"> <fo:inline text-decoration="underline"> <xsl:apply-templates /> </fo:inline> </xsl:template> </xsl:stylesheet>
A complete example of a xsl-fo template for html tags can be found here.
Entity Encoding!
If you need to parse XML content make sure that this content did not contain HTML encoded characters like ä – this entities contained in the xml source can not be processed by the XSL processor. You need to work with raw utf-8 or unicode encoded characters. For example:
"ä" or "ä" works, but "ä" wont work!
As we are using TinyMCE Edtior in most of our web applications we need to set the “raw” format to initialize TinyMCE. Otherwise characters will be HTML encoded!
$('textarea.imixs-editor') .tinymce( { .... .... // set entity encoding entity_encoding: "raw" }); }