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