xsl:fo inline line wrap and line break

Linefeeds can be present in an FO document as linefeed characters or numeric character entities (
 or 
); the following FO blocks are completely equivalent:

<fo:block>Before the linefeed&#x000A;after the linefeed.</fo:block>

<fo:block>Before the linefeed
after the linefeed.</fo:block>

The default handling of linefeeds consists in:

  1. converting them into normal spaces;
  2. collapsing them with other adjacent spaces.

This explains why your initial input produces an output where all the content pieces are placed consecutively on the same line.

Using the property linefeed-treatment="preserve" both forms of linefeeds are retained, and the line building process will respect them (they are called forced line-breaks). Note that linefeed-treatment only applies to fo:block elements; it has no effect on fo:inline elements.

Your "edit 1" block has more linefeeds than you need because "... Second Line, Image: ", the image and "some more Text on Line 2 ..." are inside three different fo:block elements, and each block generates its own lines.

Solution 1:

The simplest way to get your desired output is probably this one, with a single fo:block having its linefeed preserved (this is just your original input, after removing the unnecessary fo:inlines and putting everything on the same line:

<fo:block linefeed-treatment="preserve">First Line&#xA;Second Line, Image: <fo:external-graphic scaling="non-uniform" content-height="scale-to-fit" content-width="4mm" height="4mm" src="data:image;base64,iVBORw0KGgoAAAANSUhEUgAAAGcAAABfCAIAAAB6Ck5uAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAA0SURBVHhe7cGBAAAAAMOg+VNf4QBVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHCoAXMKAAFau+l4AAAAAElFTkSuQmCC"/> some more Text on Line 2&#10;3rd Line</fo:block>

Note that you cannot indent this code, because the extra linefeeds would appear in the output too!

Solution 2:

A second solution, which doesn't involve using the linefeed-treatment property and creates more easily readable code, would be to use empty blocks instead of forced linefeeds:

<fo:block>
    First Line<fo:block/>Second Line, Image: 
    <fo:external-graphic scaling="non-uniform" content-height="scale-to-fit" content-width="4mm" height="4mm" src="data:image;base64,iVBORw0KGgoAAAANSUhEUgAAAGcAAABfCAIAAAB6Ck5uAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAA0SURBVHhe7cGBAAAAAMOg+VNf4QBVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHCoAXMKAAFau+l4AAAAAElFTkSuQmCC"/> 
    some more Text on Line 2<fo:block/>3rd Line
</fo:block>

As linefeeds are not preserved, we can use them freely:

<fo:block>
    First Line
    <fo:block/>
    Second Line, Image: 
    <fo:external-graphic scaling="non-uniform" content-height="scale-to-fit" content-width="4mm" height="4mm" src="data:image;base64,iVBORw0KGgoAAAANSUhEUgAAAGcAAABfCAIAAAB6Ck5uAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAA0SURBVHhe7cGBAAAAAMOg+VNf4QBVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHCoAXMKAAFau+l4AAAAAElFTkSuQmCC"/> 
    some more Text on Line 2
    <fo:block/>
    3rd Line
</fo:block>

The empty blocks partition the content of the outer block without creating anything in the output.


Just found the answer in the comments of FOP 1536.

Now I'm using

linefeed-treatment="preserve"

on the block element and I'm replacing all spaces within the text inlines with some unicode magic in the xsl before:

replace(@text, ' ', '&#x00A0;&#x200B;') 

Edit 1: To be a bit more precise, this is the relevant part of the xsl I'm using:

<!DOCTYPE xsl:stylesheet [ 
    <!ENTITY nbsp "&#160;">
    <!ENTITY ZeroWidthSpace "&#x200B;"> 
]>

<fo:block linefeed-treatment="preserve">
    <fo:inline><xsl:value-of select="replace(@text, ' ', '&nbsp;&ZeroWidthSpace;')"/></fo:inline>
</fo:block>

With this approach I'm getting a pretty clean indented xml while having full control over linebreaks and blank spaces.