XSLFO overlay image - xslt

I'm using ApacheFOP to create a pdf which has multiple pages of content and a watermark (semi-transparent) on every page. I'm struggling quite a bit with XSLFO and got a proof of concept working using the list functionality - however I imagine there is a simpler way. Can someone more familiar with xslfo provide a simpler solution? Below is my code:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes" />
<xsl:param name="watermarkPath" />
<xsl:param name="pdfPages" />
<xsl:template match="/">
<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="11in" page-width="8.5in" margin="0.5in">
<fo:region-body />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="my-page">
<fo:flow flow-name="xsl-region-body">
<xsl:for-each select="$pdfPages">
<fo:block-container>
<fo:list-block>
<fo:list-item>
<fo:list-item-label>
<fo:block>
<fo:external-graphic
content-width="7.5in">
<xsl:attribute name="src">
<xsl:value-of
select="concat('data:image/png;base64,',.)" />
</xsl:attribute>
</fo:external-graphic>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<fo:external-graphic
content-width="7.5in">
<xsl:attribute name="src">
<xsl:value-of select="$watermarkPath" />
</xsl:attribute>
</fo:external-graphic>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
</fo:block-container>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>

Not sure it works with FOP but if it was a full size image of the page ...
<fo:layout-master-set>
<fo:simple-page-master master-name="my-page"
page-height="11in" page-width="8.5in" margin="0.5in">
<fo:region-body />
<fo:region-before extent="11in" region-name="myheader" background-image="{path-to-my-image}"/>
</fo:simple-page-master>
</fo:layout-master-set>
If not, then put an absolute-positioned block-container inside the actual static-content for region "myheader" and don't use the background-image above.
<fo:page-sequence master-reference="my-page">
<fo:static-content flow-name="myheader">
<fo:block-container position="absolute" top="XX" left="XX">
<fo:block>
<fo:external-graphic .../>
</fo:block>
</fo:block-container>
</fo:static-content>
If you truly want an overlay (meaning over the top of all content) then put it in region-after and not before.

I put my background image in the region-body :
fo:region-body background-image="{$Url}"/

Related

I am trying to print multiple pages with fop

I am trying to addd multiple pages with this code. The content of each page works individiually. I looked for an example on how to add multiple pages but everyone I came has not worked for me. Am I making some general error here? It would be really helpful if some could add the basic structure I would need to use for to pages.
<?xml version="1.0" encoding="UTF-8" ?>
<fo:root
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
font-family="Freesans">
<fo:layout-master-set>
<fo:simple-page-master master-name="standard"
page-height="15.2cm"
page-width="8.1cm"
margin-top="1cm"
margin-bottom="1cm"
margin-left="1.5cm"
margin-right="1.5cm">
<fo:region-body margin-top="1cm"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="rest"
page-height="15.2cm"
page-width="8.1cm"
margin-top="1cm"
margin-bottom="1cm"
margin-left="1.5cm"
margin-right="1.5cm">
<fo:region-body margin-top="1cm"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="standard">
<fo:repeatable-page-master-reference master-name="rest"/>
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="standard" force-page-count="no-force">
<fo:flow flow-name="xsl-region-body" font-size="8pt">
<fo:block text-align="right" >
<fo:page-number/> / <fo:page-number-citation ref-id="totalPages"/>
</fo:block>
<!--content-->
<fo:block id="totalPages"></fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="rest" force-page-count="no-force">
<fo:flow flow-name="xsl-region-body" font-size="8pt">
<fo:block text-align="right" >
<fo:page-number/> / <fo:page-number-citation ref-id="totalPages"/>
</fo:block>
<!--content-->
<fo:block id="totalPages"></fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

XSL:FO border-style dotted

I am trying to add a dotted line inside a table. I
Below is the XSLT . When I use the border-style = "dotted" the line appears as a solid line and not a dotted line.
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:m="http://www.ibm.com/maximo">
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="hello" page-height="11in" page-width="8.5in" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="hello">
<fo:flow flow-name="xsl-region-body">
<fo:block>
<fo:tab le width="100mm">
<fo:table-column/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block border-before-style="dashed" border-before-width="1mm" border-before-width.length="1pt">sdsdasd</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
Is the dotted style not supported in XSL-FO. I am using FONET.dll for .Net
FO.NET started as a port of Apache FOP 0.20.4 to the .NET environment.
That version of FOP did not support the whole FO standard, the different border styles being among the unsupported features.

xsl:fo template match not firing on nested list

I need to use a hyphen for the bullet on a nested list applying xsl:fo. I have two templates to match but only one is being applied. If I use just the first template, the outer list gets the template applied. If I use just the second template, the nested list gets the template applied. The pattern I am attempting to match in the second template is any unordered list with a list item as a parent. Any help on getting my desired output is greatly appreciated.
XML
<ThisNode>
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three
<ul>
<li>Sub-Item One</li>
<li>Sub-Item Two</li>
</ul>
</li>
<li>Item Four</li>
<li>Item Five</li>
</ul>
</ThisNode>
XSLT
<xsl:template match="ul">
<fo:list-block>
<xsl:for-each select="./li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="8pt">
<fo:block><xsl:value-of select="."/></fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
<xsl:template match="li//ul">
<fo:list-block start-indent="8pt">
<xsl:for-each select="./li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block font-weight="bold">-</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="16pt">
<fo:block><xsl:value-of select="."/></fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
<fo:block text-align="left">
<xsl:apply-templates select="./ThisNode"/>
</fo:block>
DESIRED OUTPUT
• Item One
• Item Two
• Item Three
- Sub-Item One
- Sub-Item Two
• Item Four
• Item Five
ACTUAL OUTPUT USING EITHER JUST THE 1ST TEMPLATE OR USING BOTH
• Item One
• Item Two
• Item ThreeSub-Item OneSub-Item Two
• Item Four
• Item Five
ACTUAL OUTPUT USING ONLY THE 2ND TEMPLATE
Item One Item Two Item Three
- Sub-Item One
- Sub-Item Two
Item Four Item Five
This looks like a good place for a call-template with a mode, to distinguish between the 2 cases. The outer template calls the inner template:
<?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:template match="/">
<fo:block text-align="left">
<xsl:apply-templates select="ThisNode"/>
</fo:block>
</xsl:template>
<xsl:template match="ul">
<fo:list-block>
<xsl:for-each select="li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="8pt">
<fo:block>
<!-- I'm not quite sure what you want here -->
<xsl:value-of select="text()"/>
<xsl:apply-templates select="ul" mode="inner"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
<xsl:template match="ul" mode="inner">
<fo:list-block start-indent="8pt">
<xsl:for-each select="./li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block font-weight="bold">-</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="16pt">
<fo:block>
<xsl:value-of select="."/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
</xsl:stylesheet>
The following stylesheet illustrates a possible solution. Your approach is not far off - however, it fails to account for the behaviour of XSLT processors. This expression:
<xsl:value-of select="."/>
by default returns any text nodes that are children of the context node. But in your case (template match for li elements), all descendant text nodes are output, not only the immediate children of li.
Therefore, the stylesheet below uses
<xsl:value-of select="child::text()"/>
to retrieve the text content of a li element instead and <xsl:apply-templates> to process any li elements that are sub-items of it.
As your title states,
xsl:fo template match not firing on nested list
You diagnosed it correctly. This is because - once inside a template match for li - you do not let the XSLT processor process descendant li elements.
Stylesheet
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/ThisNode">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="simple"
page-height="29.7cm"
page-width="21cm"
margin-top="1cm"
margin-bottom="2cm"
margin-left="2.5cm"
margin-right="2.5cm">
<fo:region-body margin-top="3cm"/>
<fo:region-before extent="3cm"/>
<fo:region-after extent="1.5cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="ul[parent::ThisNode]">
<fo:list-block>
<xsl:apply-templates/>
</fo:list-block>
</xsl:template>
<xsl:template match="ul[parent::li]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="li">
<fo:list-item>
<xsl:choose>
<xsl:when test="parent::ul/parent::ThisNode">
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block><xsl:value-of select="child::text()"/></fo:block>
</fo:list-item-body>
</xsl:when>
<xsl:otherwise>
<fo:list-item-label start-indent="3cm">
<fo:block font-weight="bold">-</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="3.5cm">
<fo:block><xsl:value-of select="."/></fo:block>
</fo:list-item-body>
</xsl:otherwise>
</xsl:choose>
</fo:list-item>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
Output (XSL-FO)
<?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="simple" page-height="29.7cm" page-width="21cm" margin-top="1cm"
margin-bottom="2cm"
margin-left="2.5cm"
margin-right="2.5cm">
<fo:region-body margin-top="3cm"/>
<fo:region-before extent="3cm"/>
<fo:region-after extent="1.5cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<fo:flow flow-name="xsl-region-body">
<fo:list-block>
<fo:list-item>
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block>Item One</fo:block>
</fo:list-item-body>
</fo:list-item>Item One
<fo:list-item>
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block>Item Two</fo:block>
</fo:list-item-body>
</fo:list-item>Item Two
<fo:list-item>
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block>Item Three
</fo:block>
</fo:list-item-body>
</fo:list-item>Item Three
<fo:list-item>
<fo:list-item-label start-indent="3cm">
<fo:block font-weight="bold">-</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="3.5cm">
<fo:block>Sub-Item One</fo:block>
</fo:list-item-body>
</fo:list-item>Sub-Item One
<fo:list-item>
<fo:list-item-label start-indent="3cm">
<fo:block font-weight="bold">-</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="3.5cm">
<fo:block>Sub-Item Two</fo:block>
</fo:list-item-body>
</fo:list-item>Sub-Item Two
<fo:list-item>
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block>Item Four</fo:block>
</fo:list-item-body>
</fo:list-item>Item Four
<fo:list-item>
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block>Item Five</fo:block>
</fo:list-item-body>
</fo:list-item>Item Five
</fo:list-block>
</fo:flow>
</fo:page-sequence>
</fo:root>
Output (PDF)

Styling pdf using xslt

This is my following xslt code :
<?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">
<xsl:output encoding="iso-8859-1" />
<xsl:template match ="records">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="list">
<fo:region-body></fo:region-body>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="list">
<fo:flow flow-name="xsl-region-body">
<fo:block>
<fo:table>
<fo:table-body>
<xsl:for-each select="./list">
<fo:table-row>
<xsl:for-each select="./item">
<fo:table-cell border="solid 1px bold" text-align="center" backgr="green">
<fo:block><xsl:value-of select="val" /></fo:block>
</fo:table-cell>
</xsl:for-each>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
i am trying to add backgorund table-cell,but it is not working.
In foLtable-cell i have added backgr attribute, but it didnot worked.
The correct attribute for defining an background color is "background", but you used "backgr" instead. I tried the corrected code and it works as expected (using the Altsoft Xml2PDF Renderer).
It must be like
<fo:table-cell border="solid 1px bold" text-align="center"
background-color="green">
See also :XSL-FO table-cell Object
You can use the background-color attribute on a table-row or table-header element.
<fo:table-header background-color="#555">
or
<fo:table-row background-color="#555">

xsl:Template match xml node

I am new to XSL-FO and have a very basic question, the following are xsl and xml files.
I expect "xxx" to be outputted for every xml node "inhouse" (template match).
But I am not getting it.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="CustomerData">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple" page-height="29.7cm" page-width="21.0cm" margin-left="1.5cm" margin-right="1.5cm" margin-top="0cm">
<fo:region-body margin-top="3cm"/>
<fo:region-before extent="0cm"/>
<fo:region-after extent="0cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<fo:flow flow-name="xsl-region-body">
<fo:block font-family="Arial" font-size="8.5pt" font-weight="normal">
abc
</fo:block>
<xsl:template match="inhouse">
<fo:block color="#053679">
xxx
</fo:block>
</xsl:template>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CustomerData>
<inhouse>
<customerList>
<customer>
<name>Tom</name>
</customer>
</customerList>
</inhouse>
</CustomerData>
The issue here is that you have a template match for inhouse within your template match for CustomerData
<xsl:template match="CustomerData">
...
<xsl:template match="inhouse">
....
</xsl:template>
....
</xsl:template>
You are not allowed to nest templates in this way. What you need to do is move your inhouse template out of the current template, but instead tell the XSLT processor to start looking for other templates at that point with xsl:apply-templates. Something like this structure
<xsl:template match="CustomerData">
...
<xsl:apply-templates select="inhouse" />
...
</xsl:template>
<xsl:template match="inhouse">
....
</xsl:template>
In fact, it could be slightly better to replace <xsl:apply-templates select="inhouse" /> with just <xsl:apply-templates /> as this would handle the case where you have other elements other than inhouse you wanted to match.
Try this XSLT
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="CustomerData">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple" page-height="29.7cm" page-width="21.0cm" margin-left="1.5cm" margin-right="1.5cm" margin-top="0cm">
<fo:region-body margin-top="3cm"/>
<fo:region-before extent="0cm"/>
<fo:region-after extent="0cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<fo:flow flow-name="xsl-region-body">
<fo:block font-family="Arial" font-size="8.5pt" font-weight="normal">
abc
</fo:block>
<xsl:apply-templates />
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="inhouse">
<fo:block color="#053679">
xxx
</fo:block>
</xsl:template>
</xsl:stylesheet>