Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSL-FO leader wrapping

I have a list of data with a dotted leader separating text aligned to the left and to the right. I'm using the following XSL-FO to achieve this.

<fo:block text-align-last="justify">
    <xsl:value-of select="left-text"/>
    <fo:leader leader-pattern="dots"/>
    <xsl:value-of select="right-text"/>
</fo:block>
Some text on the left............................some text on the right

This works perfectly when the text all fits onto one line. The issue I'm having is correctly handling how the text on the right wraps onto a new line. I have a specific requirement for it to be formatted with the wrapped text staying aligned to the right as below:

Some text on the left.................a long piece of text on the right 
                                                       that has wrapped

I tried to achieve this with leaders and tables but to no avail. I'm using the Antenna House formatter. Any advice is very welcome. Thanks for you help.

like image 958
Peter Avatar asked Dec 26 '22 06:12

Peter


2 Answers

Use this as inspiration and set your own rules:

       <fo:block text-align="justify" text-align-last="right">
           <fo:inline>Some text on the left</fo:inline>
           <fo:leader leader-pattern="dots" leader-length.minimum="2in" leader-length.optimum="2in" leader-length.maximum="3in"/>
           <fo:inline>a long piece of text on the right that has wrapped</fo:inline>
       </fo:block>
        <fo:block text-align="justify" text-align-last="right">
           <fo:inline>Some text</fo:inline>
           <fo:leader leader-pattern="dots" leader-length.minimum="2in" leader-length.optimum="2in" leader-length.maximum="3in"/>
           <fo:inline>a long piece of text on the right that has wrapped and is even longer</fo:inline>
       </fo:block>

The only things you will not be able to stop is a right hand line so long that it comes underneath the dots, but you have not specified that as a requirement. If that is, I am afraid there is no solution for that. Also if a line is too short, it would be right aligned. You have to use the min/max values to only force a wrap.

If you know the font size you could count the characters in the left/right elements and then call your template or this sample depending on the total characters.

Result of this FO

And for the count, you can do something like this template where the "50" characters you can adjust with the leader-length to get the correct results.

<xsl:template name="processitem">
    <xsl:choose>
        <xsl:when test="string-length(left) + string-length(right) > 50">
            <fo:block text-align="justify" text-align-last="right">
                <fo:inline><xsl:value-of select="left"/></fo:inline>
                <fo:leader leader-pattern="dots" leader-length.minimum="2in" leader-length.optimum="2in" leader-length.maximum="4in"/>
                <fo:inline><xsl:value-of select="right"/></fo:inline>
            </fo:block>
        </xsl:when>
        <xsl:otherwise>
            <fo:block text-align-last="justify">
                <fo:inline><xsl:value-of select="left"/></fo:inline>
                <fo:leader leader-pattern="dots"/>
                <fo:inline><xsl:value-of select="right"/></fo:inline>
            </fo:block>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

With some sample data, I got this to render:

Using Template Above with Sample Data

like image 160
Kevin Brown Avatar answered Jan 05 '23 23:01

Kevin Brown


You can use an fo:inline-container (https://www.w3.org/TR/xsl11/#fo_inline-container) and the max-width property (https://www.w3.org/TR/xsl11/#max-width) to limit the width of any long text on the right.

This example uses the axf:text-align-first="justify" extension (see https://www.antennahouse.com/product/ahf66/ahf-ext.html#axf.text-align-first) to justify the first line. You could instead use the axf:leader-expansion="force" extension (see https://www.antennahouse.com/product/ahf66/ahf-ext.html#axf.leader-expansion). Without either of those, I think that your only other alternative is to guesstimate the leader-length.optimum of the second fo:leader.

Note that the example below has no significant white-space characters between the two fo:leader. This avoids a gap between the two leaders when they are formatted.

<fo:block text-align="justify">
  <fo:inline>Some text</fo:inline><fo:leader
  leader-pattern="dots" leader-length.optimum="100%"
  leader-alignment="end"
  /><fo:inline-container
  max-width="1.5in" text-align="right"
  axf:text-align-first="justify" >
          <fo:block><fo:leader leader-pattern="dots"
  leader-length.minimum="0" />a long piece of text on the right that has wrapped
and is even longer</fo:block>
  </fo:inline-container>
</fo:block>

Example of multiple lines of right-justified text after a leader.

like image 25
Tony Graham Avatar answered Jan 05 '23 22:01

Tony Graham