I'm working on an XSL FO to generate PDF using FOP.NET. I've a requirement of generating the columns dynamically based on the XML i get from the DB. Below is the XML format i've and i need to generate the columns dynamically rather than hardcoding them in the xsl fo stylesheet. ANy help would be greatly appreciated.
Edit:
My goal is to build 20 types of reports and want to do it dynamically with 1 xsl fo. Is this possbile? or do I need to have 20 xsl fo files to generate the report? Please suggest an optimal way to do this.. I dont want to use itextsharp and other paid tools. (Only XSL FO)
Below is the XML that i get from SQL Server.
<?xml version="1.0" standalone="yes"?>
<Products>
<Product id="1" name="Rendezvous with Rama by Arthur C. Clarke" price="15" quantity="3" description="An all-time science fiction classic, Rendezvous with Rama is also one of Clarke's best novels--it won the Campbell, Hugo, Jupiter, and Nebula Awards." />
<Product id="2" name="Dune Chronicles by Frank Herbert" price="60" quantity="5" description="Dune is one of the most famous science fiction novels ever written, and deservedly so. The setting is elaborate and ornate, the plot labyrinthine, the adventures exciting. Five sequels follow." />
<Product id="3" name="Schindler's List by Thomas Keneally" price="21" quantity="6" description="A mesmerizing novel based on the true story of Oskar Schindler, a German industralist who saved and succored more than 1000 Jews from the Nazis at enormous financial and emotional expense." />
<Product id="4" name="Middle Passage by Charles Johnson" price="17" quantity="4" description="In this savage parable of the African American experience, Rutherford Calhoun, a newly freed slave eking out a living in New Orleans in 1830, hops aboard a square rigger to evade the prim Boston schoolteacher who wants to marry him. But the Republic turns out to be a slave clipper bound for Africa." />
<Product id="5" name="Underworld:A Novel by Don DeLillo" price="14" quantity="3" description="Underworld opens with a breathlessly graceful prologue set during the final game of the Giants-Dodgers pennant race in 1951. Written in what DeLillo calls super-omniscience the sentences sweep from young Cotter Martin as he jumps the gate to the press box, soars over the radio waves, runs out to the diamond, slides in on a fast ball, pops into the stands where J. It's an absolutely thrilling literary moment." />
<Product id="6" name="Stones from the River by Ursula Hegi" price="16" quantity="4" description="Ursula Hegi's Stones from the River clamors for comparisons to Gunter Grass's The Tin Drum; her protagonist Trudi Montag--like the unforgettable Oskar Mazerath--is a dwarf living in Germany during the two World Wars. " />
<Product id="7" name="Empire of the Sun by J. G. Ballard" price="12" quantity="3" description="Ballard's enduring novel of war and deprivation, internment camps and death marches, and starvation and survival is an honest coming-of-age tale set in a world thrown utterly out of joint." />
</Products>
The columns id, name, price, quantity, description need to be bound dynamically. Any help with an example would be greatly appreciated.
My Hardcoded XSL stylesheet
<fo:table border-bottom-width="5pt" width="1500pt" border-bottom-color="rgb(0,51,102)" border-collapse="collapse" background-color="rgb(255,255,255)">
<fo:table-column column-width="proportional-column-width(6.77)" column-number="1"/>
<fo:table-column column-width="proportional-column-width(5.09)" column-number="2"/>
<fo:table-column column-width="proportional-column-width(5.63)" column-number="3"/>
<fo:table-column column-width="proportional-column-width(5.94)" column-number="4"/>
<fo:table-column column-width="proportional-column-width(5.79)" column-number="5"/>
<fo:table-header>
<fo:table-row height="20.81pt" display-align="center" overflow="hidden">
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Transaction</fo:block>
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Date</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Cust ID</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Cust No</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Client Name</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Long ID</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<fo:table-row display-align="before">
<fo:table-cell text-align="center" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-left-width="1pt" border-right-width="1pt" border-top-width="1pt" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block>
1
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="left" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-left-width="1pt" border-right-width="1pt" border-top-width="1pt" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block>
Rendezvous with Rama by Arthur C. Clarke
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="right" border-top-color="rgb(0, 0, 0)" border-right-color="rgb(0, 0, 0)" border-top-style="solid" border="1pt " padding="2pt">
<fo:block>
3
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="right" border-top-style="solid" border="1pt rgb(0, 0, 0)" padding="2pt">
<fo:block>
$15.00
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="left" border-top-color="rgb(0, 0, 0)" border-left-color="rgb(0, 0, 0)" border-top-style="solid" border="1pt " padding="2pt">
<fo:block>
An all-time science fiction classic, Rendezvous with Rama is also one of Clarke's best novels--it won the Campbell, Hugo, Jupiter, and Nebula Awards.
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
Thanks,
Pavan
An XSLT 1.0 stylesheet for your sample is below. If you need to produce 20 variations on this, I suggest that you come up with an XML representation of the necessary information for each report -- e.g., the order and column-width for each of your attributes -- then use XSLT on that XML to generate an XSLT stylesheet like the one below. You can then use that XSLT to generate the FO from the XML that you get from SQL Server. It may sound complicated, but it should be simpler than trying to maintain 20 stylesheets.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<xsl:variable name="columnFontType" select="'sans-serif'"/>
<xsl:variable name="columnFontSize" select="'12pt'"/>
<xsl:template match="Products">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="a">
<fo:region-body margin="10mm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="a">
<fo:flow flow-name="xsl-region-body">
<fo:table border-bottom-width="5pt" border-bottom-color="rgb(0,51,102)" border-collapse="collapse" background-color="rgb(255,255,255)">
<fo:table-column column-width="proportional-column-width(6.77)" column-number="1"/>
<fo:table-column column-width="proportional-column-width(5.09)" column-number="2"/>
<fo:table-column column-width="proportional-column-width(5.63)" column-number="3"/>
<fo:table-column column-width="proportional-column-width(5.94)" column-number="4"/>
<fo:table-column column-width="proportional-column-width(5.79)" column-number="5"/>
<fo:table-header>
<fo:table-row height="20.81pt" display-align="center" overflow="hidden">
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Transaction</fo:block>
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Date</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Cust ID</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Cust No</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Client Name</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Long ID</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:apply-templates />
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="Product">
<fo:table-row display-align="before">
<xsl:call-template name="cell">
<xsl:with-param name="value" select="#id"/>
</xsl:call-template>
<xsl:call-template name="cell">
<xsl:with-param name="value" select="#name"/>
</xsl:call-template>
<xsl:call-template name="cell">
<xsl:with-param name="value" select="#quantity"/>
</xsl:call-template>
<xsl:call-template name="cell">
<xsl:with-param name="value" select="format-number(#price, '$0.00')"/>
</xsl:call-template>
<xsl:call-template name="cell">
<xsl:with-param name="value" select="#description"/>
</xsl:call-template>
</fo:table-row>
</xsl:template>
<xsl:template name="cell">
<xsl:param name="value" />
<fo:table-cell text-align="center" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-left-width="1pt" border-right-width="1pt" border-top-width="1pt" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block>
<xsl:value-of select="$value"/>
</fo:block>
</fo:table-cell>
</xsl:template>
</xsl:stylesheet>
Also look into xsl:attribute-set (see https://www.w3.org/TR/xslt#attribute-sets) as a way to add a bunch of attributes at once (though possibly less useful if you're generating the XSLT anyway).
My goal is to build 20 types of reports and want to do it dynamically
with 1 xsl fo. Is this possbile?
It's possible - if all the reports follow some common pattern.
For example, if the rows are always children of the root element, and the cells are the attributes of rows, you could do something like this (code simplified for the purpose of demonstration):
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<table>
<header>
<row>
<xsl:for-each select="*[1]/#*">
<cell>
<xsl:value-of select="name()"/>
</cell>
</xsl:for-each>
</row>
</header>
<body>
<xsl:for-each select="*">
<row>
<xsl:for-each select="#*">
<cell>
<xsl:value-of select="."/>
</cell>
</xsl:for-each>
</row>
</xsl:for-each>
</body>
</table>
</xsl:template>
</xsl:stylesheet>
Applied to your input example, the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<table>
<header>
<row>
<cell>id</cell>
<cell>name</cell>
<cell>price</cell>
<cell>quantity</cell>
<cell>description</cell>
</row>
</header>
<body>
<row>
<cell>1</cell>
<cell>Rendezvous with Rama by Arthur C. Clarke</cell>
<cell>15</cell>
<cell>3</cell>
<cell>An all-time science fiction classic, Rendezvous with Rama is also one of Clarke's best novels--it won the Campbell, Hugo, Jupiter, and Nebula Awards.</cell>
</row>
<row>
<cell>2</cell>
<cell>Dune Chronicles by Frank Herbert</cell>
<cell>60</cell>
<cell>5</cell>
<cell>Dune is one of the most famous science fiction novels ever written, and deservedly so. The setting is elaborate and ornate, the plot labyrinthine, the adventures exciting. Five sequels follow.</cell>
</row>
<row>
<cell>3</cell>
<cell>Schindler's List by Thomas Keneally</cell>
<cell>21</cell>
<cell>6</cell>
<cell>A mesmerizing novel based on the true story of Oskar Schindler, a German industralist who saved and succored more than 1000 Jews from the Nazis at enormous financial and emotional expense.</cell>
</row>
<row>
<cell>4</cell>
<cell>Middle Passage by Charles Johnson</cell>
<cell>17</cell>
<cell>4</cell>
<cell>In this savage parable of the African American experience, Rutherford Calhoun, a newly freed slave eking out a living in New Orleans in 1830, hops aboard a square rigger to evade the prim Boston schoolteacher who wants to marry him. But the Republic turns out to be a slave clipper bound for Africa.</cell>
</row>
<row>
<cell>5</cell>
<cell>Underworld:A Novel by Don DeLillo</cell>
<cell>14</cell>
<cell>3</cell>
<cell>Underworld opens with a breathlessly graceful prologue set during the final game of the Giants-Dodgers pennant race in 1951. Written in what DeLillo calls super-omniscience the sentences sweep from young Cotter Martin as he jumps the gate to the press box, soars over the radio waves, runs out to the diamond, slides in on a fast ball, pops into the stands where J. It's an absolutely thrilling literary moment.</cell>
</row>
<row>
<cell>6</cell>
<cell>Stones from the River by Ursula Hegi</cell>
<cell>16</cell>
<cell>4</cell>
<cell>Ursula Hegi's Stones from the River clamors for comparisons to Gunter Grass's The Tin Drum; her protagonist Trudi Montag--like the unforgettable Oskar Mazerath--is a dwarf living in Germany during the two World Wars. </cell>
</row>
<row>
<cell>7</cell>
<cell>Empire of the Sun by J. G. Ballard</cell>
<cell>12</cell>
<cell>3</cell>
<cell>Ballard's enduring novel of war and deprivation, internment camps and death marches, and starvation and survival is an honest coming-of-age tale set in a world thrown utterly out of joint.</cell>
</row>
</body>
</table>
Related
I am using Apache's XML Graphics FOP 2.6 to create a PDF document containing at least 2 pages. There is no maximum number of pages.
The exact same header is used on every page.
Page 1 (see attached)
Needs to contain text with the total number of boxes, the total number of items included in the total number of boxes and a table with 1, 2 or 3 rows. On each row, there is a photo of the box, its name and the number of items it contains. There will be at least one box containing at least one item.
Page 2
Exists only if there are 4 or more boxes and it contains rows 4, 5, 6, 7, 8 and 9 (6 rows in total) of the table from Page 1. If there are more than 9 (= 3 + 6 X 1) boxes, there needs to be a new page that will contain the layout from Page 2, but containing the rows for boxes 10, ..., 15. This pattern will be followed until the last box.
Page 3
Will contain the photo, name and number of items of the first box. Underneath there will be a table, with a row containing the column names and at most 4 rows, corresponding to the first 4 items from the first box.
Page 4
If the first box has more than 4 items, there will be new page, called Page 4, containing only the continuation of the table, including the row with the column names. It will have 7 items in total and be followed by another page if the first box has more than 11 (= 4 + 7 X 1) items. And so on until the end of all items.
Page 5 (not attached to avoid repetition)
Will follow the same logic as Page 3, but in this case for the second box, if there is a second box. And so on until the end of all boxes.
Can anyone, please help me with an idea on how to build the layout-master-set in the XSL file for my requirements? I am not looking for the entire solution. Only for the general layout structure. The answer does not have to be too detailed or too bespoke for my needs. I can adapt it if needed.
<xsl:template match="/doc">
<xsl:variable name="Logo"><xsl:value-of select="Logo"/></xsl:variable>
...
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
font-family="Nexus Sans Pro" font-weight="normal">
<fo:layout-master-set>
<fo:simple-page-master master-name="Boxes-A4" page-width="297mm" page-height="210mm"
margin-top="0mm" margin-bottom="0mm" margin-left="0mm" margin-right="0mm">
<fo:region-body region-name="xsl-region-body"/>
<fo:region-before region-name="xsl-region-before" extent="70mm"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="Items-A4" page-width="297mm" page-height="210mm"
margin-top="0mm" margin-bottom="0mm" margin-left="0mm" margin-right="0mm">
<fo:region-body region-name="xsl-region-body"/>
<fo:region-before region-name="xsl-region-before" extent="70mm"/>
</fo:simple-page-master>
</fo:layout-master-set>
I have tried the code above (using xsl:stylesheet version="1.0"), but have failed in getting things to be laid out appropriately. The rows of the table that do not fit on a page do not get displayed on the following page, even though I mark appropriate rows with break-before="page" aka page-break-before="always".
As an aid, I can insert the indices from the backend data structure into the parameters used by the library so that I know each element's index.
Thank you very much.
Page 1
Page 2
Page 3
Page 4
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/doc">
<fo:root font-family="Nexus Sans Pro" font-weight="normal">
<fo:layout-master-set>
<fo:simple-page-master master-name="Boxes-A4" page-width="297mm" page-height="210mm"
margin-top="0mm" margin-bottom="0mm" margin-left="0mm" margin-right="0mm">
<fo:region-body region-name="xsl-region-body"/>
<fo:region-before region-name="xsl-region-before" extent="70mm"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="Items-A4" page-width="297mm" page-height="210mm"
margin-top="0mm" margin-bottom="0mm" margin-left="0mm" margin-right="0mm">
<fo:region-body region-name="xsl-region-body"/>
<fo:region-before region-name="xsl-region-before" extent="70mm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<xsl:call-template name="boxes-template"/>
<xsl:call-template name="items-template"/>
</fo:root>
</xsl:template>
<xsl:template name="boxes-template">
<fo:page-sequence master-reference="Boxes-A4" font-family="Nexus Sans Pro" font-weight="normal">
<fo:static-content flow-name="xsl-region-before">
<fo:block-container border-bottom-width="1pt"
border-bottom-style="solid"
border-bottom-color="rgb(220,220,220)"
position="absolute" top="1mm" left="5mm" right="5mm" height="60mm">
<xsl:variable name="Logo" select="Logo"/>
<fo:block-container
background-image="url({$Logo})"
top="5mm" left="5mm" width="50mm" height="50mm"
background-repeat="no-repeat"
fox:background-image-width="50mm" fox:background-image-height="50mm"
absolute-position="absolute">
<fo:block/>
</fo:block-container>
<xsl:variable name="Stamp" select="Stamp"/>
<fo:block-container
background-image="url({$Stamp})"
top="5mm" right="5mm" width="50mm" height="50mm"
background-repeat="no-repeat"
fox:background-image-width="50mm" fox:background-image-height="50mm"
absolute-position="absolute">
<fo:block/>
</fo:block-container>
<fo:block-container position="absolute" top="8mm" left="80mm" width="120mm" height="42mm">
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-width="100%"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell height="12mm">
<fo:block font-family="Nexus Sans Pro Bold"
text-align="center" font-size="32pt"> Header Text
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell display-align="after" height="10mm">
<fo:block font-family="Nexus Sans Pro"
display-align="after" text-align="center" font-size="32pt"
color="rgb(233,113,28)">
<xsl:value-of select="user"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block-container>
<fo:block-container position="absolute" top="48mm" left="77mm" width="157mm" height="10mm">
<fo:table table-layout="fixed" width="100%">
<fo:table-body>
<fo:table-row>
<fo:table-cell height="10mm">
<fo:block font-family="Nexus Sans Pro" font-weight="normal" font-size="15pt"
color="rgb(128,128,128)">
From:
<xsl:value-of select="fromDate"/>
</fo:block>
</fo:table-cell>
<fo:table-cell height="10mm">
<fo:block font-family="Nexus Sans Pro" font-weight="normal" font-size="15pt"
color="rgb(128,128,128)">
To:
<xsl:value-of select="toDate"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block-container>
</fo:block-container>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block-container position="absolute" top="75mm" left="110mm" width="120mm" height="20mm">
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-number="1" column-width="50%"/>
<fo:table-column column-number="2" column-width="50%"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell height="10mm">
<fo:block
font-family="Nexus Sans Pro Bold"
font-size="15pt" color="rgb(35,31,32)">
Total number of boxes:
</fo:block>
</fo:table-cell>
<fo:table-cell height="10mm">
<fo:block font-family="Nexus Sans Pro Bold"
font-size="15pt" color="rgb(35,31,32)">
<xsl:value-of select="totalNumberOfBoxes"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell height="10mm">
<fo:block font-family="Nexus Sans Pro Bold"
font-size="15pt" color="rgb(35,31,32)">
Total number of items:
</fo:block>
</fo:table-cell>
<fo:table-cell height="10mm">
<fo:block font-family="Nexus Sans Pro Bold"
font-size="15pt" color="rgb(35,31,32)">
<xsl:value-of select="totalNumberOfItems"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block-container>
<xsl:for-each select="/doc/box">
<xsl:variable name="boxImageURL" select="boxImageURL"/>
<fo:block-container position="absolute" top="105mm" left="30mm" width="220mm" height="26mm">
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-number="1" column-width="15%"/>
<fo:table-column column-number="2" column-width="70%"/>
<fo:table-column column-number="3" column-width="15%"/>
<fo:table-body>
<fo:table-row page-break-inside="auto"
border-top-width="1pt"
border-top-style="solid"
border-top-color="rgb(220,220,220)"
margin-bottom="2mm"
height="24mm">
<fo:table-cell>
<xsl:if test="$boxImageURL != 'null'">
<fo:block-container
background-image="url({$boxImageURL})"
top="110mm" right="15mm" width="15mm" height="20mm"
background-repeat="no-repeat" margin-top="2mm"
fox:background-image-width="15mm" fox:background-image-height="20mm">
<fo:block/>
</fo:block-container>
</xsl:if>
</fo:table-cell>
<fo:table-cell display-align="center" height="20mm">
<fo:block text-align="left" font-size="16pt" color="rgb(35,31,32)">
<xsl:value-of select="boxTitle"/>
</fo:block>
</fo:table-cell>
<fo:table-cell display-align="center" height="20mm">
<fo:block text-align="left" font-size="16pt" color="rgb(35,31,32)">
<xsl:value-of select="numberOfItems"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block-container>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>
</xsl:template>
<xsl:template name="items-template">
<xsl:variable name="Logo"><xsl:value-of select="Logo"/></xsl:variable>
<xsl:variable name="Stamp"><xsl:value-of select="Stamp"/></xsl:variable>
<xsl:variable name="user"><xsl:value-of select="user"/></xsl:variable>
<xsl:variable name="fromDate"><xsl:value-of select="fromDate"/></xsl:variable>
<xsl:variable name="toDate"><xsl:value-of select="toDate"/></xsl:variable>
<xsl:for-each select="/doc/box">
<xsl:variable name="boxImageURL" select="boxImageURL"/>
<fo:page-sequence master-reference="Items-A4" font-family="Nexus Sans Pro" font-weight="normal">
<fo:static-content flow-name="xsl-region-before">
... Same header as on the Box-A4
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block-container page-break-before="always"
position="absolute" top="70mm" left="30mm" width="220mm" height="24mm">
<fo:table page-break-before="always" table-layout="fixed" width="100%">
<fo:table-column column-number="1" column-width="15%"/>
<fo:table-column column-number="2" column-width="85%"/>
<fo:table-body>
<fo:table-row margin-bottom="2mm"
height="22mm">
<fo:table-cell>
<xsl:if test="$boxImageURL != 'null'">
<fo:block-container
background-image="url({$boxImageURL})"
top="110mm" right="15mm" width="15mm" height="20mm"
background-repeat="no-repeat" margin-top="2mm"
fox:background-image-width="15mm" fox:background-image-height="20mm">
<fo:block/>
</fo:block-container>
</xsl:if>
</fo:table-cell>
<fo:table-cell display-align="center" height="20mm">
<fo:block margin-top="4mm" text-align="left" font-size="16pt" color="rgb(35,31,32)">
<xsl:value-of select="boxTitle"/>
<fo:block margin-top="4mm" text-align="left" font-size="16pt" color="rgb(35,31,32)">
<xsl:value-of select="numberOfThings"/> things
</fo:block>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block-container>
<fo:block-container position="absolute" top="100mm" left="30mm" width="220mm" height="24mm">
<fo:table page-break-before="always" table-layout="fixed" width="100%">
<fo:table-column column-number="1" column-width="60%"/>
<fo:table-column column-number="2" column-width="15%"/>
<fo:table-column column-number="3" column-width="25%"/>
<fo:table-body>
<fo:table-row border-top-width="1pt"
border-top-style="solid"
border-top-color="rgb(220,220,220)"
margin-bottom="2mm"
height="22mm">
<fo:table-cell display-align="center" height="20mm">
<fo:block text-align="left" font-size="16pt" color="rgb(35,31,32)">
Item title
</fo:block>
</fo:table-cell>
<fo:table-cell display-align="center" height="20mm">
<fo:block text-align="left" font-size="16pt" color="rgb(35,31,32)">
Revision
</fo:block>
</fo:table-cell>
<fo:table-cell display-align="center" height="20mm">
<fo:block text-align="left" font-size="16pt" color="rgb(35,31,32)">
Date completed
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block-container>
<fo:block-container position="absolute" top="125mm" left="30mm" width="220mm" height="24mm">
<fo:table page-break-before="always" table-layout="fixed" width="100%">
<fo:table-column column-number="1" column-width="60%"/>
<fo:table-column column-number="2" column-width="15%"/>
<fo:table-column column-number="3" column-width="25%"/>
<fo:table-body>
<xsl:for-each select="items/item">
<fo:table-row keep-together.within-page="always"
break-after="page"
border-top-width="1pt"
border-top-style="solid"
border-top-color="rgb(220,220,220)"
margin-bottom="2mm"
height="22mm">
<fo:table-cell display-align="center" height="20mm">
<fo:block text-align="left" font-size="16pt" color="rgb(35,31,32)">
<xsl:value-of select="itemTitle"/>
</fo:block>
</fo:table-cell>
<fo:table-cell display-align="center" height="20mm">
<fo:block text-align="left" font-size="16pt" color="rgb(35,31,32)">
<xsl:value-of select="revision"/>
</fo:block>
</fo:table-cell>
<fo:table-cell display-align="center" height="20mm">
<fo:block text-align="left" font-size="16pt" color="rgb(35,31,32)">
<xsl:value-of select="dateCompleted"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block-container>
</fo:flow>
</fo:page-sequence>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
My simplified parameters.xml (lacking a few lines):
<doc>
<Logo>ELogo.jpg</Logo>
<Stamp>Stamp.jpg</Stamp>
<backgroundImageURL>bkg.jpg</backgroundImageURL>
<user>John Richard Edgar Bowens-Robins III</user>
<fromDate>1st March 2021</fromDate>
<toDate>31 November 2021</toDate>
<totalNumberOfBoxes>5</totalNumberOfBoxes>
<totalNumberOfItems>19</totalNumberOfItems>
<box>
<boxImageURL>box1.jpg</boxImageURL>
<boxTitle>JREBR's Box 1</boxTitle>
<items>
<item>
<itemTitle>The Nice Item 11</itemTitle>
</item>
<item>
<itemTitle>The Nice Item 12</itemTitle>
</item>
<item>
<itemTitle>The Nice Item 13</itemTitle>
</item>
</items>
</box>
<box>
<boxImageURL>box2.jpg</boxImageURL>
<boxTitle>JREBR's Box 2</boxTitle>
<items>
<item>
<itemTitle>The Nice Item 21</itemTitle>
</item>
<item>
<itemTitle>The Nice Item 22</itemTitle>
</item>
<item>
<itemTitle>The Nice Item 23</itemTitle>
</item>
</items>
</box>
</doc>
What you really call "Page 1", "Page 2" ... you really mean this:
Section 1 which is all the boxes. This could be 1 to x pages depending on the quantity of boxes. All the page templates are the same so this is one page sequence with one page master.
Section 2 to n which is a page sequence for each box listing all the items. All of these page sequences are the same (one simple page master).
You do not explain what photo 1 and photo 2 are in the header for these but I would assume they are the same for every page. If that is not true and are different for "boxes" and "items" then possibly you may have different headers.
So you only have two simple-page-masters one called "boxes" and one called "items". You would just create the "boxes" page-sequence referencing the simple-page-master for boxes. You do not present a sample XML, so let's just say it looks like this for simplicity:
<order>
<box>
<name>Box 1</name>
<items>
<item>Item 1:1</item>
<item>Item 1:2</item>
<item>Item 1:3</item>
</items>
</box>
<box>
<name>Box 2</name>
<items>
<item>Item 2:1</item>
<item>Item 2:2</item>
<item>Item 2:3</item>
</items>
</box>
<box>
<name>Box 3</name>
<items>
<item>Item 3:1</item>
<item>Item 3:2</item>
<item>Item 3:3</item>
</items>
</box>
</order>
Then this simple XSL would throw pages for boxes and items in those boxes:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="boxes" page-width="7in" page-height="4in">
<fo:region-body region-name="body" margin-top="0.5in" margin-bottom="0.5in" margin-left="0.5in" margin-right="0.5in"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="items" page-width="7n" page-height="4in">
<fo:region-body region-name="body" margin-top="0.5in" margin-bottom="0.5in" margin-left="0.5in" margin-right="0.5in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<xsl:call-template name="boxes"/>
<xsl:call-template name="items"/>
</fo:root>
</xsl:template>
<xsl:template name="boxes">
<fo:page-sequence master-reference="boxes">
<fo:flow flow-name="body">
<!-- Output the table of boxes -->
<xsl:for-each select="/order/box">
<fo:block>
<xsl:value-of select="name"/>
</fo:block>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>
</xsl:template>
<xsl:template name="items">
<xsl:for-each select="/order/box">
<fo:page-sequence master-reference="items">
<fo:flow flow-name="body">
<xsl:for-each select="items/item">
<fo:block>
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This results in:
Combining this with #Tony Graham's suggestion on doing the tables and you have the whole layout. If you wonder how that works with automatic page flows, here is the exact example above with a few more boxes and one box (Box 4) with more items ... I only changed the fo:block font-size to cause pagination.
Use fo:table, and for each fo:table-row specify height (https://www.w3.org/TR/xsl11/#height) with a suitable value that will get you the required number of rows per page.
You may also need to specify keep-together.within-page="always" to avoid breaking a table row. FOP may or may not support that on fo:table-row (or fo:table-cell).
Im hoping someone can help me.
At the moment I create A4 Documents using FOP and XSLT. I have been asked to take these A4 (portrait) pages and then stitch them into an A3 booklet. So for example I have a 4 page A4 document which I need to convert into a 2 sided A3 booklet with the ability to order the first side using page 4 and 1 (side by side) and then the other side to be page 2 and 3.
I have looked at PDFBOX to see if it can do this but have had no success.
Does anyone have any ideas of how I could get the outcome that I need?
All help is appreciated!
You can do that with FOP if you wish and if you install the PDF Images Plug-In for FOP
<?xml version="1.0" encoding="UTF-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="a3" margin-right="0mm" margin-left="0mm" margin-bottom="0mm" margin-top="0mm" page-width="42cm" page-height="29.7cm">
<fo:region-body margin-left="0mm" margin-top="0mm" margin-bottom="0mm" margin-right="0mm"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="a3n">
<fo:repeatable-page-master-alternatives>
<fo:conditional-page-master-reference master-reference="a3" page-position="any"/>
</fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="a3n">
<fo:flow flow-name="xsl-region-body">
<fo:block-container height="29.7cm" width="20.9cm" top="0mm" left="0mm" position="absolute">
<fo:block>
<fo:external-graphic content-height="29.7cm" content-width="21cm" height="29.7cm" width="21cm" src="yourpathdoc.pdf#page=2"/>
</fo:block>
</fo:block-container>
<fo:block-container height="29.7cm" width="20.9cm" top="0mm" left="209mm" position="absolute">
<fo:block>
<fo:external-graphic content-height="29.7cm" content-width="21cm" height="29.7cm" width="21cm" src="yourpathdoc.pdf#page=3"/>
</fo:block>
</fo:block-container>
<fo:block-container>
<fo:block font-size="0.1pt" page-break-after="always" break-after="page"> </fo:block>
</fo:block-container>
<fo:block-container height="29.7cm" width="20.9cm" top="0mm" left="0mm" position="absolute">
<fo:block>
<fo:external-graphic content-height="29.7cm" content-width="21cm" height="29.7cm" width="21cm" src="yourpathdoc.pdf#page=4"/>
</fo:block>
</fo:block-container>
<fo:block-container height="29.7cm" width="20.9cm" top="0mm" left="209mm" position="absolute">
<fo:block>
<fo:external-graphic content-height="29.7cm" content-width="21cm" height="29.7cm" width="21cm" src="yourpathdoc.pdf#page=1"/>
</fo:block>
</fo:block-container>
</fo:flow>
</fo:page-sequence>
</fo:root>
Edit
In case you want it portrait for easier printing, simply switch the page-width and page-height of the simple-page-master and replace the four block-container lines containing the position="absolute" with
<fo:block-container height="29.7cm" width="21cm" top="0mm" left="0mm" position="absolute" reference-orientation="270">
...
<fo:block-container height="29.7cm" width="21cm" top="210mm" left="0mm" position="absolute" reference-orientation="270">
...
<fo:block-container height="29.7cm" width="21cm" top="0mm" left="0mm" position="absolute" reference-orientation="270">
...
<fo:block-container height="29.7cm" width="21cm" top="210mm" left="0mm" position="absolute" reference-orientation="270">
and if you have more than two pages don't forget to insert the
<fo:block-container>
<fo:block font-size="0.1pt" page-break-after="always" break-after="page"> </fo:block>
</fo:block-container>
everywhere inbetween (after every second image)
I have a little issue that I've been struggling with for a couple of days now.
Here is input xml:
<Facture>
<Mensualite>
<Lines>
<Line>
<NumeroMensualite>1</NumeroMensualite>
<AnneeEcheance>2015</AnneeEcheance>
<DateEcheance>20150618</DateEcheance>
<Montant>163.14</Montant>
</Line>
<Line>
<NumeroMensualite>2</NumeroMensualite>
<AnneeEcheance>2015</AnneeEcheance>
<DateEcheance>20150718</DateEcheance>
<Montant>120</Montant>
</Line>
<Line>
<NumeroMensualite>3</NumeroMensualite>
<AnneeEcheance>2015</AnneeEcheance>
<DateEcheance>20150818</DateEcheance>
<Montant>120</Montant>
</Line>
<Line>
<NumeroMensualite>4</NumeroMensualite>
<AnneeEcheance>2015</AnneeEcheance>
<DateEcheance>20150918</DateEcheance>
<Montant>120</Montant>
</Line>
<Line>
<NumeroMensualite>5</NumeroMensualite>
<AnneeEcheance>2016</AnneeEcheance>
<DateEcheance>20151018</DateEcheance>
<Montant>120</Montant>
</Line>
<Line>
<NumeroMensualite>6</NumeroMensualite>
<AnneeEcheance>2016</AnneeEcheance>
<DateEcheance>20151118</DateEcheance>
<Montant>120</Montant>
</Line>
<Line>
<NumeroMensualite>6</NumeroMensualite>
<AnneeEcheance>2016</AnneeEcheance>
<DateEcheance>20151118</DateEcheance>
<Montant>120</Montant>
</Line>
<Line>
<NumeroMensualite>6</NumeroMensualite>
<AnneeEcheance>2017</AnneeEcheance>
<DateEcheance>20151113</DateEcheance>
<Montant>122</Montant>
</Line>
<Line>
<NumeroMensualite>6</NumeroMensualite>
<AnneeEcheance>2017</AnneeEcheance>
<DateEcheance>20151112</DateEcheance>
<Montant>124</Montant>
</Line>
</Lines>
</Mensualite>
</Facture>
And here is the xslfo that i've created:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:set="http://exslt.org/sets" xmlns:exsl="http://exslt.org/common" xmlns:java="http://xml.apache.org/xalan/java">
<xsl:key name="years" match="Mensualite/Lines/Line" use="AnneeEcheance" />
<!-- Start -->
<xsl:template match="/">
<xsl:apply-templates select="exsl:node-set(document(/*/Document))/Facture"/>
</xsl:template>
<xsl:template match="Facture">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<!--Page definitions-->
<fo:layout-master-set>
<fo:simple-page-master master-name="firstPageMaster" page-height="29.7cm" page-width="21cm" margin-top="7mm" margin-bottom="8mm" margin-left="8mm" margin-right="0mm">
<fo:region-body margin-top="23mm" extent="297mm" margin-left="8mm" margin-right="8mm" region-name="body"/>
<fo:region-before extent="23mm" region-name="header1"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="secondPageMaster" page-height="29.7cm" page-width="21cm" margin-top="7mm" margin-bottom="8mm" margin-left="8mm" margin-right="0mm">
<fo:region-body margin-top="26mm" margin-bottom="95mm" extent="255mm" margin-left="8mm" margin-right="8mm" region-name="body"/>
<fo:region-before extent="23mm" region-name="header"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="nextPagesMaster" page-height="29.7cm" page-width="21cm" margin-top="7mm" margin-bottom="8mm" margin-left="8mm" margin-right="0mm">
<fo:region-body margin-top="26mm" extent="255mm" margin-left="8mm" margin-right="8mm" region-name="body"/>
<fo:region-before extent="23mm" region-name="header"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="firstSecondAndRestPages">
<fo:single-page-master-reference master-reference="firstPageMaster"/>
<fo:repeatable-page-master-reference master-reference="nextPagesMaster" maximum-repeats="no-limit"/>
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="firstSecondAndRestPages" font-family="Neo Sans Std" font-size="8.5pt" color="&darkGreen;" force-page-count="no-force" initial-page-number="1">
<fo:flow flow-name="body">
<fo:block-container position="fixed" left="10mm" top="86mm" height="30mm" width="186mm" font-size="9pt" color="black" display-align="center">
<fo:table table-layout="fixed" font-size="9pt" width="186mm" space-before="3mm" space-after="1mm">
<fo:table-column column-width="30mm" />
<xsl:if test="count(Mensualite/Lines/Line) > 0"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 1"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 2"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 3"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 4"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 5"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 6"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 7"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 8"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 9"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 10"><fo:table-column column-width="10mm"/></xsl:if>
<xsl:if test="count(Mensualite/Lines/Line) > 11"><fo:table-column column-width="10mm"/></xsl:if>
<fo:table-body>
<fo:table-row font-weight="600" text-align="center">
<fo:table-cell border-bottom="thin solid &darkGreen;" border-right="thin solid &darkGreen;"><fo:block> </fo:block></fo:table-cell>
<xsl:for-each select="Mensualite/Lines/Line[generate-id(.)=generate-id(key('years', AnneeEcheance)[1] ) ]">
<fo:table-cell border-top="thin solid &darkGreen;" border-right="thin solid &darkGreen;" number-columns-spanned="{count(key('years', AnneeEcheance))}"><fo:block><xsl:value-of select="AnneeEcheance"/></fo:block></fo:table-cell>
</xsl:for-each>
</fo:table-row>
<fo:table-row border-bottom="thin solid &darkGreen;" border-top="thin solid &darkGreen;" border-left="thin solid &darkGreen;" border-right="thin solid &darkGreen;">
<fo:table-cell border-right="thin solid &darkGreen;" font-weight="600"><fo:block> Mensualité</fo:block></fo:table-cell>
<xsl:for-each select="key('years', Mensualite/Lines/Line/AnneeEcheance)">
<fo:table-cell border-right="thin solid &darkGreen;"><fo:block><xsl:value-of select="NumeroMensualite"/></fo:block></fo:table-cell>
</xsl:for-each>
</fo:table-row>
<fo:table-row border-bottom="thin solid &darkGreen;" border-top="thin solid &darkGreen;" border-left="thin solid &darkGreen;" border-right="thin solid &darkGreen;">
<fo:table-cell border-right="thin solid &darkGreen;" font-weight="600"><fo:block> Échéance</fo:block></fo:table-cell>
<xsl:for-each select="key('years', Mensualite/Lines/Line/AnneeEcheance)">
<fo:table-cell border-right="thin solid &darkGreen;"><fo:block><xsl:value-of select="concat(substring(DateEcheance,7,2),'/',substring(DateEcheance,5,2))"/></fo:block></fo:table-cell>
</xsl:for-each>
</fo:table-row>
<fo:table-row border-bottom="thin solid &darkGreen;" border-top="thin solid &darkGreen;" border-left="thin solid &darkGreen;" border-right="thin solid &darkGreen;">
<fo:table-cell border-right="thin solid &darkGreen;" font-weight="600"><fo:block> Montant (€)</fo:block></fo:table-cell>
<xsl:for-each select="key('years', Mensualite/Lines/Line/AnneeEcheance)">
<fo:table-cell border-right="thin solid &darkGreen;"><fo:block><xsl:value-of select="Montant"/></fo:block></fo:table-cell>
</xsl:for-each>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block/>
</fo:block-container>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
I need to split the table if the xml contains more then 12 Lines (columns in that case) and make a new table after.
I'm a bit stuck on it and it's really frustrating. Does anyone have any pointers?
I couldn't understand your XSLT.
To simplify the matter to the question of creating a separate table for every N lines, where each line forms a column, consider the following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="col-limit" select="5" />
<xsl:variable name="rows" select="/Facture/Mensualite/Lines/Line[1]/*" />
<xsl:template match="/Facture">
<root>
<xsl:apply-templates select="Mensualite/Lines/Line[position() mod $col-limit = 1]" />
</root>
</xsl:template>
<xsl:template match="Line">
<xsl:variable name="cols" select=". | following-sibling::Line[position() < $col-limit]"/>
<table border="1">
<xsl:for-each select="$rows">
<xsl:variable name="row" select="position()"/>
<tr>
<th><xsl:value-of select="name()"/></th>
<xsl:apply-templates select="$cols/*[$row]"/>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="Line/*">
<td><xsl:value-of select="."/></td>
</xsl:template>
</xsl:stylesheet>
When applied to your example input, the result (rendered) will be:
For the following xml file, i need to generate an xsl-fo file to be converted into pdf.
I am new to style sheets and struggling to create dynamic table. Please help.
Also, the width for each column varies,based on the column.How would i include this into the code?
The Column Headers and Column Values are dynamically populated in the xml file. Below is a sample.
Can anybody please help in generating xsl-fo or xslt code?
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ReportData>
<ColumnHeaders>
<ColumnHeader>
<Name>Col-Header1</Name>
<Width>5</Length>
</ColumnHeader>
<ColumnHeader>
<Name>Col-Header2</Name>
<Width>10</Length>
</ColumnHeader>
<ColumnHeader>
<Name>Col-Header3</Name>
<Width>8</Length>
</ColumnHeader>
</ColumnHeaders>
<Rows>
<Row>
<Column>Row1-Col1</Column>
<Column>Row1-Col2</Column>
<Column>Row1-Col3</Column>
</Row>
<Row>
<Column>Row2-Col1</Column>
<Column>Row2-Col2</Column>
<Column>Row2-Col3</Column>
</Row>
</Rows>
</ReportData>
This should get you started. I used cm for the column width and the page is 11" x 8.5" (landscape) so the table would fit on the page. This should be easy for you to change.
XML Input (fixed to be well-formed)
<ReportData>
<ColumnHeaders>
<ColumnHeader>
<Name>Col-Header1</Name>
<Width>5</Width>
</ColumnHeader>
<ColumnHeader>
<Name>Col-Header2</Name>
<Width>10</Width>
</ColumnHeader>
<ColumnHeader>
<Name>Col-Header3</Name>
<Width>8</Width>
</ColumnHeader>
</ColumnHeaders>
<Rows>
<Row>
<Column>Row1-Col1</Column>
<Column>Row1-Col2</Column>
<Column>Row1-Col3</Column>
</Row>
<Row>
<Column>Row2-Col1</Column>
<Column>Row2-Col2</Column>
<Column>Row2-Col3</Column>
</Row>
</Rows>
</ReportData>
XSLT 1.0
<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 indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="my-page" page-height="8.5in" page-width="11in">
<fo:region-body margin="1in" margin-top="1.5in" margin-bottom="1.5in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="my-page">
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="ReportData">
<fo:table>
<fo:table-header>
<fo:table-row>
<xsl:apply-templates select="ColumnHeaders/ColumnHeader"/>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:apply-templates select="Rows/Row"/>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="ColumnHeader">
<fo:table-cell width="{Width}cm" border="solid black 1px" padding="2px" font-weight="bold" text-align="center">
<fo:block><xsl:value-of select="Name"/></fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="Row">
<fo:table-row>
<xsl:apply-templates/>
</fo:table-row>
</xsl:template>
<xsl:template match="Column">
<fo:table-cell border="solid black 1px" padding="2px">
<fo:block><xsl:value-of select="."/></fo:block>
</fo:table-cell>
</xsl:template>
</xsl:stylesheet>
XSL-FO Output
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="my-page" page-height="8.5in" page-width="11in">
<fo:region-body margin="1in" margin-top="1.5in" margin-bottom="1.5in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="my-page">
<fo:flow flow-name="xsl-region-body">
<fo:table>
<fo:table-header>
<fo:table-row>
<fo:table-cell width="5cm"
border="solid black 1px"
padding="2px"
font-weight="bold"
text-align="center">
<fo:block>Col-Header1</fo:block>
</fo:table-cell>
<fo:table-cell width="10cm"
border="solid black 1px"
padding="2px"
font-weight="bold"
text-align="center">
<fo:block>Col-Header2</fo:block>
</fo:table-cell>
<fo:table-cell width="8cm"
border="solid black 1px"
padding="2px"
font-weight="bold"
text-align="center">
<fo:block>Col-Header3</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<fo:table-row>
<fo:table-cell border="solid black 1px" padding="2px">
<fo:block>Row1-Col1</fo:block>
</fo:table-cell>
<fo:table-cell border="solid black 1px" padding="2px">
<fo:block>Row1-Col2</fo:block>
</fo:table-cell>
<fo:table-cell border="solid black 1px" padding="2px">
<fo:block>Row1-Col3</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell border="solid black 1px" padding="2px">
<fo:block>Row2-Col1</fo:block>
</fo:table-cell>
<fo:table-cell border="solid black 1px" padding="2px">
<fo:block>Row2-Col2</fo:block>
</fo:table-cell>
<fo:table-cell border="solid black 1px" padding="2px">
<fo:block>Row2-Col3</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>
PDF Output
I have a table in an XSL-FO document and in a cell there's an article description, which can easily overflow a page, so I want it to be just cut after reaching a certain height with the cell. Is that possible? This is my example, I tried setting:
height="4cm"
and
block-dimension-progression.maximum="4cm"
but it doesn't work.
<fo:table-row keep-together.within-page="always" height="2cm">
<fo:table-cell border-right="1.5pt solid black">
<fo:block text-align="center">
<xsl:value-of select="count"/>
</fo:block>
</fo:table-cell>
<fo:table-cell border-right="1.5pt solid black" padding-left="2pt">
<fo:block>
<xsl:value-of select="name"/>
</fo:block>
<fo:block font-size="10pt"><xsl:value-of select="manufacturer"/> / <xsl:value-of select="identifier"/></fo:block>
<fo:block font-size="10pt"><xsl:value-of select="description"/></fo:block>
</fo:table-cell>
<fo:table-cell border-right="1.5pt solid black" padding-right="2pt">
<fo:block text-align="right">
<xsl:value-of select="unitprice"/>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block text-align="right">
<xsl:value-of select="totalprice"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
Put the block with the article description in a block-container with overflow="hidden" and the desired height set. Like this:
<fo:block-container overflow="hidden" height="2cm">
<fo:block font-size="10pt">Long description text goes here...</fo:block>
</fo:block-container>