Apache fop generated PDF renders hyperlinks by replacing accented characters with '?' - apache

I have used Apache FOP 1.1 to programmatically generate PDF. The PDF is supposed to contain name of a document as hyperlink. When I click on the name, it should open the corresponding file. Here is the code:
<fo:block>
<fo:basic-link color="blue" show-destination="new">
<xsl:attribute name="external-destination">
<xsl:choose>
<xsl:when test="#parentFolderPath">
<xsl:value-of select="#parentFolderPath" />/<xsl:value-of select="#FileName" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="#FileName" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute><xsl:call-template name="writeWithoutOverlap"><xsl:with-param name="data" select="#FileName"/></xsl:call-template>
</fo:basic-link>
</fo:block>
This works perfectly fine when I have a file having English characters in the name. However, when I have a file name like this: "étudiant où forêt naïve garçon.docx" the hyperlink formed in the PDF replaces the accented characters with '?'.
This is a screen shot of the PDF where you can see the malformed hyperlink:
I am using "Arial" font and encoding="UTF-8".
When the name of the file is getting printed correctly, why is the hyperlink giving a problem?

Related

How to generate a cover image picture with asciidoctor-fopub

I'm trying to customize our developer guide pdf to have a decent looking first page. I'm totally fine with doing everything in photoshop as an image since asciidoc seems to be pretty limited in abilities here.
Unfortunately despite looking everywhere I can't seem to find a single way to customize the cover sheet or replace it with an image that works for asciidoctor-fopub.
The annoying thing is that this use case is specifically mentioned in the readme of the project https://github.com/asciidoctor/asciidoctor-fopub (under Custom XSL templates) but there is no mention on how to actually do it other than "its in the XSL". As someone who isn't familiar with docbook I have no idea where to begin.
asciidoctor-pdf has a tag for including an image but it barfs on our document and generates garbage (the ToC is painted over everything).
This can be done using division.xsl file under build/fopub/docbook/fo/
search for "Placeholder templates"
and paste below code there, you will be able to see cover image in your generated fopub
<!-- Placeholder templates -->
<xsl:template name="front.cover">
<xsl:call-template name="page.sequence">
<xsl:with-param name="master-reference">titlepage-cover-image</xsl:with-param>
<xsl:with-param name="content">
<fo:block text-align="center">
<fo:external-graphic src="url(path/to/cover.png)" content-height="250mm" content-width="176mm"/>
</fo:block>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
Change height and width as per your book requirement.
Once that is done you need to provide margin for image on the cover page to be clear. Add below in pagesetup.xsl
<fo:simple-page-master master-name="titlepage-cover-image"
page-width="{$page.width}"
page-height="{$page.height}"
margin-top="{$title.page.margin.top}"
margin-bottom="{$page.margin.bottom}">
<xsl:attribute name="margin-{$direction.align.start}">
<xsl:value-of select="$page.margin.inner"/>
<xsl:if test="$fop.extensions != 0">
<xsl:value-of select="concat(' - (',$title.margin.left,')')"/>
</xsl:if>
</xsl:attribute>
<xsl:attribute name="margin-{$direction.align.end}">
<xsl:value-of select="$page.margin.outer"/>
</xsl:attribute>
<xsl:if test="$axf.extensions != 0">
<xsl:call-template name="axf-page-master-properties">
<xsl:with-param name="page.master">titlepage-cover-image</xsl:with-param>
</xsl:call-template>
</xsl:if>
<fo:region-body margin-bottom="{$body.margin.bottom}"
margin-top="{$title.body.margin.top}"
column-gap="{$column.gap.titlepage}"
column-count="{$column.count.titlepage}">
<xsl:attribute name="margin-{$direction.align.start}">
<xsl:value-of select="$body.margin.inner"/>
</xsl:attribute>
<xsl:attribute name="margin-{$direction.align.end}">
<xsl:value-of select="$body.margin.outer"/>
</xsl:attribute>
</fo:region-body>
<fo:region-before region-name="xsl-region-before-first"
extent="{$region.before.extent}"
precedence="{$region.before.precedence}"
display-align="before"/>
<fo:region-after region-name="xsl-region-after-first"
extent="{$region.after.extent}"
precedence="{$region.after.precedence}"
display-align="after"/>
<xsl:call-template name="region.inner">
<xsl:with-param name="sequence">first</xsl:with-param>
<xsl:with-param name="pageclass">titlepage</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="region.outer">
<xsl:with-param name="sequence">first</xsl:with-param>
<xsl:with-param name="pageclass">titlepage</xsl:with-param>
</xsl:call-template>
</fo:simple-page-master>
Then add variables in fo-pdf.xsl to zeroed out your body top margin.
HTH.

XSLT check if string contains: '

I have to check that my XML don't contains sumbol ' in text fields. But I don't know how to order it, because such way it don't work:
<xsl:for-each select="//Surname">
<xsl:if test="contains(text(), ''')">
<xsl:text>ERROR!</xsl:text>
</xsl:if>
</xsl:for-each>
I tried \' and other variants, it don't works. How it is possible to do?

Apache FOP keeping two elements together not working

I have following xslt:
<xsl:template match="P">
<fo:block>
1.1 First Image
</fo:block>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="figure">
<fo:block margin-top="-0.30in" keep-with-previous.within-page="always">
<fo:external-graphic>
<xsl:attribute name="src"> <xsl:value-of select="abc.svg" />
</xsl:attribute>
</fo:external-graphic>
</fo:block>
</xsl:template>
Both these templates will be called in a recursive method.
My output is :
P tag is coming in one page where it has space. Since figures are big, it shows in the next page. I want them to be together.
Tried solutions: keep-with, break-after, page-break-after.
Keep-with is not working. Others are creating new page for every P tag though there is space in the previous tag.
I am generating PDF output using FOP1.0.
Please help.
Thanks in advance.
change
<xsl:template match="P">
<fo:block>
1.1 First Image
</fo:block>
<xsl:apply-templates />
</xsl:template>
to
<xsl:template match="P">
<fo:block keep-with-next.within-page="always">
1.1 First Image
</fo:block>
<xsl:apply-templates />
</xsl:template>

Can disable-output-escaping be set using a template parameter?

Why won't the following work in XSLT1.0?
<xsl:template name="GenerateSummaryOld">
<xsl:param name="Content" />
<xsl:param name="Length" />
<xsl:param name="DisableOutputEscaping" />
<xsl:value-of select="substring($Content, 1, $Length)" disable-output-escaping="$DisableOutputEscaping" />
<xsl:if test="string-length($Content) > $Length"><i>...text has been shortened</i></xsl:if>
</xsl:template>
I'm using the following when calling the template:
<xsl:with-param name="DisableOutputEscaping">no</xsl:with-param>
I'm trying this in a SharePoint Content Query WebPart but I get a web part error. If I hard-code disable-output-escaping as "yes" or "no" in the template, i get no error.
Short answer: the value of disable-output-escaping must be specified literally in the XSLT stylesheet; it cannot be calculated at stylesheet execution time.
That is, the behavior you are observing is the behavior prescribed by the language definition.
Longer answer: The XSLT 1.0 spec shows the syntax of xsl:value-of like this (more or less):
<!-- Category: instruction -->
<xsl:value-of
select = string-expression
disable-output-escaping = "yes" | "no" />
Note that "string-expression" is italicized here; it means that the select attribute has as its value not the string "string-expression" but any XPath expression which can be evaluated and coerced to a string. But the "yes" and "no" of disable-output-escaping are not italicized, not described as being an expression, and not described as being an attribute-value template. The "yes" or "no" value must be given literally.
The closest the spec comes to saying this explicitly (that I could find) is the note in section 7.6.2 on attribute value templates:
NOTE:Not all attributes are interpreted as attribute value templates. Attributes whose value is an expression or pattern, attributes of top-level elements and attributes that refer to named XSLT objects are not interpreted as attribute value templates. ...
This is one of a number of early-binding constraints in XSLT designed to ensure that stylesheets could be compiled and not just interpreted.
The explanation was provided in the good answer by C. M. Sperberg-McQueen.
Here is a workaround:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vAmp">&</xsl:variable>
<xsl:variable name="vYesNo" select="'yes'"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$vYesNo = 'yes'">
<xsl:value-of select="$vAmp" disable-output-escaping="yes"/>
</xsl:when>
<xsl:when test="$vYesNo = 'no'">
<xsl:value-of select="$vAmp" disable-output-escaping="no"/>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on any XML document (not used), the result is:
&
If we replace:
<xsl:variable name="vYesNo" select="'yes'"/>
with:
<xsl:variable name="vYesNo" select="'no'"/>
the result of the modified transformation now is:
&

Remove unmatched parentheses and unmatched brackets from XML content

I saw questions related for Ruby, etc. I didn't see any answers that would cover this case.
I'm using XSLT to transform an XML document.
I'm forced to use XSLT 1.0, since the application that uses XSLT and XPATH is still on 1.0.
Would you use Javascript function embedded in XSL using regex?
I have xml code like this:
<document>
<content name="PROD_MAJ_CLS_CD" type="text" vse-streams="2" u="20" action="cluster" weight="1">2</content>
<content name="PART_DESC_SHORT" type="text" vse-streams="2" u="22" action="cluster" weight="1">SCREW-ROCKER</content>
</document>
The content attribute where name="PART_DESC_SHORT" can have parentheses and brackets in it
Thanks,
Paul
In your example, none of the parentheses match, and all are open parentheses; for that case, the task of removing unmatched parentheses and brackets amounts to removing all parentheses and brackets. This is most easily done with the translate function:
<xsl:value-of select="translate(.,'([','')"/>
If you actually need to retain matched braces and translate input of the form a(b[c]d(e into ab[c]de, then the simplest way to do it in XSLT is with a recursive named template which takes two parameters: an input string and a stack recording the material processed so far. (The stack can be just a sequence of strings delimited by a separator you choose, that you hope won't appear in the input. Since you show the input as coming from an attribute value, &#x9; will probably be a safe choice (it will have been normalized out of the input unless the data producer used a numeric character reference for it), but you can use |||never-use-this-string-in-a-part-description||| instead if you like.)
On the initial call, you pass just the input string, and let the stack default to empty.
On each call with non-empty input, the template takes one character off of the input stream and does the right thing with it:
for "(" and "[", push a new string onto the stack.
for "]" and ")" matching the first character of the top item on the stack, pop the stack twice, concatenate item 2, item 1 (the old top item), and the character "]" or ")", and push the concatenation onto the stack.
For "]" and ")" that don't match, the input is not well balanced, and you need to do something. (The code here drops the character.)
For any other character, append it to the top item on the stack.
So at any given time, every item on the stack except the bottom one begins with an open parenthesis or bracket which has not yet been matched. Every time we get a match, the parenthesized string is appended to the next item on the stack, thus reducing the stack size.
When the input string is exhausted and the stack has more than one item in it, the leading brace on the stack's top item needs to be stripped and the top item (minus the brace) appended to the next item.
Once the stack is down to one item, that item contains the string you wanted.
Here it is in XSLT:
<xsl:template name="paren-match-or-strip">
<xsl:param name="input"/>
<xsl:param name="stack"/>
<xsl:variable name="char"
select="substring($input,1,1)"/>
<xsl:variable name="stacktop"
select="substring-before($stack,$sep)"/>
<xsl:variable name="stackrest"
select="substring-after($stack,$sep)"/>
<xsl:choose>
<xsl:when test="not($input = '')">
<xsl:choose>
<xsl:when test="$char = '(' or $char = '['">
<!--* Push another potential-left-brace on the stack *-->
<xsl:call-template name="paren-match-or-strip">
<xsl:with-param name="input"
select="substring($input,2)"/>
<xsl:with-param name="stack"
select="concat(
$char,
$sep,
$stack
)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="($char = ']' and substring($stacktop,1,1) = '[')
or
($char = ')' and substring($stacktop,1,1) = '(')
">
<!--* Match the left brace at the top of the stack *-->
<xsl:variable name="stacktop2"
select="substring-before($stackrest,$sep)"/>
<xsl:variable name="stackrest2"
select="substring-after($stackrest,$sep)"/>
<xsl:call-template name="paren-match-or-strip">
<xsl:with-param name="input"
select="substring($input,2)"/>
<xsl:with-param name="stack"
select="concat(
$stacktop2,
$stacktop,
$char,
$sep,
$stackrest
)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$char = ']' or $char = ')'">
<!--* Unmatched right brace, drop it silently *-->
<xsl:call-template name="paren-match-or-strip">
<xsl:with-param name="input"
select="substring($input,2)"/>
<xsl:with-param name="stack"
select="$stack"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="paren-match-or-strip">
<xsl:with-param name="input"
select="substring($input,2)"/>
<xsl:with-param name="stack"
select="concat(
$stacktop,
$char,
$sep,
$stackrest
)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$input = '' and contains($stackrest,$sep)">
<!--* Input is exhausted and at least one unmatched
* parenthesis is on the stack.
*-->
<xsl:variable name="stacktop2"
select="substring-before($stackrest,$sep)"/>
<xsl:variable name="stackrest2"
select="substring-after($stackrest,$sep)"/>
<xsl:call-template name="paren-match-or-strip">
<xsl:with-param name="input"
select="$input"/>
<xsl:with-param name="stack"
select="concat(
$stacktop2,
substring($stacktop,2),
$sep,
$stackrest2
)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!--* input is exhausted, stack only has one item *-->
<xsl:value-of select="substring-before($stack,$sep)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>