I have a table in FOP and it is working nicely until I get a very long word. The word then overwrites the cell ending in the table. I tried the wrap-option="wrap" within the table-cell and/or the block of the cell but it doesn't work
**Total Edit**
since I guess it is to complicated to just show bits here is the complete xsl file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="fo">
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes" />
<xsl:param name="tableCell" select="'1.0'" />
<!-- Globale Variablen START -->
<xsl:param name="tabbgcolor" select="'#EEEEEE'" />
<!-- Globale Variablen ENDE -->
<xsl:template match="/datasheet">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<fo:layout-master-set>
<fo:simple-page-master page-height="29.7cm" page-width="21cm" margin-top="1cm" margin-bottom="1cm" margin-left="1.5cm" margin-right="1.5cm" master-name="first">
<fo:region-body margin-top="20mm" margin-bottom="20mm" />
<fo:region-before extent="15mm" />
<fo:region-after extent="15mcm" />
</fo:simple-page-master>
<fo:simple-page-master master-name="new" margin-right="1.0cm" margin-left="1.0cm" margin-bottom="1cm" margin-top="1cm" page-height="21cm" page-width="29.7cm">
<fo:region-body margin-top="30mm" margin-bottom="20mm" />
<fo:region-before extent="30mm" />
<fo:region-after extent="15mm" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence language="de" country="DE" master-reference="new" initial-page-number="1">
<fo:static-content flow-name="xsl-region-before">
<fo:block text-align="center" font-size="12pt" padding="5pt" font-weight="bold">
<xsl:value-of select="title" />
</fo:block>
<fo:block text-align="right" font-size="12pt" padding="5pt" font-weight="bold">
<xsl:value-of select="date" />
</fo:block>
<fo:block text-align="right" font-size="12pt" padding="0pt" font-weight="bold">
<xsl:value-of select="time" />
</fo:block>
<fo:block>
<fo:leader leader-length="100%" leader-pattern="rule" rule-thickness="2pt" color="black" />
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
<fo:block text-align="center">
Seite
<fo:page-number />
von
<fo:page-number-citation ref-id="TheVeryLastPage" />
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block>
<fo:leader />
</fo:block>
<fo:block>
<fo:leader />
</fo:block>
<fo:block>
<fo:leader />
</fo:block>
<fo:block font-weight="bold" padding="5pt" padding-top="25pt">
Jahre <xsl:value-of select="fromYear" /> bis <xsl:value-of select="toYear" />
</fo:block>
<fo:block text-align="center">
<xsl:choose>
<xsl:when test="dataList != ''">
<fo:table table-layout="fixed" width="100%" border-style="solide" border-width="1pt">
<fo:table-column column-width="25%" border-style="solid" border-width="1pt" />
<fo:table-column column-width="25%" border-style="solid" border-width="1pt" />
<fo:table-column column-width="25%" border-style="solid" border-width="1pt" />
<fo:table-column column-width="25%" border-style="solid" border-width="1pt" />
<fo:table-header>
<fo:table-row>
<fo:table-cell border-style="solid" font-weight="bold" border-width="0pt">
<fo:block>
Cell1
</fo:block>
</fo:table-cell>
<fo:table-cell border-style="solid" font-weight="bold" border-width="0pt">
<fo:block>
Cell2
</fo:block>
</fo:table-cell>
<fo:table-cell border-style="solid" font-weight="bold" border-width="0pt">
<fo:block>
Cell3
</fo:block>
</fo:table-cell>
<fo:table-cell border-style="solid" font-weight="bold" border-width="0pt">
<fo:block>
Cell4
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:for-each select="dataList">
<fo:table-row>
<fo:table-cell padding="5pt" border-style="solid" border-width="1pt">
<fo:block text-align="left">
<xsl:value-of select="data1" />
</fo:block>
</fo:table-cell>
<fo:table-cell padding="5pt" border-style="solid" border-width="1pt">
<fo:block text-align="left">
<xsl:value-of select="data2" />
</fo:block>
</fo:table-cell>
<fo:table-cell padding="5pt" border-style="solid" border-width="1pt">
<fo:block text-align="left">
<xsl:value-of select="data3" />
</fo:block>
</fo:table-cell>
<fo:table-cell padding="5pt" border-style="solid" border-width="1pt">
<fo:block text-align="left">
<xsl:call-template name="intersperse-with-zero-spaces">
<xsl:with-param name="str" select="data4"/>
</xsl:call-template>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:when>
<xsl:otherwise>
<fo:block padding="6cm" text-align="center" font-weight="bold" font-size="16pt">No data.
</fo:block>
</xsl:otherwise>
</xsl:choose>
</fo:block>
<fo:block id="TheVeryLastPage">
</fo:block>
</fo:flow>
</fo:page-sequence>
<!-- ___________________________________________________________________________________________________________ -->
</fo:root>
</xsl:template>
<xsl:template name="intersperse-with-zero-spaces">
<xsl:param name="str"/>
<xsl:variable name="spacechars">
</xsl:variable>
<xsl:if test="string-length($str) > 0">
<xsl:variable name="c1" select="substring($str, 1, 1)"/>
<xsl:variable name="c2" select="substring($str, 2, 1)"/>
<xsl:value-of select="$c1"/>
<xsl:if test="$c2 != '' and
not(contains($spacechars, $c1) or
contains($spacechars, $c2))">
<xsl:text></xsl:text>
</xsl:if>
<xsl:call-template name="intersperse-with-zero-spaces">
<xsl:with-param name="str" select="substring($str, 2)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
The cell data4 is the one with the problems.... like 255 digits or characters at once with no hyphen oder space.
The input is from a database but could be like:
<datasheet>
<dataList>
<data1>intro</data1>
<data2>section</data2>
<data3>cutters</data3>
<data4>743576746876357467569384657654687465874638563465873487435767468763574675693846576546874658746385634658734874357674687635746756938465765468746587463856346587348743576746876357467569384657654687465874638563465873487435767468763574675693846576546874658746385634658734874357674687635746756938465765468746587463856346587348743576746876357467569384657654687465874638563465873487435767468763574675693846576546874658746385634658734874357674687635746756938465765468746587463856346587348743576746876357467569384657654687465874638563465873487435767468763574675693846576546874658746385634658734874357674687635746756938465765468746587463856346587348</data4>
</dataList>
</datasheet>
the result should be a table like:
|cell1 |cell2 |cell3 |cell4 |
_________________________________
|intro |section|cutters|7435767|
|4687635|
|7467569|
|3846576|
_________________________________
and so on in cell 4
Now the above works
<xsl:template name="intersperse-with-zero-spaces">
<xsl:param name="str"/>
<xsl:variable name="spacechars">
</xsl:variable>
<xsl:if test="string-length($str) > 0">
<xsl:variable name="c1" select="substring($str, 1, 1)"/>
<xsl:variable name="c2" select="substring($str, 2, 1)"/>
<xsl:value-of select="$c1"/>
<xsl:if test="$c2 != '' and
not(contains($spacechars, $c1) or
contains($spacechars, $c2))">
<xsl:text></xsl:text>
</xsl:if>
<xsl:call-template name="intersperse-with-zero-spaces">
<xsl:with-param name="str" select="substring($str, 2)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
calling place use to call like below:
<fo:block text-align="left">
<xsl:call-template name="intersperse-with-zero-spaces">
<xsl:with-param name="str" select="data4"/>
</xsl:call-template>
</fo:block>
I tested, it's working fine.
One option would be for you to break up the long number/word in XSLT while you're transforming to FO. You'd have to decide where you want it to break.
See also:
XSL-FO fop. Long text flows into adjacent cells/block, obscuring stuff there
Update (copied from comment):
There must be copy/paste errors in the stylesheet... there is an <xsl:param>, which is only supposed to occur at the beginning of a template, in the middle of the template. The stylesheet is therefore invalid. Are there supposed to be two templates? Also, I don't yet see the template named intersperse-with-zero-spaces; but maybe you're still adding it.
Update 2:
The above has been fixed in the Question.
I had assumed the second template couldn't be intersperse-with-zero-spaces, since it was calling that template. It didn't occur to me that it was supposed to be a recursive template!
By the way, if you have the option of using XSLT 2.0, the intersperse-with-zero-spaces template could be replaced by a much more efficient regexp replace.
Add hyphenate="true", then it will automatically adjust the spaces in the table cell.
<fo:table-cell border-bottom-width="0px" border-left-width="0px"
border-right-width="0px" border-top-width="0px" font-size="9px"
padding-left="0px" border-style="solid" border-width="1pt"
border-color="white" padding-start="0px" padding-end="2px"
padding-before="0px" padding-after="0px" width="16%" display-align="center"
text-align="start" hyphenate="true">
Related
I have this problem where I need to remove table cells when they are empty. But they always leave a small gap.
If the user fills out every option, the table is normal. If the user only fills out some fields then the table generates this dark horizontal line.
I suspect it is the empty cells bunching up.
<?xml version="1.0" encoding="UTF-8"?>
<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 version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" media-type="text/html" />
<xsl:template match="fwcF17Part35Page">
<xsl:apply-templates select="part35Details"/>
</xsl:template>
<xsl:template match="part35Details">
<fo:block keep-together.within-page="always">
<fo:block padding="5pt"/>
<fo:block font-size="16pt" text-align="left">
Upload Documents - test
</fo:block>
<fo:block>
<fo:leader leader-pattern="rule" leader-length="100%" rule-style="solid" rule-thickness="2pt"/>
</fo:block>
<fo:block padding="8pt"/>
<fo:block background-color="#ebe8e8" font-size="10pt" font-weight="bold">
Document(s)
</fo:block>
<fo:block padding="4px" font-size="8pt" font-weight="normal" text-align="center">
<fo:table>
<fo:table-column column-width="50%" />
<fo:table-column column-width="50%" />
<fo:table-header>
<fo:table-row>
<fo:table-cell border-style="solid" padding="2pt">
<fo:block font-weight="bold">Document Name</fo:block>
</fo:table-cell>
<fo:table-cell border-style="solid" padding="2pt">
<fo:block font-weight="bold">Document Type</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:for-each select="/root/pages/page_12/sections/fwcF17DocumentUpload/data">
<fo:table-row>
<xsl:choose>
<xsl:when test="size > 0">
<fo:table-cell border-style="solid" padding="2pt">
<fo:block>
<xsl:value-of select="name" />
</fo:block>
</fo:table-cell>
</xsl:when>
<xsl:otherwise>
<fo:table-cell>
<fo:block>
</fo:block>
</fo:table-cell>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="size > 0">
<fo:table-cell border-style="solid" padding="2pt">
<fo:block>
<xsl:value-of select="documentType" />
</fo:block>
</fo:table-cell>
</xsl:when>
<xsl:otherwise>
<fo:table-cell>
<fo:block>
</fo:block>
</fo:table-cell>
</xsl:otherwise>
</xsl:choose>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</fo:block>
</xsl:template>
</xsl:stylesheet>
I have tried putting in:
<fo:table-cell visilibity="hidden">
<fo:table-cell display="none">
<fo:table-cell height="0px">
Wrong output when there are empty cells:
Correct output when there are no empty cells:
Only create fo:table-row if your data fulfills the filter size > 0
You can do that by adding a predicate to your for-each.
In addition you can use that same predicate in the match, te ensure that there will be not a invalid fo:table constructed.
The xslt would then look like this:
<?xml version="1.0" encoding="UTF-8"?>
<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 version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" media-type="text/html" />
<xsl:template match="fwcF17Part35Page">
<xsl:apply-templates select="part35Details"/>
</xsl:template>
<xsl:template match="part35Details[/root/pages/page_12/sections/fwcF17DocumentUpload/data[size > 0]]">
<fo:block keep-together.within-page="always">
<fo:block padding="5pt"/>
<fo:block font-size="16pt" text-align="left">
Upload Documents - test
</fo:block>
<fo:block>
<fo:leader leader-pattern="rule" leader-length="100%" rule-style="solid" rule-thickness="2pt"/>
</fo:block>
<fo:block padding="8pt"/>
<fo:block background-color="#ebe8e8" font-size="10pt" font-weight="bold">
Document(s)
</fo:block>
<fo:block padding="4px" font-size="8pt" font-weight="normal" text-align="center">
<fo:table>
<fo:table-column column-width="50%" />
<fo:table-column column-width="50%" />
<fo:table-header>
<fo:table-row>
<fo:table-cell border-style="solid" padding="2pt">
<fo:block font-weight="bold">Document Name</fo:block>
</fo:table-cell>
<fo:table-cell border-style="solid" padding="2pt">
<fo:block font-weight="bold">Document Type</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:for-each select="/root/pages/page_12/sections/fwcF17DocumentUpload/data[size > 0]">
<fo:table-row>
<fo:table-cell border-style="solid" padding="2pt">
<fo:block>
<xsl:value-of select="name" />
</fo:block>
</fo:table-cell>
<fo:table-cell border-style="solid" padding="2pt">
<fo:block>
<xsl:value-of select="documentType" />
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</fo:block>
</xsl:template>
</xsl:stylesheet>
It would be really helpful if you would add a minimal xml-source-sample to your question to better understand your xslt.
I.e: your template match: <xsl:template match="part35Details"> looks somewhat strange. The template does not use the context.
I am using apache fop to produce a PDF, I have an XSL-FO template that produces a table and I would like to be able to call the template multiple times, with different select parameters.
here is my xsl stylesheet
<xsl:stylesheet 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"
version="1.0">
<xsl:output method="html"/>
<xsl:template name="checklist">
<xsl:param name="H1"/>
<xsl:param name="H2"/>
<xsl:param name="H3"/>
<xsl:param name="src"/>
<fo:block width="19cm" >
<fo:table font-size="8pt" table-layout="fixed" width="100%">
<fo:table-column column-width="1.2cm"/>
<fo:table-column column-width="16.5cm"/>
<fo:table-column column-width="1.2cm"/>
<fo:table-header font-weight="bold" background-color="lightgrey">
<fo:table-row>
<fo:table-cell>
<fo:block><xsl:value-of select="$H1"/></fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block text-align="center"><xsl:value-of select="$H2"/></fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block><xsl:value-of select="$H3"/></fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:apply-templates select="$src" />
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template match="item">
<fo:table-row line-stacking-strategy="line-height" margin="0mm" space-before="1mm" background-color="white">
<xsl:variable name="hdr" select="hdr"/>
<xsl:choose>
<xsl:when test="$hdr = 'y'">
<fo:table-cell number-columns-spanned="3" background-color="lightgrey" border="1px solid #b8b6b6">
<fo:block>
<fo:inline>
<xsl:value-of select="id"/>
<xsl:value-of select="description"/>
</fo:inline>
</fo:block>
</fo:table-cell>
</xsl:when>
<xsl:otherwise>
<fo:table-cell border="1px solid #b8b6b6" vertical-align="middle" text-align="center">
<fo:block line-height="4mm">
<xsl:value-of select="id"/>
</fo:block>
</fo:table-cell>
<fo:table-cell border="1px solid #b8b6b6" padding-left="3pt">
<fo:block>
<xsl:value-of select="description"/>
</fo:block>
</fo:table-cell>
<fo:table-cell border="1px solid #b8b6b6" text-align="center" padding-right="3pt">
<xsl:variable name="outcome" select="outcome"/>
<fo:block color="white">
<!--<fo:external-graphic src="file:///F:/Projects/Active/eCert/src/resources/c1.svg" width="4.0mm" height="4.0mm" content-width="scale-to-fit" content-height="scale-to-fit"/>-->
<xsl:choose>
<xsl:when test="$outcome = 'ok'">
<fo:external-graphic src="file:///F:/Projects/Active/eCert/src/resources/c1n.svg" vertical-align="middle" height="4.0mm" content-height="scale-to-fit"/>
</xsl:when>
<xsl:when test="$outcome = 'c1'">
<fo:external-graphic src="file:///F:/Projects/Active/eCert/src/resources/ok.svg" vertical-align="middle" height="3.9mm" content-height="scale-to-fit"/>
</xsl:when>
<xsl:when test="$outcome = 'c2'">
<fo:external-graphic src="file:///F:/Projects/Active/eCert/src/resources/c2.svg" vertical-align="middle" height="3.8mm" content-height="scale-to-fit"/>
</xsl:when>
<xsl:when test="$outcome = 'c3'">
<fo:external-graphic src="file:///F:/Projects/Active/eCert/src/resources/c3.svg" vertical-align="middle" height="3.7mm" content-height="scale-to-fit"/>
</xsl:when>
<xsl:when test="$outcome = 'fi'">
<fo:external-graphic src="file:///F:/Projects/Active/eCert/src/resources/fi.svg" vertical-align="middle" height="3.6mm" content-height="scale-to-fit"/>
</xsl:when>
<xsl:when test="$outcome = 'nv'">
<fo:external-graphic src="file:///F:/Projects/Active/eCert/src/resources/nv.svg" vertical-align="middle" height="3.5mm" content-height="scale-to-fit"/>
</xsl:when>
<xsl:when test="$outcome = 'na'">
<fo:external-graphic src="file:///F:/Projects/Active/eCert/src/resources/na.svg" vertical-align="middle" height="3.4mm" content-height="scale-to-fit"/>
</xsl:when>
<xsl:when test="$outcome = 'lim'">
<fo:external-graphic src="file:///F:/Projects/Active/eCert/src/resources/lim.svg" vertical-align="middle" height="3.3mm" content-height="scale-to-fit"/>
</xsl:when>
</xsl:choose>
</fo:block>
</fo:table-cell>
</xsl:otherwise>
</xsl:choose>
</fo:table-row>
</xsl:template>
</xsl:stylesheet>
And here is one of the flows that calls the template
<fo:flow flow-name="xsl-region-body">
<fo:block />
<xsl:call-template name="checklist">
<xsl:with-param name="H1" select="'Item No.'"/>
<xsl:with-param name="H2" select="'Description'"/>
<xsl:with-param name="H3" select="'Outcome'"/>
<xsl:with-param name="src" select="'eicr/checklist/item'"/>
</xsl:call-template>
</fo:flow>
When I execute FOP I get the following error ** Can not convert #STRING to a NodeList!**
Parameters H1, H2 and H3 are used as the column headers and that part works fine
The src param is the one that should be used to select the items from from an xml list.
I am new xsl fo so any help or pointers to documentation that can help me achieve the desired result would be appreciated.
Many thanks
Remove the single-quotes around eicr/checklist/item. 'eicr/checklist/item' is a string literal; eicr/checklist/item is a location path that will select elements relative to the context node.
The alternative that I was trying to avoid (because it's more verbose) is to apply templates before or as part of calling the template and then just copying the result to the result tree:
<xsl:with-param name="src">
<xsl:apply-templates select="eicr/checklist/item" />
</xsl:with-param>
<fo:table-body>
<xsl:copy-of select="$src" />
</fo:table-body>
It's a technique that you see in the DocBook XSLT 1.0 stylesheets, e.g.:
https://github.com/docbook/xslt10-stylesheets/blob/6ff683948c5a85949e4b7661f302e8b5f12f7bf2/xsl/fo/block.xsl#L181
I am trying to group values of individual column in xsl fo:table, some values not grouped as expected, it get grouped according to previous column's grouped value,
i need individual grouping in columns, check with my xsl and xml file, i am using these files to generate PDF file using apache FOP.
My XSL File
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="data">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple"
page-height="8.5in" page-width="11in" margin-top=".5in"
margin-bottom=".5in" margin-left=".5in" margin-right=".5in">
<fo:region-body margin-top="2cm" margin-bottom="2cm" />
<fo:region-before extent="2cm" overflow="hidden" />
<fo:region-after extent="1cm" overflow="hidden" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple"
initial-page-number="1">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-size="13.0pt" font-family="serif"
padding-after="2.0pt" space-before="4.0pt" text-align="center"
border-bottom-style="solid" border-bottom-width="1.0pt">
<xsl:text>PDF Test</xsl:text>
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
<fo:block font-size="12.0pt" font-family="sans-serif"
padding-after="2.0pt" space-before="2.0pt" text-align="center"
border-top-style="solid" border-bottom-width="1.0pt">
<xsl:text>Page</xsl:text>
<fo:page-number />
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates select="data-body" />
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="data-body">
<fo:block text-align="center">
<fo:table table-layout="fixed" width="100%"
border-style="dashed">
<fo:table-column border-style="solid" />
<fo:table-column border-style="solid" />
<fo:table-column border-style="solid" />
<fo:table-header>
<xsl:apply-templates select="table-header" />
</fo:table-header>
<fo:table-body>
<xsl:for-each-group select="table-data" group-adjacent="column-two">
<xsl:apply-templates select="current-group()">
<xsl:with-param name="row-span" select="count(current-group())" tunnel="yes"/>
</xsl:apply-templates>
</xsl:for-each-group>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template match="table-header">
<fo:table-row keep-together.within-page="always"
border-style="solid">
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-one"></xsl:value-of>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-two"></xsl:value-of>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-three"></xsl:value-of>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
<xsl:template match="table-data">
<fo:table-row keep-together.within-page="always"
border-style="solid">
<xsl:apply-templates>
<xsl:with-param name="row-group-index" tunnel="yes" select="position()"/>
</xsl:apply-templates>
</fo:table-row>
</xsl:template>
<xsl:template match="table-data/*">
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="."></xsl:value-of>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="table-data/column-two">
<xsl:param name="row-span" tunnel="yes"/>
<xsl:param name="row-group-index" tunnel="yes"/>
<xsl:choose>
<xsl:when test="$row-span = 1">
<xsl:next-match/>
</xsl:when>
<xsl:when test="$row-span > 1 and $row-group-index = 1">
<fo:table-cell number-rows-spanned="{$row-span}">
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="."></xsl:value-of>
</fo:block>
</fo:table-cell>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="table-data/column-three">
<xsl:param name="row-span" tunnel="yes"/>
<xsl:param name="row-group-index" tunnel="yes"/>
<xsl:choose>
<xsl:when test="$row-span = 1">
<xsl:next-match/>
</xsl:when>
<xsl:when test="$row-span > 1 and $row-group-index = 1">
<fo:table-cell number-rows-spanned="{$row-span}">
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="."></xsl:value-of>
</fo:block>
</fo:table-cell>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
My XML File
<?xml version="1.0" encoding="UTF-8"?>
<data>
<data-body>
<table-header>
<column-one>Column One</column-one>
<column-two>Column Two</column-two>
<column-three>Column Three</column-three>
</table-header>
<table-data>
<column-one>One</column-one>
<column-two>5000</column-two>
<column-three>Three</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>5000</column-two>
<column-three>Three</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>1200</column-two>
<column-three>Three</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>2000</column-two>
<column-three>Four</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>2000</column-two>
<column-three>Four</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>1234</column-two>
<column-three>Five</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>5666</column-two>
<column-three>Five</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>5666</column-two>
<column-three>Five</column-three>
</table-data>
</data-body>
</data>
I think one way to solve that is to use two passes, one which computes and adds the row-span to columns, and the second that transforms to XSL-FO.
In https://xsltfiddle.liberty-development.net/3NSSEuY/2 I have used XSLT 3 and xsl:iterate to implement the first step for a sequence of column names provided as an xs:string* parameter:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="columns-to-group" as="xs:string*" select="'column-two', 'column-three'"/>
<xsl:mode name="compute-row-spans" on-no-match="shallow-copy"/>
<xsl:mode name="compute-row-span" on-no-match="shallow-copy"/>
<xsl:template match="data-body" mode="compute-row-spans">
<xsl:iterate select="$columns-to-group">
<xsl:param name="table" select="."/>
<xsl:on-completion select="$table"/>
<xsl:next-iteration>
<xsl:with-param name="table">
<xsl:apply-templates select="$table" mode="compute-row-span">
<xsl:with-param name="column-to-group" tunnel="yes" select="."/>
</xsl:apply-templates>
</xsl:with-param>
</xsl:next-iteration>
</xsl:iterate>
</xsl:template>
<xsl:template match="data-body" mode="compute-row-span">
<xsl:param name="column-to-group" as="xs:string" tunnel="yes"/>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="table-header"/>
<xsl:for-each-group select="table-data" group-adjacent="*[name() = $column-to-group]">
<xsl:apply-templates select="current-group()" mode="compute-row-span">
<xsl:with-param name="column-to-group" tunnel="yes" select="$column-to-group"/>
<xsl:with-param name="row-span" select="count(current-group())" tunnel="yes"/>
</xsl:apply-templates>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="table-data" mode="compute-row-span">
<xsl:copy>
<xsl:apply-templates select="#*" mode="#current"/>
<xsl:apply-templates select="*" mode="#current">
<xsl:with-param name="current-row-index" tunnel="yes" select="position()"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="table-data/*" mode="compute-row-span">
<xsl:param name="column-to-group" tunnel="yes"/>
<xsl:param name="row-span" tunnel="yes"/>
<xsl:param name="current-row-index" tunnel="yes"/>
<xsl:choose>
<xsl:when test="name() = $column-to-group and $row-span > 1">
<xsl:if test="$current-row-index = 1">
<xsl:copy>
<xsl:apply-templates select="#*" mode="#current"/>
<xsl:attribute name="row-span" select="$row-span"/>
<xsl:apply-templates mode="#current"/>
</xsl:copy>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:next-match/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="data">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple"
page-height="8.5in" page-width="11in" margin-top=".5in"
margin-bottom=".5in" margin-left=".5in" margin-right=".5in">
<fo:region-body margin-top="2cm" margin-bottom="2cm" />
<fo:region-before extent="2cm" overflow="hidden" />
<fo:region-after extent="1cm" overflow="hidden" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple"
initial-page-number="1">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-size="13.0pt" font-family="serif"
padding-after="2.0pt" space-before="4.0pt" text-align="center"
border-bottom-style="solid" border-bottom-width="1.0pt">
<xsl:text>PDF Test</xsl:text>
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
<fo:block font-size="12.0pt" font-family="sans-serif"
padding-after="2.0pt" space-before="2.0pt" text-align="center"
border-top-style="solid" border-bottom-width="1.0pt">
<xsl:text>Page</xsl:text>
<fo:page-number />
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates select="data-body" />
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="data-body">
<fo:block text-align="center">
<fo:table table-layout="fixed" width="100%"
border-style="dashed">
<fo:table-column border-style="solid" />
<fo:table-column border-style="solid" />
<fo:table-column border-style="solid" />
<fo:table-header>
<xsl:apply-templates select="table-header" />
</fo:table-header>
<xsl:variable name="table-with-row-spans">
<xsl:apply-templates select="." mode="compute-row-spans"/>
</xsl:variable>
<fo:table-body>
<xsl:apply-templates select="$table-with-row-spans/data-body/table-data"/>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template match="table-header">
<fo:table-row keep-together.within-page="always"
border-style="solid">
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-one"></xsl:value-of>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-two"></xsl:value-of>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-three"></xsl:value-of>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
<xsl:template match="table-data">
<fo:table-row keep-together.within-page="always"
border-style="solid">
<xsl:apply-templates/>
</fo:table-row>
</xsl:template>
<xsl:template match="table-data/*">
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:apply-templates/>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="table-data/*[#row-span]">
<fo:table-cell number-rows-spanned="{#row-span}">
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:apply-templates/>
</fo:block>
</fo:table-cell>
</xsl:template>
</xsl:stylesheet>
Here is snippet of my xsl:
<fo:table-row height="27.8mm">
<fo:table-cell border-bottom="0.2mm solid" number-columns-spanned="2">
<fo:table border="0px solid"
border-collapse="collapse"
table-layout="fixed"
width="100%"
height="100%">
<fo:table-column column-width="110mm"/>
<fo:table-body>
<fo:table-row height="27.8mm">
<fo:table-cell border-bottom="0.2mm solid" height="28mm">
<xsl:call-template name="LabelTemplate">
<xsl:with-param name="name" select="'REFERENCE'"/>
</xsl:call-template>
<xsl:call-template name="ReferenceTemplate">
<xsl:with-param name="First" select="First"/>
<xsl:with-param name="Second" select="Second"/>
<xsl:with-param name="eNo" select="eNo"/>
</xsl:call-template>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:table-cell>
</fo:table-row>
When using inline container inside ReferenceTemplate nothing is displayed.
<xsl:template name="ReferenceTemplate">
<xsl:param name="First"/>
<xsl:param name="Second"/>
<xsl:param name="eNo"/>
<xsl:param name="size" select="'22pt'"/>
<xsl:param name="left" select="'5pt'"/>
<xsl:param name="top" select="'15px'"/>
<xsl:param name="text-indent" select="'5px'"/>
<fo:block-container
position="absolute"
top="{$top}" left="{$left}" right="5pt"
width="auto"
border="0px solid">
<fo:inline-container vertical-align="top" inline-progression-dimension="49.9%">
<fo:block><xsl:value-of select="$Second"/></fo:block>
</fo:inline-container>
<fo:inline-container vertical-align="top" inline-progression-dimension="49.9%">
<fo:block><xsl:value-of select="$First"/></fo:block>
</fo:inline-container>
</fo:block-container>
</xsl:template>
When using this sample instead of inline container content is displayed.
<fo:block text-align-last="justify">
<xsl:value-of select="$Second"/>
<fo:leader leader-pattern="space" />
<xsl:value-of select="$First"/>
</fo:block>
I think you cannot embed an fo:inline-container into an fo:block-container.
See this reference for fo:block-container - fo:inline-container is not in the list of allowed children.
I'm trying to render this list as a table in xsl-fo
<ul class="tablelist">
<li class="a">A</li>
<li class="a">A
</li>
<li class="b">B
</li>
<li class="b">B
</li>
<li class="a">A</li>
<li class="b">B</li>
<li class="a">A</li>
</ul>
All the ones with class A in the left column, all the ones with class B in the right column.
My current solution:
<fo:table>
<fo:table-column column-number="1" column-width="30mm"/>
<fo:table-column column-number="2" />
<fo:table-body>
<xsl:for-each select="li[#class='a']">
<fo:table-row>
<fo:table-cell column-number="1">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
<xsl:for-each select="li[#class='b']">
<fo:table-row>
<fo:table-cell column-number="2">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
... doesnt work, of course. What would I need to change?
Thanks for help!
EDIT:
Desired output in this case would be:
<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>
A
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
B
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block>
A
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
B
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block>
A
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
B
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block>
A
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block/
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
because there are four class="a" and three class="b"elements. So, 4 rows in total, in 4 rows the left cell is A and in three of those rows, the right column is B.
Hope, it is a bit clearer now!
Here's another way you could look at it:
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:template match="/">
<table>
<xsl:call-template name="generate-rows">
<xsl:with-param name="left" select="ul/li[#class='a']"/>
<xsl:with-param name="right" select="ul/li[#class='b']"/>
</xsl:call-template>
</table>
</xsl:template>
<xsl:template name="generate-rows">
<xsl:param name="left"/>
<xsl:param name="right"/>
<xsl:param name="i" select="1"/>
<xsl:if test="$i <= count($left) or $i <= count($right)">
<row>
<cell><xsl:value-of select="$left[$i]"/></cell>
<cell><xsl:value-of select="$right[$i]"/></cell>
</row>
<xsl:call-template name="generate-rows">
<xsl:with-param name="left" select="$left"/>
<xsl:with-param name="right" select="$right"/>
<xsl:with-param name="i" select="$i + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
One option is to use position() to apply-templates to the element with the opposite class that's in the same position.
If you know that there will always be more a class elements than b class elements (or if you don't care what happens to the remaining b class elements), you could do something like this:
<xsl:template match="ul[#class='tablelist']">
<fo:table>
<fo:table-column column-number="1" column-width="30mm"/>
<fo:table-column column-number="2" />
<fo:table-body>
<xsl:for-each select="li[#class='a']">
<xsl:variable name="pos" select="position()"/>
<fo:table-row>
<fo:table-cell column-number="1">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:table-cell>
<fo:table-cell column-number="2">
<fo:block>
<xsl:apply-templates select="../li[#class='b'][position()=$pos]"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
If you do care about those b class elements, when there are more b than a, you could do something like this:
<xsl:template match="ul[#class='tablelist']">
<fo:table>
<fo:table-column column-number="1" column-width="30mm"/>
<fo:table-column column-number="2" />
<fo:table-body>
<xsl:choose>
<xsl:when test="count(li[#class='a']) >= count(li[#class='a'])">
<xsl:apply-templates select="li[#class='a']" mode="createRow"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="li[#class='b']" mode="createRow"/>
</xsl:otherwise>
</xsl:choose>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="li[#class='a']" mode="createRow">
<xsl:variable name="pos" select="position()"/>
<fo:table-row>
<fo:table-cell column-number="1">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:table-cell>
<fo:table-cell column-number="2">
<fo:block>
<xsl:apply-templates select="../li[#class='b'][position()=$pos]"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
<xsl:template match="li[#class='b']" mode="createRow">
<xsl:variable name="pos" select="position()"/>
<fo:table-row>
<fo:table-cell column-number="1">
<fo:block>
<xsl:apply-templates select="../li[#class='a'][position()=$pos]"/>
</fo:block>
</fo:table-cell>
<fo:table-cell column-number="2">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>