简体   繁体   中英

How to detect overflow or line breaks in XSL-FO document rendered with Apache FOP

I have a very simple FO document:

<?xml version="1.0" encoding="UTF-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">

<fo:layout-master-set>
  <fo:simple-page-master master-name="A4">
    <fo:region-body margin-top="30mm" />
  </fo:simple-page-master>
</fo:layout-master-set>

<fo:page-sequence master-reference="A4">
  <fo:flow flow-name="xsl-region-body">
    <fo:block-container height="10mm" font-size="8mm" overflow="error-if-overflow" wrap-option="wrap">
      <fo:block wrap-option="wrap">Hello W3Schools Hello W3Schools Hello W3Schools sad da sadasd dsaasd</fo:block>
    </fo:block-container>
  </fo:flow>
</fo:page-sequence>
</fo:root>

Having overflow set to error-if-overflow , I'll get an error rendering this document. Is there any way of detecting the place of overflow in the text? I'd like to be able to brake this text into many by hand, but I don't like idea of removing one word at a time and reruning rendering just to see if it failes again.

The exception that is get is:

Content overflows the viewport of an fo:block-container in block-progression direction by 26078 millipoints. Content will be clipped. (See position 12:103)

Unfortunatelly this is the position of block-container tag in which the error occured and not a specific word that created overflow.

tl;dr version:

Instead of creating a PDF output, you can use the FOP's "intermediate format" feature to create an XML representation of the generated pages and areas.

You can then use it as an input to

  • check whether an overflow happened or not
  • check how many characters (and / or which text ) would be placed in the first line, so that you can modify the input file by hand
  • automatically rewrite your input file so that the text that would overflow is placed in a different block instead (this is going to be less trivial)

More details:

You can create the Area Tree (AT) output from the command line using

fop input.fo -at application/pdf at.xml

or you can create the Intermediate Format (IF) output with

fop input.fo -if application/pdf if.xml

( FOP's site has details about how to programmatically produce the intermediate format output using Java code).

For example, if your input FO file contains

<!--
there is no need for the wrap-option="wrap" attributes, as that is the default value, 
I added an id attribute on the fo:block-container
-->
<fo:block-container id="foo" height="10mm" font-size="8mm" overflow="error-if-overflow">
  <fo:block>Hello W3Schools Hello W3Schools Hello W3Schools sad da sadasd dsaasd</fo:block>
</fo:block-container>

the IF output (which is less verbose than the AT one) is like this:

...
<page index="0" name="1" page-master-name="A4" width="594720" height="792000">
    <page-header/>
    <content>
        <viewport transform="translate(0,85039)" width="594720" height="706961">
            <viewport width="594720" height="28346" clip-rect="0 0 594720 28346">
                <font family="sans-serif" style="normal" weight="400" variant="normal" size="22677" color="#000000"/>
                <id name="foo"/>
                <text x="0" y="19400">Hello W3Schools Hello W3Schools Hello W3Schools sad</text>
                <text x="0" y="46612">da sadasd dsaasd</text>
            </viewport>
        </viewport>
    </content>
    <page-trailer/>
</page>
...

and the XPath //viewport[id[@name = 'foo']]/text[1] gives you the text content of the first line.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM