XSL-FO leader wrapping - xslt

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.

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.
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:

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>

Related

Can you apply a stylesheet on grouping-separator in XSL?

In my template, I have defined a decimal format element, that later is used to format some of the numbers coming from the database.
It looks as below:
<xsl:decimal-format name="M" decimal-separator="," grouping-separator=" " infinity="-" minus-sign="-" NaN="-" percent="%" zero-digit="0" digit="#" pattern-separator=";" />
<fo:block font-family="Arial">
<xsl:value-of select="format-number(254768,'## ### ##0.00$','M')"/>
</fo:block>
</xsl:template>
With the above template, I will get the following result: 2 547.68$ .
The <fo:block> element has the same font-family, but it can be set as Regular, or as Bold(font-weight="bold"). When the font is Bold, the space between number 2 and number 5 will be higher, than the space between the same numbers when the font is Regular. I was looking for a way to decrease the space when font-weight is bold.
Is there any way I can apply a stylesheet and manage that space?
Thank you!

How can I strike text with custom thickness XSL:FO

I strike text with text-decoration="line-through", but I find out the thickness is not suitable.
<fo:inline text-decoration="line-through">
...
</fo:inline>
I tried to use but I can't find a way to overlay the text. Is there any way to adjust the thickness of the strike? Or a way to use fo:leader to do the same thing?
There is no property in XSL 1.1 for specifying the width of the text-decoration line. (FWIW, AH Formatter has an extension property for it: https://www.antennahouse.com/product/ahf66/ahf-ext.html#axf.text-line-width.)
Using fo:leader could be problematic because you might have trouble getting the width exactly right.
You might be able to do something with an fo:inline-container with a top or bottom border and playing tricks with the baseline shifts of the fo:inline-container and of the text in an fo:block within the fo:inline-container such that the fo:inline-container is lowered/raised to make the strike-through and the text is raised/lowered to be back on the original baseline.
You should be able to just set the padding-bottom to negative 1/2 the font-height coupled with a bottom-border. Like this if say the font-size is 24pt.
<fo:block>Testing line-through
<fo:inline text-decoration="line-through">
I have regular line-through
</fo:inline>
</fo:block>
<fo:block space-before="48pt">Testing line-through
<fo:inline border-bottom="5px solid black" padding-bottom="-12pt">
I have custom line-through
</fo:inline>
</fo:block>
This in RenderX results in:
Unfortunately nothing tried in FOP will work as it apparently does not respect any margin or padding settings on fo:inline.

Apache FOP: How to hide table-header from the first page only?

I have a document generated using Apache FOP with a multi-pages dynamic table that has a fo:table-header with the sum of items from the previous page using fo:marker and fo:retrieve-table-marker.
<fo:table-header>
<fo:table-row>
<--! column title cells here -->
</fo:table-row>
<fo:table-row>
<fo:table-cell number-columns-spanned="4">
<fo:block>Übertrag</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<fo:inline>
<fo:retrieve-table-marker retrieve-class-name="totalsMarkerHeader"
retrieve-position-within-table="last-ending-within-page"
retrieve-boundary-within-table="table"/>
</fo:inline>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:for-each select="items/item">
<fo:table-row page-break-inside="avoid">
<--! data table cells here -->
<fo:block>
<fo:marker marker-class-name="totalsMarkerHeader">
<xsl:value-of select="format-number(sum(preceding::total_price),'€#,##0.00')"/>
</fo:marker>
</fo:block>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
This works fine, except that on the first page this row is useless, I would like to remove it from the first page and have it on every other page of the document then.
What I am looking for is an option exactly opposite to the "omit-header-at-break" property of the fo:table.
I came across the following options of different rendering engines:
fpc: table-omit-header-at-start="true"
rx: table-omit-initial-header
... but couldn't find something that works with apache fop.
Is there a workaround to do something similar with Apache FOP and the standard XSL-FO?
I also tried to use a conditional visibility for the sum row in the header:
<xsl:if test="position() > 1">
<fo:table-row>
...
</fo:table-row>
</xsl:if>
Unfortunately it doesn't seem like the header condition is evaluated on every page, but is rather done once on the first page making the row invisible on all pages (not just the first page as I would have expected).
If the section of your document with this table can be isolated into a single page-sequence then:
1) Setup a page sequence with a different first page (so use first and any)
2) In the page template for all pages but the first, create a matching simple one row table in the region before, set to the very bottom so it lands on top of the table in your body. Carefully planned, you can make the little table in the header look like it is a "table-header" even though it is in the page header.
3) Obviously do not put any header on the first page and of course not on the table in the body unless you want to, you can put something completely different here because it would be the region-before of the first page.
4) The you can use regular markers to keep the running total and pull that marker into your table in the header on latter pages.
Add an empty fo:marker that will be picked up by the fo:retrieve-table-marker only on the first page.

My xsl-fo stylesheet don't add my page number prefix as expected

I'm trying to change the way the index page works by adding to it a number present in the xml. so in theory this is supposed to be made out of the box, but for some reason the output doesn't have my page-number prefix.
for example, if the node somethingElse has the value, 57 and is on the page 13 I want to have 57.13 displayed on the index but only 13 gets displayed.
I tried to change value-of/inline to a block conataining only a word test, but even that doesn't seem to work. So I can only assume that I'm not using index-page-number-prefix correctly...
What am I doing wrong ?
<fo:block>
<fo:inline font-weight="normal">
<fo:leader leader-pattern="dots"/>
<fo:index-page-citation-list>
<fo:index-key-reference ref-index-key="{.};{../title};;" font-weight="bold">
<fo:index-page-number-prefix>
<fo:inline>
<xsl:value-of select="ancestor::something/SomethigElse"/>.
</fo:inline>
</fo:index-page-number-prefix>
</fo:index-key-reference>
</fo:index-page-citation-list>
</fo:inline>
</fo:block>
fo:index-page-number-prefix is ignored by RenderX. See http://www.renderx.com/reference.html#XSL11_Support or, more specifically, http://www.renderx.com/reference.html#XSL11_Indexes.

XSL-FO : Block element wrong height

Im trying to surround and image with 2 vertical gray bar using XSL-FO. I created a vertical separator with 180*1 dimension, and i'm able to render it correctly in my XSL.
Problem is, the <fo:block> element is taking too much height, and i cant seem to find a workaround, see image below ( the red is the background of the <fo:block> element, while the thin grey line is my separator. I've had good result by wrapping the whole <fo-block> into a <fo:block-container> but the separator isnt centered, and i wasnt able to center it.
This is my code
<fo:block height='1px' background-color='#DE122D'>
<fo:external-graphic height='1px' content-width="scale-down-to-fit" src="url('images/verticalSeparator.png')" />
</fo:block>
I put a background color in order to be able to see how much height it was taking.
Ultimately i'm trying to achieve the 2nd screenshot, there might be other way to do this ( perhaps something with border ? ) and i'm willing to try them. Simply notice that the 2 vertical bars are longer than the image, and that the content must be centered !
I might not understand your question, but based on the code posted you imply the rule is the issue and make too much space. If the rule is your issue, possibly you want to use an alternative structure than an image. For this you could use a leader and set the length to what you want and have no issues centering it. The following code:
<fo:block text-align="center">Text Before</fo:block>
<fo:block text-align="center" font-size="1px" line-height="0"><fo:leader color="silver" leader-length="2in" leader-pattern="rule"/></fo:block>
<fo:block text-align="center">Text Between</fo:block>
<fo:block text-align="center" font-size="1px" line-height="0"><fo:leader color="silver" leader-length="2in" leader-pattern="rule"/></fo:block>
<fo:block text-align="center">Text After</fo:block>
Produces this output -- you can see no issues in spacing: