Multiple rows in freemarker and page break pdf - xslt

Suppose you have the following below. How I can wrap those in order to produce a page break if the rows don't fit on a page ?
<fo:table-body start-indent="0pt">
#loop here
<fo:table-row>
</fo:table-row>
<fo:table-row>
</fo:table-row>
<fo:table-row>
</fo:table-row>
# loop ends here
</fo:table-body>

Change:
<fo:table-body start-indent="0pt">
to:
<fo:table-body start-indent="0pt" keep-together.within-page="always">
See https://www.w3.org/TR/xsl11/#keep-together

Related

How to wirte a part of <fo:table> in a function

I have to create many <fo:table-row> in a <fo:table-body>. I think it's not nice if I write almost 5 lines of code several times (Maybe 50 times) to create the rows.
Like this:
<fo:table-body>
<fo:table-row>
<fo:table-cell padding-bottom="6pt">
<fo:value-of select="row1"/>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell padding-bottom="6pt">
<fo:value-of select="row2"/>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell padding-bottom="6pt">
<fo:value-of select="row3"/>
</fo:table-cell>
</fo:table-row>
....
</fo:table-body>
I tried to write a function that writes the <fo:table-row> for me. And I have to call the function every time and pass a parameter.
<xsl:function name="fn:createRow">
<xsl:param name="string1"/>
<fo:table-row>
<fo:table-cell padding-bottom="6pt">
<fo:value-of select="$string1"/>
</fo:table-cell>
</fo:table-row>
</xsl:function>
And now my XSLT look like this.
<fo:table-body>
<fo:block>
<fo:value-of select="fn:createRow('row1')"/>
<fo:value-of select="fn:createRow('row2')"/>
</fo:block>
</fo:table-body>
But I get the error:
"fo:block" is not a valid child of "fo:table-body"!
But when I work without <fo:block> I get nothing in the PDF:
<fo:table-body>
<fo:value-of select="fn:createRow('row1')"/>
<fo:value-of select="fn:createRow('row2')"/>
</fo:table-body>
Is there any opportunity to do it?
Thanks!
fo:table-cell can contain one or more block-level FOs, including fo:block. (See https://www.w3.org/TR/xsl11/#fo_table-cell)
You don't show your XML, but if all of the row* elements are contained by one element, then in the template for that element, you could do something like:
<fo:table>
<fo:table-body>
<xsl:for-each select="*">
<fo:table-row>
<fo:table-cell padding-bottom="6pt">
<fo:block>
<!-- The row* element is the current element here. -->
<xsl:apply-templates />
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:for-each>
</fo:table-body>
</fo:table>
Alternatively, you could make a template for all of the row* elements:
<xsl:template match="*[starts-with(local-name(), 'row')]">
<fo:table-row>
...
(From this distance, it's not clear why the row elements need separate element names.)
When you know the names of the elements that you want to format, you can do:
<xsl:apply-templates select="row1, row2, row3" />
and:
<xsl:template match="row1 | row2 | row3">
<fo:table-row>
...
I think instead of <fo:value-of select="$string1"/> you want <xsl:value-of select="$string1"/>. I would also check whether a fo:table-cell allows inline content, it might be necessary to put a fo:block container in the cell which has the xsl:value-of element as a child.
Also, for the function calls, don't use <fo:value-of select="fn:createRow('row1')"/>, instead, use <xsl:sequence select="fn:createRow('row1')"/>.
Also, fn is a reserved prefix, for your own functions declare and use your own namespace (e.g. xmlns:mf="http://example.com/mf" and <xsl:function name="mf:createRow" ...>...</xsl:function>, then use <xsl:sequence select="mf:createRow('row1')"/>.
So an example of the function would be
<xsl:function name="mf:createRow">
<xsl:param name="input"/>
<fo:table-row>
<fo:table-cell padding-bottom="6pt">
<fo:block>
<xsl:value-of select="$input"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:function>
and you could call it as e.g.
<fo:table-body>
<xsl:sequence select="(1 to 3) ! ('Row ' || . ) ! mf:createRow(.)"/>
</fo:table-body>

How to add a continued label in a static table with XSL/XSL-FO?

I am using an xml data similar to the sample below. There is a list of possible risks, and each of them can have a name and a description.
<risks>
<freezeDeductible name="item1" description="desc 1"/>
<moneySecLimit name="item2" description="desc 2"/>
<unscheduledLimit name="item3" description="desc 3"/>
...
</risks>
The structure of my template looks as below:
<xsl:template name="displayRisks">
<fo:block>
<fo:table>
<fo:table-column column-width="proportional-column-width(33.333)" column-number="1"/>
<fo:table-column column-width="proportional-column-width(33.333)" column-number="2"/>
<fo:table-column column-width="proportional-column-width(33.333)" column-number="3"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block font-weight="bold">ALL RISKS</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block><xsl:value-of select="/risks/freezeDeductible/#name"/></fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block><xsl:value-of select="/risks/freezeDeductible/#description"/></fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block> </fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block><xsl:value-of select="/risks/moneySecLimit/#name"/></fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block><xsl:value-of select="/risks/moneySecLimit/#description"/></fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
From the above template, I am generating PDF outputs. Because of the risk description size, and the number of risks elements is unknown, the table can go over multiple one or pages.
On the column1 x row1, there is displayed on first page, the title - "ALL RISKS". It needs to be on the same line as first risk name and description, so cannot move it to the table-header.
Is there any way that, when the table gets to page2, page3, etc. , to display the title (ALL RISKS) on the first row of the new page, with a label - for example: (continue..) ?
For example:
Page1: should display the title, on first table-row, as follows: ALL RISKS
If there is a Page2: display the title on the first table-row on Pag2, as follows: ALL RISKS(continued..)
Thanks!
There is an fo:retrieve-table-marker example in the 'XSL-FO Samples Collection' at https://www.antennahouse.com/xsl-fo-samples#table-retrieve-table-marker-1. (You may need to scroll up after you follow the link because of the banner on the page.)
There's also an example of the axf:repeat-content-at-break and axf:table-cell-repeated-marker AH Formatter extensions at https://www.antennahouse.com/xsl-fo-samples#axf-table-cell-repeated-marker-1 that demonstrates both the repetition and a '(Continued)' marker like what you want.

XSL-FOP text decoration extend line

I'm still a newbiew when it comes to XML, XSL, FOP.
How can I obtain an output having a long line with a text underneath it? something like:
<fo:inline text-decoration> Signature </fo:inline>
The only problem on this is that the line is too small. I want the line to be longer.
I want to have 2 sets of this on the same line. One is Signature and the other is Date
Please help. :)
If you want a simple signature block like you are trying to create, just use a table like this:
<fo:table>
<fo:table-column column-width="2.5in"/>
<fo:table-column column-width="1in"/>
<fo:table-column column-width="2.5in"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell border-top="1pt solid black">
<fo:block>Signature</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block/>
</fo:table-cell>
<fo:table-cell border-top="1pt solid black">
<fo:block>Date</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
Which gives you this:

Splitting a particular column with a simple horizontal line

I am trying to split a particular column with a simple horizontal line .
<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell border-color="white" padding-top="5px" padding-bottom="5px">
<fo:block>
<xsl:choose>
<xsl:when test=>
<fo:block border-bottom-width="0.1mm" border-bottom-style="solid" border-bottom-color="black" font-weight="bold">
First I tried to make another table in a column for splitting of data but its not working. border-bottom inside <fo:block > is also not helping .
The line doesn't seem to properly split the column .How can I do this .
On my comment above, the best solution is change your logic to apply appropriate spanning. Here is some FO to get you thinking:
<fo:table font-size="18pt">
<fo:table-body>
<fo:table-row>
<fo:table-cell number-rows-spanned="2" border="1pt solid black" padding="3pt">
<fo:block>I am all in one spanned cell</fo:block>
</fo:table-cell>
<fo:table-cell border="1pt solid black" padding="3pt">
<fo:block>I am in top half of the cell</fo:block>
</fo:table-cell>
<fo:table-cell number-rows-spanned="2" border="1pt solid black" padding="3pt">
<fo:block>I am all in one spanned cell</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell border="1pt solid black" padding="3pt">
<fo:block>I am in bottom half of the cell</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
The result is:

Page break inside table XSL-FO

I have an XSL-FO stylesheet for a table.
<fo:page-sequence master-reference="defaultPage">
<fo:flow flow-name="xsl-region-body">
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-width="9pt"/>
<fo:table-column column-width="30pt"/>
<fo:table-column column-width="150pt"/>
<fo:table-header>
<fo:table-row>
<fo:table-cell>
<fo:block><xsl:text>Column 1</xsl:text></fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block><xsl:text>Column 2</xsl:text></fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block><xsl:text>Column 3</xsl:text></fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<fo:table-row>
<xsl:apply-templates select="rbrOcjena"/>
<xsl:apply-templates select="sifPred"/>
<xsl:apply-templates select="nazPred"/>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
The table can have many rows, so I'd like to break it on new page when it comes to the end of current, when generating PDF. Also, I would like to repeat table header on new page, if that's possible. What attributes should I put in the table tag to make it so?
Thanks!
The table can have many rows, so I'd like to break it on new page when
it comes to the end of current
Without seeing your XSL-FO code, it is difficult to answer this. Please show it. But generally, this is done with keeps and breaks. For example:
<fo:table-row keep-together.within-page="always">
I would like to repeat table header on new page, if that's possible.
What attributes should I put in the table tag to make it so?
Instructing an XSL-FO processor to repeat a number of rows at the top of every page is not done via an attribute to fo:table. Instead, the rows that are to be repeated are put inside fo:table-header:
<fo:table-header>
<fo:table-row>
<fo:table-cell>
<!--Block and text content-->
</fo:table-cell>
</fo:table-row>
</fo:table-header>
Then, the default behaviour of the processor should be to repeat the header rows after a page break. That's because the omit-header-at-break attribute of fo:table is set to "false" by default.
The most obvious reason for this is that it is immediately clear which rows belong to the header and should thus be repeated. If this was just a reference in an attribute of fo:table it would be harder to identify multiple rows as the header. You will find the relevant part of the XSL specification here.
I've faced similar scenario...
Try below code...
<fo:table-row>
<xsl:if test="position() != 1">
<xsl:attribute name="break-before">page</xsl:attribute></i>
.
.
.