1
votes

Issue
I'm using XSL-T (v1.0) and XSL-FO (Apache FOP 1.0) to produce PDF (A4) reports using data from forms filled by user in a third-party software (that output XML).

The forms contains text areas users can fill as they want (no control over the content size). The text area content is then outputed in an XML as a node/text() (<textArea> ** content: user input ** </textArea>). To preserve users input formatting, I use linefeed-treatment = "preserve" attribute at the block-level.

Problem is, whenever text areas are filled with enough data to cause a page break, I have a nullPointerException with Apache FOP 1.0 when the page-break occurs on a line-break. I can't find any solution to the problem except using a keep-together.within-page = "always" as a workaround (not a long-term solution as I loose data when text() is longer than one page.

Tools
To develop XSL Stylesheet, I'm using:

  • XSLT Engine: Altova (built-in RaptorXML XSLT engine) with XSLT v1.0
  • FOP Processor: Apache FOP 1.0

I don't have a choice regarding what the software uses to generate PDF with the XSL Stylesheet (stuck with FOP 1.0 and XSLT 1.0).

Context
To produce reports based on user inputs within their forms, the software allows to link an XSL Stylesheet to each kind of form. It then uses Apache FOP 1.0 and an unknown XSLT engine to apply the XSL stylesheet to the XML output. I'm in charge of building those XSL Stylesheet for each kind of forms and I'm stuck with that issue.

Below is the error outputed by FOP and the XSL-FO (trimmed and complete) issuing the error.


Part of XSL-FO causing the issue

<fo:block space-before="5mm" text-align="justify">
                <fo:block linefeed-treatment="preserve" keep-together.within-page="auto">
                    <fo:block>
                        <fo:inline/>
                        <fo:inline> TEST
END OF TEST </fo:inline>
                    </fo:block>
                </fo:block>
            </fo:block>

Error verbose

Standard Error
        Jun 29, 2018 9:02:59 AM org.apache.fop.cli.Main startFOP
        SEVERE: Exception
        org.apache.fop.apps.FOPException
        java.lang.NullPointerException
            at org.apache.fop.cli.InputHandler.transformTo(InputHandler.java:302)
            at org.apache.fop.cli.InputHandler.renderTo(InputHandler.java:130)
            at org.apache.fop.cli.Main.startFOP(Main.java:174)
            at org.apache.fop.cli.Main.main(Main.java:205)
        Caused by: java.lang.NullPointerException
            at org.apache.fop.layoutmgr.AbstractBreaker.doLayout(AbstractBreaker.java:434)
            at org.apache.fop.layoutmgr.PageBreaker.doLayout(PageBreaker.java:85)
            at org.apache.fop.layoutmgr.PageSequenceLayoutManager.activateLayout(PageSequenceLayoutManager.java:107)
            at org.apache.fop.area.AreaTreeHandler.endPageSequence(AreaTreeHandler.java:238)
            at org.apache.fop.fo.pagination.PageSequence.endOfNode(PageSequence.java:120)
            at org.apache.fop.fo.FOTreeBuilder$MainFOHandler.endElement(FOTreeBuilder.java:349)
            at org.apache.fop.fo.FOTreeBuilder.endElement(FOTreeBuilder.java:177)
            at org.apache.xalan.transformer.TransformerIdentityImpl.endElement(TransformerIdentityImpl.java:1101)
            at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
            at org.apache.xerces.xinclude.XIncludeHandler.endElement(Unknown Source)
            at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanEndElement(Unknown Source)
            at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
            at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
            at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
            at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
            at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
            at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
            at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
            at org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:484)
            at org.apache.fop.cli.InputHandler.transformTo(InputHandler.java:299)
            ... 3 more

        ---------

        java.lang.NullPointerException
            at org.apache.fop.layoutmgr.AbstractBreaker.doLayout(AbstractBreaker.java:434)
            at org.apache.fop.layoutmgr.PageBreaker.doLayout(PageBreaker.java:85)
            at org.apache.fop.layoutmgr.PageSequenceLayoutManager.activateLayout(PageSequenceLayoutManager.java:107)
            at org.apache.fop.area.AreaTreeHandler.endPageSequence(AreaTreeHandler.java:238)
            at org.apache.fop.fo.pagination.PageSequence.endOfNode(PageSequence.java:120)
            at org.apache.fop.fo.FOTreeBuilder$MainFOHandler.endElement(FOTreeBuilder.java:349)
            at org.apache.fop.fo.FOTreeBuilder.endElement(FOTreeBuilder.java:177)
            at org.apache.xalan.transformer.TransformerIdentityImpl.endElement(TransformerIdentityImpl.java:1101)
            at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
            at org.apache.xerces.xinclude.XIncludeHandler.endElement(Unknown Source)
            at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanEndElement(Unknown Source)
            at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
            at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
            at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
            at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
            at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
            at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
            at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
            at org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:484)
            at org.apache.fop.cli.InputHandler.transformTo(InputHandler.java:299)
            at org.apache.fop.cli.InputHandler.renderTo(InputHandler.java:130)
            at org.apache.fop.cli.Main.startFOP(Main.java:174)
            at org.apache.fop.cli.Main.main(Main.java:205)

Complete XSL-FO before FOP

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <fo:layout-master-set>
        <fo:simple-page-master master-name="coverPage" margin="5mm" page-height="297mm" page-width="210mm" reference-orientation="0" writing-mode="lr-tb">
            <fo:region-body margin-top="25mm" margin-bottom="25mm" margin-left="45mm" margin-right="5mm"/>
            <fo:region-after extent="20mm" precedence="true" display-align="before"/>
            <fo:region-start extent="40mm"/>
        </fo:simple-page-master>
        <fo:simple-page-master master-name="repeatablePage" margin="5mm" page-height="297mm" page-width="210mm" reference-orientation="0" writing-mode="lr-tb">
            <fo:region-body margin-top="30mm" margin-bottom="25mm" margin-left="20mm" margin-right="20mm"/>
            <fo:region-after extent="20mm" precedence="true" display-align="before"/>
        </fo:simple-page-master>
        <fo:page-sequence-master master-name="pageSequence">
            <fo:single-page-master-reference master-reference="coverPage"/>
            <fo:repeatable-page-master-reference master-reference="repeatablePage" maximum-repeats="no-limit"/>
        </fo:page-sequence-master>
    </fo:layout-master-set>
    <fo:page-sequence master-reference="pageSequence" font-family="sans-serif" font-weight="normal">
        <fo:static-content flow-name="xsl-region-after">
            <fo:block text-align="right" font-size="10" color="#083E70">
                Page <fo:page-number/> de <fo:page-number-citation ref-id="endDoc"/></fo:block>
            <fo:block text-align="center" font-size="8" color="#083E70" space-before="8mm">
                <fo:block>ADRESSE LINE 1</fo:block>
                <fo:block>ADRESSE LINE 2</fo:block>
            </fo:block>
        </fo:static-content>
        <fo:static-content flow-name="xsl-region-start">
            <fo:block>
                <fo:external-graphic src="Logo.jpg" content-width="40mm" scaling="uniform"/>
            </fo:block>
            <fo:block-container color="#083E70" border-end-color="#083E70" border-end-width="1pt" border-end-style="solid" block-progression-dimension="235mm">
                <fo:block/>
                <fo:block space-before="10mm" space-after="10mm" font-weight="bold" text-decoration="underline"/>
            </fo:block-container>
        </fo:static-content>
        <fo:flow flow-name="xsl-region-body" font-size="10pt">
            <fo:block text-align="right" space-after="5mm">
                <fo:inline>Bruxelles, le </fo:inline>
                <fo:inline>19/06/2018</fo:inline>.
                    </fo:block>
            <fo:block space-after="10mm" border="0pt solid black" padding="2mm 0">
                <fo:table start-indent="3mm" space-after="10mm" table-layout="fixed" width="147mm">
                    <fo:table-column column-number="1" column-width="35mm"/>
                    <fo:table-column column-number="2" column-width="112mm"/>
                    <fo:table-body>
                        <fo:table-row>
                            <fo:table-cell>
                                <fo:block>
                                    <fo:inline font-weight="bold">
                                        <fo:inline>Destinataire:</fo:inline>
                                    </fo:inline>
                                </fo:block>
                            </fo:table-cell>
                            <fo:table-cell display-align="center">
                                <fo:block start-indent="40mm">Mara Kristen<fo:block/>5911 Maple Blvd<fo:block/>1400 NIVELLES<fo:block/>B<fo:block/></fo:block>
                            </fo:table-cell>
                        </fo:table-row>
                    </fo:table-body>
                </fo:table>
                <fo:table start-indent="3mm" table-layout="fixed" width="147mm">
                    <fo:table-column column-number="1" column-width="35mm"/>
                    <fo:table-column column-number="2" column-width="112mm"/>
                    <fo:table-body>
                        <fo:table-row>
                            <fo:table-cell>
                                <fo:block>
                                    <fo:inline font-weight="bold">
                                        <fo:inline>Copie:</fo:inline>
                                    </fo:inline>
                                </fo:block>
                            </fo:table-cell>
                            <fo:table-cell>
                                <fo:block>
                                    <fo:inline>Gold Denis</fo:inline>
                                    <fo:inline font-style="italic"> (Merci Denis !, 3001 HEVERLEE, B)</fo:inline>
                                </fo:block>
                            </fo:table-cell>
                        </fo:table-row>
                        <fo:table-row>
                            <fo:table-cell>
                                <fo:block/>
                            </fo:table-cell>
                            <fo:table-cell>
                                <fo:block>
                                    <fo:inline>Gold Denis</fo:inline>
                                    <fo:inline font-style="italic"> (Merci Denis !, 3001 HEVERLEE, B)</fo:inline>
                                </fo:block>
                            </fo:table-cell>
                        </fo:table-row>
                        <fo:table-row>
                            <fo:table-cell>
                                <fo:block/>
                            </fo:table-cell>
                            <fo:table-cell>
                                <fo:block>
                                    <fo:inline>Gold Denis</fo:inline>
                                    <fo:inline font-style="italic"> (Merci Denis !, 3001 HEVERLEE, B)</fo:inline>
                                </fo:block>
                            </fo:table-cell>
                        </fo:table-row>
                    </fo:table-body>
                </fo:table>
            </fo:block>
            <fo:block text-align="left" space-after="10mm"> 
            Ref.: 002956347</fo:block>
            <fo:block space-after="10mm" text-align="center" text-decoration="underline" font-weight="bold">
                <fo:inline>Lettre de consultation - </fo:inline>Psychiatrie</fo:block>
            <fo:block>
                <fo:inline>Concerne: </fo:inline>
            </fo:block>
            <fo:block space-after="10mm" border="1pt solid black" padding="2mm 0">
                <fo:table table-layout="fixed" start-indent="3mm" width="147mm">
                    <fo:table-column column-number="1" column-width="35mm"/>
                    <fo:table-column column-number="2" column-width="112mm"/>
                    <fo:table-body>
                        <fo:table-row>
                            <fo:table-cell>
                                <fo:block font-weight="bold">
                                    <fo:inline>Nom, Prénom:</fo:inline>
                                </fo:block>
                            </fo:table-cell>
                            <fo:table-cell>
                                <fo:block>Quigley, Jules</fo:block>
                            </fo:table-cell>
                        </fo:table-row>
                        <fo:table-row>
                            <fo:table-cell>
                                <fo:block font-weight="bold">
                                    <fo:inline>Adresse:</fo:inline>
                                </fo:block>
                            </fo:table-cell>
                            <fo:table-cell>
                                <fo:block>9816 Main Street,
                                1402 LOOL,
                                B</fo:block>
                            </fo:table-cell>
                        </fo:table-row>
                        <fo:table-row>
                            <fo:table-cell>
                                <fo:block font-weight="bold">
                                    <fo:inline>Nr. national:</fo:inline>
                                </fo:block>
                            </fo:table-cell>
                            <fo:table-cell>
                                <fo:block>31035622101</fo:block>
                            </fo:table-cell>
                        </fo:table-row>
                    </fo:table-body>
                </fo:table>
            </fo:block>
            <fo:block text-align="left">
                <fo:inline font-weight="bold" text-decoration="underline">
                    <fo:inline>Sujet:</fo:inline>
                </fo:inline> <fo:inline>
                    <fo:inline>Exemple</fo:inline>
                </fo:inline>
            </fo:block>
            <fo:block space-before="5mm" text-align="justify">
                <fo:block linefeed-treatment="preserve" keep-together.within-page="auto">
                    <fo:block>
                        <fo:inline/>
                        <fo:inline>TEST
























TEST</fo:inline>
                    </fo:block>
                </fo:block>
            </fo:block>
            <fo:block keep-together.within-page="always">
                <fo:block space-before="10mm" text-align="right">
                    <fo:inline text-decoration="underline">
                        <fo:inline>Signataire</fo:inline>
                    </fo:inline>
                    <fo:block/>
                    <fo:block>
                        <fo:inline>John SMITH</fo:inline>
                    </fo:block>
                    <fo:block>
                        <fo:inline>
                            <fo:inline>Nr. INAMI: </fo:inline>
                        </fo:inline>
                        <fo:inline>45632163140</fo:inline>
                    </fo:block>
                </fo:block>
            </fo:block>
            <fo:block id="endDoc"/>
        </fo:flow>
    </fo:page-sequence>
</fo:root>

EDIT
I've found a way to replace all the line-breaks with &#x00A0;<fo:block/> as suggested by @lfurini but it still produce de same NPE error.
Code used is shown below:

 <xsl:template name="gReplaceLineBreak">
        <xsl:param name="pString"/>
        <xsl:choose>
            <xsl:when test="substring-before($pString,'&#xA;')">
                <xsl:value-of select="substring-before($pString,'&#xA;')"/>&#x00A0;<fo:block/>
                <xsl:call-template name="gReplaceLineBreak">
                    <xsl:with-param name="pString" select="substring-after($pString,'&#xA;')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$pString"/>
                </xsl:otherwise>
            </xsl:choose>
    </xsl:template>  

EDIT-2
Ok I've finally found why it wasn't working with the above code. There was a <fo:inline> node enclosing all the <fo:block/>. Now that I removed it, it works as @lfurini said it would. Thanks a lot.

1

1 Answers

0
votes

This is a bug affecting every FOP version, including the latest one.

Here is a (very ugly) workaround:

  • remove the properties linefeed-treatment="preserve" keep-together.within-page="auto", as the former creates the error, and the latter would make the content overflow the page limits
  • replace linefeeds in that block with &#x00A0;<fo:block/> (non-breaking space, empty block, linefeed for readability only)

For example, the relevant block in your example would become:

            <fo:block space-before="5mm" text-align="justify">
                <fo:block>&#x00A0;<fo:block/>
                    <fo:block>&#x00A0;<fo:block/>
                        <fo:inline/>&#x00A0;<fo:block/>
TEST&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
&#x00A0;<fo:block/>
END OF TEST&#x00A0;<fo:block/>
                    </fo:block>&#x00A0;<fo:block/>
                </fo:block>
            </fo:block>

This works with FOP from 1.1 (couldn't test with 1.0 as it is not even available from the download page anymore) to the most recent 2.3.

How this could be achieved: in your XSLT stylesheet you should probably use a special mode to process user content from a text area, and for text nodes whose length is 0 produce &#x00A0;<fo:block/>.