XSL-FO - Center Text not working - alignment

In my XSL-FO, I am having problems centering text as it breaks the footnote-line2 into 2 sentences as opposed to going the full length of the page and then breaking the sentence once it runs out of room. See graphics below.
I have this code:
<fo:block font-size="9pt" text-align="center">
<xsl:value-of select="footnote-line1"/>
</fo:block>
<fo:block font-size="9pt" text-align="center">
<xsl:value-of select="footnote-line2"/>
</fo:block>
Here is my XML:
<footnote-line1>This verification of XXXXXX is self-generated and is produced by John Smith from our secure website.</footnote-line1>
<footnote-line2>If there are any questions regarding the information contained in this letter, you may contact the Joe Blow at his office at the contact information noted above.</footnote-line2>
Which generates this output::
Unfortunately, the above image is not what I want as it is doing a paragraph break after the word "you".
This 2 images below are the output I am hoping to get. The first image I achieved that was by shrinking down the font to 6pt, but I don't want to shrink the font down.
Option 1) Alternate solution, but would rather not shrink down the font size
Option 2) Optimal solution without shrinking the font
How would I achieve option #2?
Updated with colored backgrounds and both are the same length for the first and second footnotes:
Here is the full XSL-FO document:
<xsl:stylesheet version="1.0" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" indent="yes" encoding="UTF-8"/>
<xsl:output indent="yes"/>
<xsl:template match="/">
<fo:root font-family="Times Roman" font-size="9pt">
<fo:layout-master-set>
<fo:simple-page-master master-name="main-voe"
margin-top="15mm" margin-bottom="15mm" margin-left="25mm" margin-right="25mm" page-width="215mm" page-height="279mm">
<fo:region-body margin-top="1.0in" margin-bottom="1.0in"/>
<fo:region-before extent="1.0in" margin-top="1.0in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="main-voe" initial-page-number="1">
<fo:static-content flow-name="xsl-region-before" font-size="9pt">
<fo:block>
<xsl:apply-templates select="enrolment/address-dept-info"/>
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body" font-size="9pt">
<fo:block font-weight="bold" linefeed-treatment="preserve" space-after="9pt">
<xsl:apply-templates select="enrolment/letter"/>
</fo:block>
<fo:block linefeed-treatment="preserve" font-weight="bold" space-after="9pt">
Notes:
</fo:block>
<xsl:apply-templates select="enrolment/student-info/student-notes/student-notes-details"/>
<xsl:apply-templates select="enrolment/signature"/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<!-- This sections builds the header information at the top of the page -->
<xsl:template match="address-dept-info">
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-width="25mm" padding="0"/>
<fo:table-column column-width="100mm"/>
<fo:table-column column-width="85mm"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>
Logo info
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block linefeed-treatment='preserve'
white-space-collapse='false'><xsl:value-of select="address1"/></fo:block>
<fo:block linefeed-treatment='preserve'
white-space-collapse='false'><xsl:value-of select="address2"/></fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block linefeed-treatment='preserve'
white-space-collapse='false'>
<xsl:value-of select="dept/dept-name"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="student-info">
<fo:block linefeed-treatment="preserve" space-after="9pt">
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-width="5mm"/>
<fo:table-column column-width="80mm"/>
<fo:table-column column-width="100mm"/>
<fo:table-body>
<xsl:apply-templates select="//student-info/student-program/student-program-details"/>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template match="student-notes/student-notes-details">
<xsl:value-of select="description"/>
</xsl:template>
<xsl:template match="signature">
<fo:block linefeed-treatment='preserve' space-after="9pt">
Sincerely,
</fo:block>
<fo:block linefeed-treatment='preserve' space-after="12pt">
<xsl:value-of select="first-name"/><xsl:text> </xsl:text> <xsl:value-of select="last-name"/><xsl:text>
</xsl:text>
<xsl:value-of select="position"/><xsl:text>
</xsl:text>
</fo:block>
<fo:block font-size="9pt" text-align="center" background-color="grey">
<xsl:value-of select="//letter/footnote-line1"/>
</fo:block>
<fo:block font-size="9pt" text-align="center" background-color="yellow">
<xsl:value-of select="//letter/footnote-line2"/>
</fo:block>
</xsl:template>
<xsl:template match="letter">
<fo:block linefeed-treatment='preserve' text-align="center">
<xsl:value-of select="title"/>
</fo:block>
</xsl:template>
</xsl:stylesheet>
Thanks
Cheers

I tested this with FOP and you get the answer you get. Sorry. It's FOP. You could report as a bug.
Using RenderX XEP you get the answer you want and should rightly expect.

Related

Is it possible to show subsections with page numbers in TOC using XSL:FO?

I am using XSL FO to generate PDF file. I am trying to show the chapter, section1, subsection1, subsubsection1 with Page numbers. But I am unable to do it. Here is the code that I am trying to achieve. But I can able to see the page number and internal link only for the "Chapter" part alone. See the below image. I want to show the page number and internal destination link for subsections too. Any help?
<xsl:template name="genTOC">
<fo:block break-before='page'>
<fo:block font-size="16pt" text-align="center" font-weight="bold">TABLE OF CONTENTS</fo:block>
<xsl:for-each select="//chapter|//section1|//subsection1|//subsubsection1">
<fo:block text-align-last="justify">
<fo:basic-link internal-destination="{generate-id(.)}">
<xsl:value-of select="index"/>
<xsl:text> </xsl:text>
<xsl:value-of select="title"/>
<fo:leader leader-pattern="dots"/>
<fo:page-number-citation ref-id="{generate-id(.)}"/>
</fo:basic-link>
</fo:block>
</xsl:for-each>
</fo:block>
</xsl:template>
<xsl:template match="chapter">
<fo:block id="{generate-id()}">
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="section1">
<fo:block id="{generate-id()}">
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="subsection1">
<fo:block id="{generate-id()}">
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="subsubsection1">
<fo:block id="{generate-id()}">
<xsl:apply-templates/>
</fo:block>
</xsl:template>

Transform only the last element of XML and copy the rest in XSLT

I have an XML like below -
<root>
<row>
<col1>16</col1>
<col2>466</col2>
<col3>144922</col3>
<col4>0</col4>
<col5>5668</col5>
<col6>475</col6>
</row>
</root>
The number of columns can vary inside the root element. It can also be up to col9. My requirement is to modify the last column and copy others as it is for an incoming XML.
I have something like this till now where I am assigning the value to used as the last element in a variable and then trying to call it when the last position is reached-
<?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" exclude-result-prefixes="xs"
version="2.0">
<xsl:param name="line88.field2" />
<xsl:param name="rec16.col2" />
<xsl:variable name="col3">
<xsl:choose>
<xsl:when test="$rec16.col2 ='165'">
<xsl:value-of select="'Y'"/>
</xsl:when>
<xsl:when>
------
<xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"></xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="row[position() = last()]">
<col9>
<xsl:call-template name="AnotherTemplate">
<xsl:with-param name="inputData">
<xsl:value-of select="$col3" />
</xsl:with-param>
</xsl:call-template>
</col9>
</xsl:template>
<xsl:template name="AnotherTemplate">
<xsl:param name="inputData"></xsl:param>
<xsl:value-of select="$inputData" />
</xsl:template>
</xsl:stylesheet>
But this is not working for me. Just giving me one column with the modified value.Please help.
The desired outcome should be as below where the last column has the value from the variable.
<root>
<row>
<col1>16</col1>
<col2>466</col2>
<col3>144922</col3>
<col4>0</col4>
<col5>5668</col5>
<col6>Y</col6>
</row>
</root>
Without knowing your whole XSLT code. You can use this row template:
<xsl:template match="row/*[starts-with(local-name(),'col') and position() = last()]">
<xsl:element name="{concat('col',position() div 2)}">
<xsl:call-template name="AnotherTemplate">
<xsl:with-param name="inputData">
<xsl:value-of select="$col3" />
</xsl:with-param>
</xsl:call-template>
</xsl:element>
</xsl:template>
It replaces the last col? element by the given value (the result of the xsl:call-template code).

Some help on how groupings actually work would be much appreciated

I'm trying to get my head around how the different grouping techniques work. What causes a group, how are each group defined, and how the key are formed for each group.
If I wanted to use "group-adjacent" to move all following siblings of a specific element name into the first of preceding sibling of a given type. Would this be doable? I know how I can do this with recursive templates, and to some extent with keys in xslt 1.0. But I cannot get the 2.0 groups to work for me.
Lets say that I want to move all fig elements into the first preceding para, given that there are no other kinds of elements in between the fig(s) and the preceding para element, in this simple xml.
<root>
<first_lvl>
<title>First heading</title>
<para>First para under first heading</para>
<para>Second para under first heading</para>
<fig>fig1</fig>
<fig>fig 2</fig>
<table>Table A</table>
<fig>fig 3</fig>
<para>Third para under first heading</para>
<para>Fourth para under first heading</para>
<fig>fig4</fig>
</first_lvl>
</root>
Desired result:
<root>
<first_lvl>
<title>First heading</title>
<para>First para under first heading</para>
<para>Second para under first heading
<fig>fig1</fig>
<fig>fig 2</fig>
</para>
<table>Table A</table>
<fig>fig 3</fig>
<para>Third para under first heading</para>
<para>Fourth para under first heading
<fig>fig4</fig>
</para>
</first_lvl>
</root>
How can I set a grouping up that takes care of every directly following fig element?
This doesn't work:
<xsl:template match=para[following-sibling::*[1][self::fig]]>
<xsl:for-each-group select"folowing-sibling::*" group-adjacent="boolean(self::fig)">
<xsl:apply-templates select="current-group()" mode="move"/>
</xsl:for-each-group>
</xsl:template>
And then I've added atemplate to build content for each fig inside the para, and one to ignore those figs when they appear later on in the processing.
No luck though.
I have no other values to group by, other that the fact that they are fig elements.
What am I missing here?
I would start with a group-starting-with on those para followed by a fig and then inside use group-adjacent to identify only the first group of adjacent figs. With the verbosity of XSLT that looks a bit convoluted but does the job as far as I have understood your requirements:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes" />
<xsl:template match="*[para and fig]">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:for-each-group select="*" group-starting-with="para[following-sibling::*[1][self::fig]]">
<xsl:choose>
<xsl:when test="self::para[following-sibling::*[1][self::fig]]">
<xsl:variable name="para-head" select="."/>
<xsl:for-each-group select="tail(current-group())" group-adjacent="boolean(self::fig)">
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:copy select="$para-head">
<xsl:apply-templates select="node(), current-group()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/6qVRKxh
I have taken the liberty to use XSLT 3 instead of 2 but you simply would have to spell out the identity transformation declared by the xsl:mode on-no-match="shallow-copy" and make sure you use
<xsl:element name="{name($para-head)}" namespace="{namespace-uri($para-head)}">
<xsl:apply-templates select="$para-head/node(), current-group()"/>
</xsl:element>
instead of the XSLT 3 only xsl:copy with a select:
<xsl:copy select="$para-head">
<xsl:apply-templates select="node(), current-group()"/>
</xsl:copy>
and instead of the XPath 3 tail function you use subsequence e.g.
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:output method="xml" indent="yes" />
<xsl:template match="*[para and fig]">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:for-each-group select="*" group-starting-with="para[following-sibling::*[1][self::fig]]">
<xsl:choose>
<xsl:when test="self::para[following-sibling::*[1][self::fig]]">
<xsl:variable name="para-head" select="."/>
<xsl:for-each-group select="subsequence(current-group(), 2)" group-adjacent="boolean(self::fig)">
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:element name="{name($para-head)}" namespace="{namespace-uri($para-head)}">
<xsl:apply-templates select="$para-head/node(), current-group()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:transform>
http://xsltransform.hikmatu.com/bFDb2BN
On the other hand, I am not sure whether an attempt not using xsl:for-each-group but rather a template matching para[following-sibling::*[1][self::fig]] and then consuming following sibling figs (which can be done easily in XSLT 3 with xsl:iterate) is not more compact:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="para[following-sibling::*[1][self::fig]]">
<xsl:copy>
<xsl:apply-templates select="#*, node()"/>
<xsl:iterate select="following-sibling::*">
<xsl:choose>
<xsl:when test="self::fig">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:break/>
</xsl:otherwise>
</xsl:choose>
</xsl:iterate>
</xsl:copy>
</xsl:template>
<xsl:template match="fig[preceding-sibling::*[not(self::fig)][1][self::para]]"/>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/6qVRKxh/3

Need to create a static footer with xsl-fo

At the bottom of my document, I have an address that I need to stay at the bottom so the address can be used in window mailers. I have tried using static-content tags to achieve this, but my document errors out every time. I am new to this, so I'm guessing I missing something. I want the "contractor" template to be static in the footer.
<xsl:template match="/" >
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<!-- Setup up page size (Can be in inches or centimeters)-->
<fo:simple-page-master
master-name="page"
page-width="8.50in"
page-height="11.00in"
margin-top="0.50in"
margin-bottom="0.50in"
margin-left="0.50in"
margin-right="0.50in">
<fo:region-body margin-top="0cm"/>
<fo:region-before extent="0cm"/>
<fo:region-after extent="0cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<xsl:apply-templates select="/Permits/Permit" />
</fo:root>
</xsl:template>
<xsl:template match="Permit">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="10pt">
<xsl:call-template name="header"/>
<xsl:call-template name="permitdetails"/>
<xsl:call-template name="permitdetails2"/>
<xsl:call-template name="parties"/>
<xsl:call-template name="feesummary"/>
<xsl:call-template name="inspections"/>
<xsl:call-template name="contractor"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</xsl:template>
<fo:static-content> should be a child of <fo:page-sequence> It should not work if you were simply trying to wrap your <xsl:call-template name="contractor"/> above in static-content tags. Can you post your template with the error?
Something like this should work:
<xsl:template match="Permit">
<fo:page-sequence master-reference="page">
<fo:static-content flow-name="xsl-region-after">
<fo:block>
<xsl:call-template name="contractor"/>
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="10pt">
<xsl:call-template name="header"/>
<xsl:call-template name="permitdetails"/>
<xsl:call-template name="permitdetails2"/>
<xsl:call-template name="parties"/>
<xsl:call-template name="feesummary"/>
<xsl:call-template name="inspections"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</xsl:template>
</xsl:template>
<fo:static-content> should be declared before the body flow, even if it appears after the body in the output.

Complex XSL Transformation

I am still a beginner with XSLT but I am having a difficult task in hand.
I have a non-xml file which needs to be transformed. The format of the file is a s follows:
type1
type1line1
type1line2
type1line3
type2
type2line1
type2line2
type3
type3line1
type3line2
types (type1, type2, ...) are specified using certain codes which don't have a specific order. Each type has multiple line underneath.
So, I need to transform this file but the problem is that for each type I have to do a different transformation for each of it's underlying lines.
Now, I can read the string line by line and determine that a new type has begun but I don't know how to set a flag (indicating the type) to use it in the underlying lines.
Here is what I have right now:
<?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" version="2.0">
<xsl:param name="testString" as="xs:string">
type1
line1
line2
type1
line1
</xsl:param>
<xsl:template match="/">
<xsl:call-template name="main">
<xsl:with-param name="testString" select="$testString"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="main">
<xsl:param name="testString"/>
<xsl:variable name="iniFile" select="$testString"/>
<config>
<xsl:analyze-string select="$iniFile" regex="\n">
<xsl:non-matching-substring>
<item>
<xsl:choose>
<xsl:when test="starts-with(., 'type1')">
<!-- do a specific transformation-->
</xsl:when>
<xsl:when test="starts-with(., 'type2')">
<!-- do another transformation-->
</xsl:when>
</xsl:choose>
</item>
</xsl:non-matching-substring>
</xsl:analyze-string>
</config>
</xsl:template>
</xsl:stylesheet>
Any idea about how to solve the problem.
I think XSLT 2.1 will allow you to use its powerful stuff like for-each-group on sequences of atomic values like strings but with XSLT 2.0 you have such powerful features only for sequences of nodes so my first step when using XSLT 2.0 with plain string data I want to process/group is to create elements. So you could tokenize your data, wrap each token into some element and then use for-each-group group-starting-with to process each group starting with some pattern like '^type[0-9]+$'.
You haven't really told us what you want to with the data once you have identified a group so take the following as an example you could adapt:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="input" as="xs:string">type1
type1line1
type1line2
type1line3
type2
type2line1
type2line2
type3
type3line1
type3line2</xsl:param>
<xsl:template name="main">
<xsl:variable name="lines" as="element(item)*">
<xsl:for-each select="tokenize($input, '\n')">
<item><xsl:value-of select="."/></item>
</xsl:for-each>
</xsl:variable>
<xsl:for-each-group select="$lines" group-starting-with="item[matches(., '^type[0-9]+$')]">
<xsl:choose>
<xsl:when test=". = 'type1'">
<xsl:apply-templates select="current-group() except ." mode="m1"/>
</xsl:when>
<xsl:when test=". = 'type2'">
<xsl:apply-templates select="current-group() except ." mode="m2"/>
</xsl:when>
<xsl:when test=". = 'type3'">
<xsl:apply-templates select="current-group() except ." mode="m3"/>
</xsl:when>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="item" mode="m1">
<foo>
<xsl:value-of select="."/>
</foo>
</xsl:template>
<xsl:template match="item" mode="m2">
<bar>
<xsl:value-of select="."/>
</bar>
</xsl:template>
<xsl:template match="item" mode="m3">
<baz>
<xsl:value-of select="."/>
</baz>
</xsl:template>
</xsl:stylesheet>
When applied with Saxon 9 (command line options -it:main -xsl:sheet.xsl) the result is
<foo>type1line1</foo>
<foo>type1line2</foo>
<foo>type1line3</foo>
<bar>type2line1</bar>
<bar>type2line2</bar>
<baz>type3line1</baz>
<baz>type3line2</baz>

Resources