FOP XSL 1.0 Replace text and keep line break - xslt

I'm trying to generate a pdf using xsl + xml, but Im having problems on a part of the document where there is some lines of text with line breaks.
When generating the document it did not keep those line breaks.
I have tried everything, and Im completely stuck.
My code is:
<fo:table-row>
<fo:table-cell margin-right="0mm" margin-left="0mm"
margin-bottom="0mm" margin-top="0mm"
xsl:use-attribute-sets="bordergris" number-columns-spanned="5">
<fo:block xsl:use-attribute-sets="titoldades"
space-before.optimum="0pt" space-after.optimum="0pt"
keep-together="always" >
More info:
</fo:block>
<fo:block xsl:use-attribute-sets="dades"
space-before.optimum="0pt" space-after.optimum="0pt"
keep-together="always" linefeed-treatment="preserve">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="/Response/DataList/Data/MoreInfo"/>
<xsl:with-param name="replace" select="' '" />
<xsl:with-param name="with" select="'<fo:block/>'"/>
</xsl:call-template>
</fo:block>
</fo:table-cell>
</fo:table-row>
Which use a template function:
<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="replace"/>
<xsl:param name="with"/>
<xsl:choose>
<xsl:when test="contains($text,$replace)">
<xsl:value-of select="substring-before($text,$replace)"/>
<xsl:value-of select="$with"/>
<xsl:call-template name="replace-string">
<xsl:with-param name="text"
select="substring-after($text,$replace)"/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="with" select="$with"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
And the resulting text appears with the hardcoded text "<fo:block/>" instead of applying the line break.
What am I doing wrong?
Thanks!!!

The important thing is to put the following properties inside the fo:block:
inefeed-treatment="preserve" white-space-collapse="false" white-space-treatment="preserve"
And then do the replace with the following:
<fo:block xsl:use-attribute-sets="dades"
linefeed-treatment="preserve" white-space-collapse="false" white-space-treatment="preserve">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="/Response/DataList/Data/MoreInfo"/>
<xsl:with-param name="replace" select="' '" />
<xsl:with-param name="with" select="'
'"/>
</xsl:call-template>

Related

Apache FOP | Multi page table row height issue

I am generating PDF using Apache FOP XSL file format.
My requirements are
Tabular data in PDF
Table size is large so the Same table extended to multiple pages (width-wise, few columns in first page others are on the next page)
Page 1 has 3 columns (C1, C2, C3)
Page 2 has 5 columns (C4, C5, C6, C7, C8)
Few cells may have multiline data
Problem description:
When Page-2 has multiline data for Row 4, Column 4, so its row height increased as per content
But in Page-1 row 4 has row height as a single line.
I want to have the same row height across all pages of the same table when any cell data is multiline of any page.
Here is XSL file if needed:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<!-few params declaration->
<xsl:template match="/rs">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="data-template-1" page-height="11.0in" page-width="17.0in"
margin-top="0.5in" margin-bottom="1.0in" margin-left="0.5in"
margin-right="0.5in">
<fo:region-body margin-top="1.5in" margin-bottom="0.8in"/>
<fo:region-before extent="0.7in"/>
<fo:region-after/>
</fo:simple-page-master>
<fo:simple-page-master master-name="data-template-2" page-height="11.0in" page-width="17.0in"
margin-top="0.5in" margin-bottom="1.0in" margin-left="0.5in"
margin-right="0.5in">
<fo:region-body margin-top="1.5in" margin-bottom="0.8in"/>
<fo:region-before extent="0.7in"/>
<fo:region-after/>
</fo:simple-page-master>
</fo:layout-master-set>
<xsl:for-each select="rb">
<xsl:variable name="current-initial-page-number" select="$param.initialPageNumber + (position() * $pagesPerTable)" />
<fo:page-sequence master-reference="data-template-1" initial-page-number="{$current-initial-page-number}"
font-size="{$cdrFontSize}" font-family="{$cdrFontFamily}" line-height="10.2pt">
<fo:flow flow-name="xsl-region-body">
<fo:table table-layout="fixed" width="100%" space-after.optimum="{$cdrInfoTableSpaceAfter}" border-width="0.4mm" border-style="solid">
<fo:table-column column-width="23.1mm"/>
<fo:table-column column-width="23.1mm"/>
<fo:table-column column-width="18.9mm"/>
<fo:table-header text-align="center" display-align="center">
<fo:table-row font-weight="bold" background-color="rgb(230,230,230)">
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="'C1'"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="'C2'"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="'C3"/>
</xsl:call-template>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:for-each select="r">
<fo:table-row text-align="left" display-align="before">
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="c[#n='C1']"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="c[#n='C12']"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="c[#n='C3']"/>
</xsl:call-template>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="data-template-2"
font-size="{$cdrFontSize}" font-family="{$cdrFontFamily}" line-height="10.2pt">
<fo:flow flow-name="xsl-region-body">
<fo:table table-layout="fixed" width="100%" space-after.optimum="{$cdrInfoTableSpaceAfter}" border-width="0.4mm" border-style="solid">
<fo:table-column column-width="88.2mm"/>
<fo:table-column column-width="88.2mm"/>
<fo:table-column column-width="48.3mm"/>
<fo:table-column column-width="23.1mm"/>
<fo:table-column column-width="54.6mm"/>
<fo:table-header text-align="center" display-align="center">
<fo:table-row font-weight="bold" background-color="rgb(230,230,230)">
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="'C4'"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="'C5'"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="'C6'"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="'C7'"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="'C8'"/>
</xsl:call-template>
</fo:table-row>R
</fo:table-header>
<fo:table-body>
<xsl:for-each select="r">
<fo:table-row text-align="left" display-align="before">
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="c[#n='C4']"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="c[#n='C5']"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="c[#n='C6']"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="c[#n='C7']"/>
</xsl:call-template>
<xsl:call-template name="cdr_table_cell">
<xsl:with-param name="cellValue" select="c[#n='C8']"/>
</xsl:call-template>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</xsl:for-each>
</fo:root>
</xsl:template>
<xsl:template name="cdr_table_cell">
<xsl:param name="cellValue"/>
<fo:table-cell border-width="0.4mm" border-style="solid">
<fo:block-container overflow="hidden">
<fo:block margin-left="0.5mm" margin-top="0.3mm">
<xsl:call-template name="zero_width_space_1">
<xsl:with-param name="data" select="$cellValue"/>
</xsl:call-template>
</fo:block>
</fo:block-container>
</fo:table-cell>
</xsl:template>
<!-- The following templates are used to add empty space character to data, so that FOP can break (wrap) the word -->
<xsl:template name="zero_width_space_1">
<xsl:param name="data"/>
<xsl:param name="counter" select="0"/>
<xsl:choose>
<xsl:when test="$counter <= string-length($data)">
<xsl:value-of select='concat(substring($data,$counter,1),"​")'/>
<xsl:call-template name="zero_width_space_2">
<xsl:with-param name="data" select="$data"/>
<xsl:with-param name="counter" select="$counter+1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="' '"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="zero_width_space_2">
<xsl:param name="data"/>
<xsl:param name="counter"/>
<xsl:value-of select='concat(substring($data,$counter,1),"​")'/>
<xsl:call-template name="zero_width_space_1">
<xsl:with-param name="data" select="$data"/>
<xsl:with-param name="counter" select="$counter+1"/>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
What I don't want
Fixed row height as it wastes page space even if all data is accumulated in a single line.
Format the full table twice: once for each page.
For the first copy of the table, make everything after column 3 be white or transparent.
For the second copy of the table, make everything in columns 1 to 3 be white or transparent and also add a negative margin on the table (and set it back to 0 in the table cells) so that columns 1 to 3 are off the left side of the page.
Note that if you were using AH Formatter, you could use the Spread Page Master extension (see https://www.antenna.co.jp/AHF/help/v70e/ahf-spread.html) and make a region that spans both pages.

XSL:FO Different list-item-label per level

I'm using Apache FOP to generate PDFs from my web application, where users can edit richtext using CKEditor.
My problem is that users sometimes use different levels of indentation in (un-)ordered lists, e.g.:
List item level 1
List item level 2
The CKEditor shows different bulletins per level (or indentation), but the generated PDFs do not, because my template looks like this:
<!-- Lists -->
<xsl:template match="ul|ol" mode="content">
<xsl:apply-templates select="li" mode="content">
<xsl:with-param name="ordered">
<xsl:value-of select="name()='ol'"/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="li" mode="content">
<xsl:param name="ordered"/>
<xsl:variable name="label">
<xsl:choose>
<xsl:when test="$ordered='true'">
<xsl:value-of select="position()"/>
.
</xsl:when>
<xsl:otherwise>
•
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<fo:list-block padding-bottom="0pt">
<fo:list-item>
<fo:list-item-label>
<fo:block>
<xsl:value-of select="$label"/>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates mode="content"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
</xsl:template>
So how can I set the label variable depending on which level of indentation I'm at?
Something like:
1st level: &#8226
2nd level: &#9702
3rd level: &#8269
Thanks in advance, ~Fabi
EDIT: So the solution suggested by #fafl looks like this:
<!-- Lists -->
<xsl:template match="ul|ol" mode="content">
<xsl:param name="depth" select="0"/>
<xsl:apply-templates select="li" mode="content">
<xsl:with-param name="ordered">
<xsl:value-of select="name()='ol'"/>
</xsl:with-param>
<xsl:with-param name="depth">
<xsl:value-of select="$depth + 1"/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="li" mode="content">
<xsl:param name="depth" select="0"/>
<xsl:param name="ordered"/>
<xsl:variable name="label">
<xsl:choose>
<xsl:when test="$ordered='true'">
<xsl:value-of select="position()"/>
.
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$depth = 1">
• <!--filled circle-->
</xsl:when>
<xsl:when test="$depth = 2">
◦ <!--not-filled circle-->
</xsl:when>
<xsl:otherwise>
■ <!--black square -->
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<fo:list-block padding-bottom="0pt">
<fo:list-item>
<fo:list-item-label>
<fo:block>
<xsl:value-of select="$label"/>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates mode="content">
<xsl:with-param name="depth">
<xsl:value-of select="$depth"/>
</xsl:with-param>
</xsl:apply-templates>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
</xsl:template>
Try adding a parameter "depth" to both templates with a default value of 1. On each recursive call of "ul|ol" increase it by 1. Then you can query it inside both templates.

Removing &#160 with XSLT

I hope someone can help me with this...
I am using SharePoint 2013 and trying to render a CQWP to show the latest blog posts. The problem I have is that when displaying the 'content' from the post I get '&#160' added and quotes are shown as '&quot'. I have managed to strip the HTML mark up but can't seem to get rid of these.
My code is as follows - any help would be much appreciated, thanks.
Generate Summary and Remove HTML
<!-- Generate Summary -->
<xsl:template name="GenerateSummary">
<xsl:param name="Content"/>
<xsl:param name="Length"/>
<xsl:param name="Suffix"/>
<xsl:variable name="cleanContent">
<xsl:call-template name="RemoveHtml">
<xsl:with-param name="String" select="$Content"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="SubstringBeforeLast">
<xsl:with-param name="String"
select="substring($cleanContent, 1, $Length)"/>
<xsl:with-param name="Char" select="' '"/>
</xsl:call-template>
<xsl:if test="string-length($cleanContent) > $Length">
<xsl:value-of select="$Suffix"
disable-output-escaping="yes"/>
</xsl:if>
</xsl:template>
<!-- RemoveHTML -->
<xsl:template name="RemoveHtml">
<xsl:param name="String"/>
<xsl:choose>
<xsl:when test="contains($String, '<')">
<xsl:value-of select="substring-before($String, '<')"/>
<xsl:call-template name="RemoveHtml">
<xsl:with-param name="String"
select="substring-after($String, '>')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$String"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="SubstringBeforeLast">
<xsl:param name="String" />
<xsl:param name="Char" />
<xsl:param name="subsequent"/>
<xsl:choose>
<xsl:when test="contains($String, $Char)">
<xsl:if test="$subsequent = 1">
<xsl:value-of select="$Char"/>
</xsl:if>
<xsl:value-of select="substring-before($String, $Char)"/>
<xsl:call-template name="SubstringBeforeLast">
<xsl:with-param name="String"
select="substring-after($String, $Char)" />
<xsl:with-param name="Char" select="$Char" />
<xsl:with-param name="subsequent" select="1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$subsequent != 1">
<xsl:value-of select="$String"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Calling it here
<div class="fcItemContent">
<xsl:call-template name="GenerateSummary">
<xsl:with-param name="Content" select="#content" />
<xsl:with-param name="Length" select="200" />
<xsl:with-param name="Suffix" select="'...'"/>
</xsl:call-template>
</div>
Use function of XSLT
normalize-space()
**<xsl:value-of select="normalize-space()"/>**
White space is normalized by stripping leading and trailing white space and replacing sequences of white space characters with a single space. If the argument is omitted, the string-value of the context node is normalized and returned.
referred Link :
Remove Space using XSLT

Increment Letter's in XSL 1.0

I have from XML for example the String "AA"
and i need to increment it Like:
AA AB AC AD AE (...) AZ BA BB (...)
For example increment it for 35 times (coming from a varaible called (`xsl:variable name ="NumIncr">)) starting at AA and finishing in BG.
The string don't always have "AA" can be any 2 letters...
Any idea to do this?!
I think the <xsl:number> tag can help, but still the problem to pass from letters to numbers.
Need something like
<fo:table-cell border-collapse="collapse" border-color="gray" font-family="Helvetica" font-size="8pt" border="solid 1pt gray" padding="1pt" display-align="before">
<fo:block text-align="center">
<xsl:value-of select="string($Sequence)"/>
</fo:block>
</fo:table-cell>
Where $sequence is the AA AB AC (...)
Can writte evrything in the same cell, the problem isn't the output but the tamplate to increment the AA
HELP!!!
To translate a string like "AA" to its numerical value, you can use the following template:
<xsl:template name="string-to-num">
<xsl:param name="string"/>
<xsl:param name="alpha" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:param name="magnitude" select="1"/>
<xsl:param name="carryover" select="0"/>
<xsl:param name="bit" select="substring($string, string-length($string), 1)"/>
<xsl:param name="bit-value" select="string-length(substring-before($alpha, $bit)) + 1"/>
<xsl:variable name="return" select="$carryover + $bit-value * $magnitude"/>
<xsl:choose>
<xsl:when test="string-length($string) > 1">
<xsl:call-template name="string-to-num">
<xsl:with-param name="string" select="substring($string, 1, string-length($string) - 1)"/>
<xsl:with-param name="magnitude" select="string-length($alpha) * $magnitude"/>
<xsl:with-param name="carryover" select="$return"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$return" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Some examples of calling the template:
<xsl:call-template name="string-to-num">
<xsl:with-param name="string">A</xsl:with-param>
</xsl:call-template>
returns 1;
<xsl:call-template name="string-to-num">
<xsl:with-param name="string">Z</xsl:with-param>
</xsl:call-template>
returns 26;
<xsl:call-template name="string-to-num">
<xsl:with-param name="string">AA</xsl:with-param>
</xsl:call-template>
returns 27;
<xsl:call-template name="string-to-num">
<xsl:with-param name="string">ZZ</xsl:with-param>
</xsl:call-template>
returns 702;
<xsl:call-template name="string-to-num">
<xsl:with-param name="string">AAA</xsl:with-param>
</xsl:call-template>
returns 703.
These results are the exact reverse of:
<xsl:number value="$return" format="A"/>

XSLT split string on every character

I have a string like : "ABCDEFGHI"
I want the output as A,B,C,D,E,F,G,H,I in xslt-
I have been using -
<xsl:variable name="string_Comma_Delimited">a,b,c,d,e,f,g,h,i</xsl:variable>
<xsl:call-template name="parseString">
<xsl:with-param name="list" select="$string_Comma_Delimited"/>
</xsl:call-template>
<xsl:template name="parseString">
<xsl:param name="list"/>
<xsl:if test="contains($list, ',')">
<fo:table-cell border-width="0.000pt " border-style="solid" border-color="rgb(0,0,0)" padding-top="4.000pt">
<fo:block-container height="6mm" border-width="0.200pt" border-style="solid" border-color="rgb(0,0,0)" text-align="center">
<fo:block text-align="center">
<xsl:value-of select="substring-before($list, ',')"/>
</fo:block>
</fo:block-container>
</fo:table-cell>
<xsl:call-template name="parseString">
<xsl:with-param name="list" select="substring-after($list, ',')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
Your current template splits the string by commas. To simply split it on every single character you can still use a recursive template. All the template would do is output the first character using substring, and then, if the length of the string was 2 or more characters, recursively call the template with the remaining portion of the string.
Try this
<xsl:template name="parseString">
<xsl:param name="text"/>
<letter>
<xsl:value-of select="substring($text, 1, 1)"/>
</letter>
<xsl:if test="string-length($text) > 1">
<xsl:call-template name="parseString">
<xsl:with-param name="text" select="substring($text, 2, string-length($text) - 1)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
Given INDIA as input, the following is output:
<letter>I</letter>
<letter>N</letter>
<letter>D</letter>
<letter>I</letter>
<letter>A</letter>
Now, if you were using XSLT 2.0, you could use the xsl:analyze-string function to achieve the same
<xsl:template name="parseString">
<xsl:param name="text"/>
<xsl:analyze-string select="$text" regex=".">
<xsl:matching-substring>
<letter>
<xsl:value-of select="." />
</letter>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:template>
(Of course, if you were using XSLT 2.0, you could have used tokenize in the first case to split the comma-delimited string)