XSL FO Table row header content is smashed - xslt

I am creating an xsl fo table that will have a varying number of columns. The application uses Apache FOP to display the transformed document. When there is a low number of columns, everything displays fine (i.e. content of the cells is centered and displayed in full although some columns end up taking up two lines because the text wraps). However, some tables have over 12 columns, and this is where the problem occurs: in the column header cells, the name of the column is all the way to the right of the cell taking multiple lines. It looks like the words are wrapping, but even the last two characters are seemingly cut off. The text is not leaking into the neighboring cells.
Here is the input xml file in this case it's a row for the table header and one row for the body for brevity's sake. I didn't include the chart elements referenced in the xsl document as that part displays properly:
<exports>
<export>
<table>
<tblRow>
<hdrCell>Month</hdrCell>
<hdrCell>Allow Amt PEPM Med</hdrCell>
<hdrCell>Allow Amt PEPM Rx</hdrCell>
<hdrCell>Allow Amt PEPM Med and Rx</hdrCell>
<hdrCell>Allow Amt PMPM Med</hdrCell>
<hdrCell>Allow Amt PMPM Rx</hdrCell>
<hdrCell>Allow Amt PMPM Med and Rx</hdrCell>
<hdrCell>Employees Avg Med or Rx</hdrCell>
<hdrCell>Members Avg Med or Rx</hdrCell>
<hdrCell>Net Pay PEPM Med</hdrCell>
<hdrCell>Net Pay PEPM Rx</hdrCell>
<hdrCell>Net Pay PEPM Med and Rx</hdrCell>
<hdrCell>Net Pay PMPM Med</hdrCell>
<hdrCell>Net Pay PMPM Rx</hdrCell>
<hdrCell>Net Pay PMPM Med and Rx</hdrCell>
</tblRow>
<tblRow>
<tblCell>Jan 2010</tblCell>
<tblCell>11</tblCell>
<tblCell>202</tblCell>
<tblCell>213</tblCell>
<tblCell>26</tblCell>
<tblCell>30</tblCell>
<tblCell>56</tblCell>
<tblCell>56</tblCell>
<tblCell>44</tblCell>
<tblCell>11</tblCell>
<tblCell>22</tblCell>
<tblCell>33</tblCell>
<tblCell>12</tblCell>
<tblCell>12</tblCell>
<tblCell>24</tblCell>
<tblCell>1</tblCell>
</tblRow>
</table>
</export>
And here is the xsl file that transforms the input file to xsl fo. I am new to xsl.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="exportPage">
<fo:region-body />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="exportPage">
<fo:flow flow-name="xsl-region-body">
<fo:block id="chartBlock">
<!-- THIS PART WORKS FINE -->
</fo:block>
<!-- THE PROBLEM PART -->
<fo:block id="tableBlock" margin="0.25in">
<xsl:apply-templates select="exports/export/table"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<!-- Creates the table -->
<xsl:template match="table">
<fo:table table-layout="fixed" width="100%" >
<fo:table-header>
<fo:table-row>
<xsl:apply-templates select="tblRow[position() = 1]"/>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:apply-templates select="tblRow[position() > 1]"/>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="hdrCell">
<fo:table-cell background-color="#666" border-right-style="solid" border-right-width="1px" border-right-color="white" empty-cells="show">
<fo:block color="white" font-family="arial, helvetica, sans-serif" font-size="xx-small"><xsl:value-of select="."/></fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="tblCell">
<fo:table-cell border-bottom-style="solid" border-bottom-width="1px"
border-bottom-color="#E3E3E3">
<fo:block color="#7E7E7E" font-family="arial, helvetica, sans-serif" font- size="xx-small"><xsl:value-of select="."/></fo:block>
</fo:table-cell>
</xsl:template >
<xsl:template match="tblRow[position() > 1]">
<fo:table-row>
<xsl:apply-templates />
</fo:table-row>
</xsl:template>
</xsl:stylesheet>
I have tried setting a padding right property for each table-cell's block element hoping it would shift the text to the left to no avail. I have tried adjusting the 'width' property of each block element that is a child of a table-cell. I am new to xsl in general, so I'm not sure how to proceed. Would it be helpful to specify elements with a specific width? What can I do to ensure the full width of the table is displayed in the pdf and is without this jumbled, truncated cell content? Also, all units are in 'px' where not specified.
Thanks in advance,
Brandt

Answer: removing the margin="0.25in" from the surrounding block yields the result I think you expect (except of course for the margin on that block). To be clear, change this:
<fo:block id="tableBlock" margin="0.25in">
<xsl:apply-templates select="exports/export/table"/>
</fo:block>
And remove the margin="0.25in".
Note: This is not the result you would get from a different formatter. I used RenderX on your original file and you get what you expect and the correct result. I used FOP and get the incorrect result but remove that indent (which is obviously being inherited someway improperly to only one dimension of table cells).
One additional note: You have 15 header cells and 16 cells in your sample.

Related

How to interrupt a page-sequence to insert another page-sequence

Via xsl:for-each-group I group my data with a property pagemaster. For this group I assign the page-sequence in the attribute pagemaster. Then the template is called for each element in this group.
Now to my question: is it somehow possible that I leave the current page-sequence in the for-each loop to insert another page-sequence and then continue with the previous one?
As an example, let's assume that all elements in the group should be rendered on blue pages, but if an element has a certain attribute, a red page will be inserted at this place.
My code section looks like this:
.
<!-- master-set defined here -->
.
</fo:layout-master-set>
<xsl:for-each-group select=".//reportelements/*[pagemaster != '']" group-adjacent="pagemaster">
<fo:page-sequence master-reference="{current-grouping-key()}">
<!-- Static-Content per pagemaster Group -->
<xsl:call-template name="STATIC-CONTENT">
<xsl:with-param name="pageMaster" select="current-grouping-key()" />
</xsl:call-template>
<fo:flow flow-name="xsl-region-body">
<xsl:for-each select="current-group()">
<!-- Here, for example, i would like to check if the current element (.)
is from type "section" and the attribute "hastoc" is true.
If yes the current page sequence should be interrupted and a new page-sequence
should be inserted on which the table of contents is rendered. -->
<xsl:apply-templates select="."/>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>
</xsl:for-each-group>
</fo:root>
</xsl:template>
<xsl:template name="STATIC-CONTENT">
<xsl:param name="pageMaster" />
<xsl:if test="$pageMaster = 'TITLEPAGE'">
<fo:static-content flow-name="xsl-region-after">
<fo:block text-align="right">
<fo:external-graphic src="url(file:C\Logo.pdf)" content-width="6cm" />
</fo:block>
</fo:static-content>
</xsl:if>
</xsl:template>
Xml Code looks like
<?xml version="1.0" encoding="utf-8"?>
<root>
<report>
<layout>report.xsl</layout>
<namecontent>Report</namecontent>
<reportelements>
<section>
<layout>section_normal</layout>
<pagemaster></pagemaster>
<titlecontent>Vorspann</titlecontent>
<hastoc>false</hastoc>
<reportelements>
<picture>
<layout>picture_title</layout>
<pagemaster>TITLEPAGE</pagemaster>
<titlecontent>Titelpicture</titlecontent>
<reportelements />
<path>files\Titelpicture213124.Jpeg</path>
</picture>
<section>
<layout>section_leader.xsl</layout>
<pagemaster>DIN-A4-HEADER-ODD-EVEN</pagemaster>
<titlecontent>Profil</titlecontent>
<hastoc>true</hastoc>
<reportelements>
<paragraph>
<layout>paragraph_leader.xsl</layout>
<pagemaster>DIN-A4-HEADER-ODD-EVEN</pagemaster>
<titlecontent>p1</titlecontent>
<reportelements />
<textcontent>paragraph_leader 1 text</textcontent>
</paragraph>
<paragraph>
<layout>paragraph_leader.xsl</layout>
<pagemaster>DIN-A4-HEADER-ODD-EVEN</pagemaster>
<titlecontent>p2</titlecontent>
<reportelements />
<textcontent>paragraph_leader 2 text</textcontent>
</paragraph>
.
.
.
.
I am using the Apache Formatting Object Processor 2.3

Index mapping in XSLT-2.0

I have created index page using XSLT code. The contents name are shown to index page correctly but i want to map contents according to page number for specific title.
I am getting title with their description So I have named that block as id="TOC" and given as ref-id=”TOC” but the page number is not reflecting in my title.
Title:- Title names present in Index page.
Summary:- Title content associated with page.
The below is my XSLT-2.0 sample code:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="content_name">
<fo:block space-after="7pt" space-after.conditionality="retain" line-height="1.147" font-family="Calibri" font-size="15pt" font-weight="bold" language="FR">
<fo:inline>
<fo:leader leader-length="0pt" />
<xsl:value-of select="title"/>
<fo:page-number-citation ref-id="TOC"/>
</fo:inline>
</fo:block>
</xsl:template>
<xsl:template match="pro_list">
<fo:block space-after="15pt" space-after.conditionality="retain" line-height="1.147" font-family="Calibri" font-size="15pt" font-weight="bold" text-decoration="underline" language="FR">
<fo:inline>
<fo:leader leader-length="0pt" />
<xsl:value-of select="title" id="TOC"/>
</fo:inline>
</fo:block>
<fo:block space-after="8pt" space-after.conditionality="retain" line-height="1.147" font-family="Calibri" font-size="15pt" language="FR">
<fo:inline>
<fo:leader leader-length="0pt"/>
<xsl:value-of select="summary" disable-output-escaping="yes" />
</fo:inline>
</fo:block>
</xsl:template>
</xsl:stylesheet>
This is the output:
Contents
Title1 page no.
Title2 page no.
Title3 page no.
Suppose title1 content is associated with page2 & similar for title2-3 & title3-4, then output looks like as follows
Contents
Title1 2
Tilte2 3
Title3 4
Is there any syntax or predefined function available to do index mapping?

fo:block next to fo:table in xsl

how can I put a fo:block with a text like:
<fo:block text-align="right" font-size="48pt">
HALLO
</fo:block>
side by side / next to a my fo:table in the xsl file.
My XSL File looks so:
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:java="http://xml.apache.org/xslt/java" xmlns:date="java.util.Date" xmlns:sf="java.text.SimpleDateFormat"
exclude-result-prefixes="java" version="1.0">
....
....
...
<xsl:template match="Order">
<fo:table border="0.5pt solid">
<fo:table-column column-width="5cm"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block font-size="10pt">
delivery:
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-weight="bold" font-size="12pt">
<xsl:value-of select="#DeliveryTime"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</xsl:stylesheet>
Next to the table above in my xsl sheet I want to put the HALLO text.
If you really want this, you can specify a block-container that contains two block-containers with absolute positions placed side by side. The table goes in one, the text goes in the other.
But it's probably simpler to extend the table across the full page width and place the 'Hallo' text inside a cell, and span/merge cells if you need more room.

Need to scale images to fit using XSL FO

I am working on a project in which we have charts and a table exported to PDF. We are using Apache FOP for the PDF generation. The charts are in SVG and display fine if there's only one. However, we will have cases in which there are up to four, and in these instances only three of the four are fitting on the generated PDF. I need all images to fit regardless of number. I'm afraid simply putting the page in landscape will be a temporary solution for when we need even more to fit. The sizes of each chart are set in pixels from the svg generated in the client by the Highcharts library. It appears as though the images are inserted into the pdf without any scaling, even though I set attributes for the instream-foreign-object per an example seen here: Scaling images using scale-to-fit
So I need each chart to "shrink to fit". I have tried setting the length and width of the element that encloses each element that contains an instream-foreign object (I am also including my xsl). Within the instream-foreign -object I am assigning the svg width & height to the values from the actual chart svg. I thought maybe this was the problem, but if I don't include these dimensions the charts don't appear in the pdf. I also tried setting the scaling attribute to "non-uniform" per the question here: Scale images with fixed height and the results were no better. It actually stretched a chart across the whole page thus displaying only one of four. Here's my xsl:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="exportPage">
<fo:region-body />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="exportPage">
<fo:flow flow-name="xsl-region-body">
<fo:block id="mainTitleBlock" font-family="arial, helvetica, sans-serif" color="#5c068c" font-weight="bold">
<xsl:value-of select="exports/export/charts/#mainTitle"/>
</fo:block>
<fo:block id="timestampBlock" font-family="arial, helvetica, sans-serif" font-size="small" color="#6D869F">
<xsl:value-of select="exports/export/charts/#timeStamp"/>
</fo:block>
<!-- This is where the charts go -->
<!-- Within this block will be an inline element for each chart-->
<fo:block id="chartBlock" width="8.25in" height="6in">
<xsl:apply-templates select="exports/export/charts/chart"/>
</fo:block>
<fo:block id="tableBlock" >
<xsl:apply-templates select="exports/export/table"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<!-- Creates the table -->
<xsl:template match="table">
<fo:table table-layout="fixed" width="100%" >
<fo:table-header>
<fo:table-row>
<xsl:apply-templates select="tblRow[position() = 1]"/>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:apply-templates select="tblRow[position() > 1]"/>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="hdrCell">
<fo:table-cell background-color="#666" border-right-style="solid" border-right-width="1px" border-right-color="white" empty-cells="show">
<fo:block color="white" font-family="arial, helvetica, sans-serif" font-size="x-small"><xsl:value-of select="."/></fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="tblCell">
<fo:table-cell border-bottom-style="solid" border-bottom-width="1px" border-bottom-color="#E3E3E3" >
<fo:block color="#7E7E7E" font-family="arial, helvetica, sans-serif" font-size="x-small"><xsl:value-of select="."/></fo:block>
</fo:table-cell>
</xsl:template >
<xsl:template match="tblRow[position() > 1]">
<fo:table-row>
<xsl:apply-templates />
</fo:table-row>
</xsl:template>
<xsl:template match="chart">
<fo:inline>
<fo:instream-foreign-object xmlns:svg="http://www.w3.org/2000/svg" content-width="scale-to-fit" content-height="100%" width="100%" scaling="uniform">
<svg:svg width="{svg:svg/#width}" height="{svg:svg/#height}">
<xsl:copy-of select="svg:svg"/>
</svg:svg>
</fo:instream-foreign-object>
</fo:inline>
</xsl:template>
</xsl:stylesheet>
What am I missing? Would it help to display the charts in table-cells (thus breaking the convention of not using tables for layout- the horror!)? How can I get these to scale and fit in the page?
Thanks,
Brandt
The scale property makes the chart fit in the containing block. If you haven't set dimensions for that block, the formatting engine won't know what size to scale to so it will use 100%.
I don't know what happens when you place more than one chart into one block.
You may need to put the charts in a table, one chart per column so you can set the column widths depending on the number of charts.

How do I translate <b> tags inside data with xsl-fo

I have report that I must convert to PDF using xsl-fo from xml data coming from a MySQL database.
The xml structure that I am working on has already been used to create a HTML report.
There are certain fields that already have html tags inside that I was able to use in the HTML report by adding disable-output-escaping="yes" to my xsl:value-of's statement.
How do I do the similar operation in xsl-fo? Is there a way I can change the tags to be fo:inline? Or perhaps something I can change in the database output that will be the equivalent PDF version of bolding?
Here is a xml snippet:
<foal_line>
<yob>0</yob>
<description>Tis The Alarm. Unplaced at 3 in NA. Dam of <B>SA MOKEN</B> (f, by Smoke Glacken. 2 wins at 2, $60,382 in NA. Won Ken Kendrick Memorial Futurity (SRP, $25,043). 2nd Kachina S. (RUI, $10,982). 3rd Ruidoso Thoroughbred Futurity (RUI, $7,787), etc.) Granddam of <B>Dream Kin</B> (f, by Desert God. 4 wins, 2 to 4, $127,880 in US. 2nd New Mexico Cup Juv. Fillies S.-R (ZIA, $33,440). 3rd C. O. "Ken" Kendrick Memorial S-R (SRP, $7,500), Lincoln H. [R] (RUI, $5,000), Carlos Salazar S. [N] (ALB, $4,000), etc.)</description>
</foal_line>
My previous xslt snippet to create xhtml:
<tr>
<td width="30px" style="vertical-align:text-top;">
<xsl:value-of select="yob"/>
</td>
<td style="vertical-align:text-top;text-align:left;padding-left:2px">
<xsl:value-of select="description" disable-output-escaping="yes" />
</td>
</tr>
My current xsl-fo snippet:
<fo:table-row>
<fo:table-cell>
<fo:block><xsl:value-of select="yob"/></fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block><xsl:value-of select="description"/></fo:block>
</fo:table-cell>
</fo:table-row>
Edit:
Here is what I'm really getting from the server. That's what I get for using IE to view my xml.
<foal_line>
<yob>0</yob>
<description>Tis The Alarm. Unplaced at 3 in NA. Dam of <B>SA MOKEN</B> (f, by Smoke Glacken. 2 wins at 2, $60,382 in NA. Won Ken Kendrick Memorial Futurity (SRP, $25,043). 2nd Kachina S. (RUI, $10,982). 3rd Ruidoso Thoroughbred Futurity (RUI, $7,787), etc.) Granddam of <B>Dream Kin</B> (f, by Desert God. 4 wins, 2 to 4, $127,880 in US. 2nd New Mexico Cup Juv. Fillies S.-R (ZIA, $33,440). 3rd C. O. "Ken" Kendrick Memorial S-R (SRP, $7,500), Lincoln H. [R] (RUI, $5,000), Carlos Salazar S. [N] (ALB, $4,000), etc.)</description>
</foal_line>
This is why suggested answer is not working.
Instead of doing xsl:value-of for <description>, do xsl:apply-templates. You can then create a template to match <B>. In the B template you can use fo:inline to make the text bold.
Here's an example:
<xsl:template match="foal_line">
<fo:table-row>
<fo:table-cell>
<fo:block><xsl:value-of select="yob"/></fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block><xsl:apply-templates select="description"/></fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
<xsl:template match="description">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="B">
<fo:inline font-weight="bold"><xsl:apply-templates/></fo:inline>
</xsl:template>
Using your XML input and the above templates, the following output is generated:
<fo:table-row xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:table-cell>
<fo:block>0</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Tis The Alarm. Unplaced at 3 in NA. Dam of <fo:inline font-weight="bold">SA MOKEN</fo:inline> (f, by Smoke Glacken. 2 wins at 2, $60,382 in NA. Won Ken Kendrick Memorial Futurity (SRP, $25,043). 2nd Kachina S. (RUI, $10,982). 3rd Ruidoso Thoroughbred Futurity (RUI, $7,787), etc.) Granddam of <fo:inline font-weight="bold">Dream Kin</fo:inline> (f, by Desert God. 4 wins, 2 to 4, $127,880 in US. 2nd New Mexico Cup Juv. Fillies S.-R (ZIA, $33,440). 3rd C. O. "Ken" Kendrick Memorial S-R (SRP, $7,500), Lincoln H. [R] (RUI, $5,000), Carlos Salazar S. [N] (ALB, $4,000), etc.)</fo:block>
</fo:table-cell>
</fo:table-row>
Also, you should do the same for <yob> if it is also mixed content (text and other elements such as <B>).
You can also do this for your XHTML XSLT so you don't have to use disable-output-escaping (which I try to avoid at all costs).
I know that this question is rather old. I'm using Apache FOP and got stuck with this behavior of encoded or raw HTML treatment. Here's my solution I've been working on for a couple of hours.
XML:
<foal_line>
<yob>0</yob>
<description><html xmlns="http://www.w3.org/1999/xhtml">HTML text can be <b>bold</b> and <i>italic</i></html></description>
</foal_line>
XSL:
<xsl:stylesheet version="1.0" xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
>
<!-- Output in XML -->
<xsl:output method="xml" version="1.0" indent="yes" />
<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<!-- Templates -->
<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="seite" page-width="210mm" page-height="297mm" margin="20mm 20mm 20mm 20mm">
<fo:region-body margin="20mm 0mm 10mm 0mm"/>
<fo:region-before region-name="header"/>
<fo:region-after region-name="footer"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence id="seite" master-reference="seite">
<fo:static-content flow-name="footer">
<fo:block>Footer</fo:block>
</fo:static-content>
<fo:static-content flow-name="header">
<fo:block>Header</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="foal_line">
<fo:block-container>
<fo:block>Yob: <xsl:value-of select="yob"/></fo:block>
<fo:block>Desc:
<xsl:apply-templates select="description/xhtml:html"/>
</fo:block>
</fo:block-container>
</xsl:template>
<xsl:template match="description">
<xsl:message>Description</xsl:message>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="xhtml:b">
<xsl:message>Bold</xsl:message>
<fo:inline font-weight="bold"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match="xhtml:i">
<xsl:message>italic</xsl:message>
<fo:inline font-style="italic"><xsl:apply-templates/></fo:inline>
</xsl:template>
</xsl:stylesheet>
Finally I got a well-formed FO and could translate that into PDF.