XSL: chop off string at arbitrary place - pdf

I'm using XSL to get an XML styled. The xsl defines a table with two columns. Thanks to Kevin Brown, the following code works fine to chop off at a word boundary, but what I need is to chop off at an arbitrary place.
<fo:table-cell>
<fo:block-container overflow="hidden" height="15pt"><fo:block>this is a very, very, very long text here</fo:block></fo:block-container>
</fo:table-cell>

If you generate this from XML and XSL, you would normally create a template when outputting that particular content and place ​ entities (the zero-width breaking space character). So however you do it, make the content like this (this says "very long word" with that entity between the letters:
v​e​r​y l​o​n​g w​o​r​d
So in your example (I only put them near the break so you can see):
<fo:table-cell border="1pt solid silver">
<fo:block-container overflow="hidden" height="15pt"><fo:block>this is a very, very, very l​o​n​g t​e​x​t here</fo:block></fo:block-container>
</fo:table-cell>
You would get this now ( it breaks at "o" in "long"):
A very interesting effect if you are so inclined is to set "text-align" as "justify" on that fo:block which will actually make all things align if at the end of the block you inserted an fo:leader of sufficient length to fill the cell. NOTE: This does not work in Apache FOP, it does in RenderX XEP.
Like:
<fo:table-cell border="1pt solid silver">
<fo:block-container overflow="hidden" height="15pt"><fo:block text-align="justify">this is a<fo:leader leader-length.minimum="3in"/></fo:block></fo:block-container>
</fo:table-cell>
If you did that, you would get this:

Related

How to align paragraph in XSl FO PDF

I want to align a paragraph below in XSL fO.
Label : value
Be careful not to set the heap size too large, as whatever
you allocate reduces the amount of memory available to the
operating system and other programs, which could cause
excessive paging (memory swapped back and forth between
RAM and the swap disc, which will slow your system down)
with proper alignment and indentation. Am able to create with word-breaks but indentation is missing .can anyone suggest the solution
Think you something like this?
<fo:block text-align="justify" margin-left="1.5cm">Your text here ...</fo:block>
Or you can use linefeed-treatment white-space-treatment, whitespace-collapse attributes together for preformatted texts.
And you can drop the fo:block into a fo:block-container for background coloring and bordering.
<fo:block margin-left="5mm" margin-right="5mm"
font-family="verdana" font-size="12pt"
space-before="5mm" space-after="5mm" keep-together="always"
linefeed-treatment="preserve" whitespace-treatment="pre" whitespace-collapse="false">
Your multiline
code here,
and more lines,
with multiple spaces on start and within
and empty lines ...
</fo:block>

converting xsl-fo to pdf middle dot encoding is not recognized

I am looking for a way to print a list with middle dot.
I am using an xsl file to convert it in a pdf file.
Below is a sample of my xsl file which lead to an unrecognized middle dot in my pdf file :
<?xml version="1.0" encoding="utf-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="Calibri" >
<fo:layout-master-set>
<fo:simple-page-master master-name="FirstPage" margin-top="0.5cm">
<fo:region-body margin-top="6cm" margin-bottom="1.5cm" margin-left="2cm" margin-right="2cm" />
<fo:region-before extent="1cm" region-name="first-page-header"/>
<fo:region-after extent="1cm" region-name="first-page-footer" padding-left="1cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:flow flow-name="xsl-region-body">
<fo:block>
<fo:inline font-family="Symbol">·</fo:inline>
</fo:block>
</fo:flow>
I have tried to include this symbol with "&#183", "&#xb7" and "& middot" but it does not succed.
I also tried to add encoding-mode="single-byte" next to font-family="Calibri" but still no success.
Any idea why it does not work ?
Drop the font-family="Symbol". At present, you are using the Symbol font for the · and not using Calibri, so changing the configuration for Calibri isn't going to change anything.
According to 'Character Map' on Windows 7, Symbol does not have a character at 0xB7 and Calibri has Middle Dot at 0xB7.
(If the purpose of the fo:inline is just to change the font, then you can also drop the fo:inline.)

Data-driven titles in PDFs from Julia using Taro and Mustache

I have some test demographic data in the following form (truncated for demo purposes):
TreatmentArm Site-Subject Gender Age
Placebo 000001-000002 M 42
Placebo 000001-000043 F 23
Placebo 000003-000076 F 45
.
.
Active 000001-000003 M 56
Active 000003-000098 F 34
I can produce a PDF with headers, footers and a table showing the data in the above structure. However, the treatment arm repeats are unnecessary and would normally be handled by sub-titles:
Treatment Arm: Placebo
Site-Subject Gender Age
000001-000002 M 42
000001-000043 F 23
000003-000076 F 45
<page-break>
Treatment Arm: Active
Site-Subject Gender Age
000001-000003 M 56
000003-000098 F 34
So, the two values of treatment arm are controlling the text in the sub-title and the change of the treatment arm value is triggering a page-throw.
The language I'm trying here is Julia, which has, so far, acquitted itself very well. In order to write a simple report to a PDF I need to use a package called Taro, which also uses a port of Mustache.js to Julia. Here, Julia is calling Java, which uses Apache FOP to produce the PDF. Julia calls an XSL-FO template and the Mustache render function marries the data to the template.
Hence, there are 2 source files: the Julia program and the XSL-FO template files. First, the Julia source, abridged as far as possible:
using Taro
# init() once per session to set the Java classpath
Taro.init()
using Mustache
using DataFrames
# get the xsl-fo template
tmpl = Mustache.template_from_file("tables.fo.tmpl")
# get the data, process, sort and select columns
df = readtable("DM1.csv")
df[:sitesubj] = map(x->x[8:end], df[:usubjid])
df2 = sort(df[:, [:armcd, :arm, :sitesubj, :age, :sex]], cols = [:armcd, :sitesubj])
# Write the data to an Array of Dictionaries
d=Array(Dict, nrow(df2));
for i in 1:length(d)
d[i] = Dict{ASCIIString,Any}(
"armcd"=>df2[i, :armcd],
"arm"=>df2[i, :arm],
"sitesubj"=>df2[i, :sitesubj],
"age"=>df2[i, :age],
"sex"=>df2[i, :sex],
)
end
# Some Mustache magic. Render adds the data to the report template
# tn is a String, to is an IOStream
tn, to=mktemp()
fo=render(tmpl, D=d)
write(to, fo)
close(to)
Taro.fo(tn, "test_listing.pdf")
And now the template, abridged as far as possible, but leaving a working example, albeit without the sub-title I need:
<?xml version="1.0" encoding="UTF-8"?>
<fo:root font-family="Courier" font-size="10pt" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="A4-landscape"
margin-right="0.5cm"
margin-left="0.5cm"
margin-bottom="0.5cm"
margin-top="0.5cm"
page-width="29.7cm"
page-height="21cm">
<fo:region-body margin-top="4cm" margin-bottom="3cm"/>
<fo:region-before extent="8cm"/>
<fo:region-after extent="3cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4-landscape">
<!-- Headers -->
<fo:static-content flow-name="xsl-region-before">
<fo:block line-height="14pt" font-size="8pt" text-align-last="justify">ACME Corp
<fo:leader leader-pattern="space" />
CONFIDENTIAL
</fo:block>
<fo:block line-height="14pt" font-size="8pt" text-align-last="justify">XYZ123 / Anti-Hypertensive
<fo:leader leader-pattern="space" />
Draft
</fo:block>
<fo:block line-height="14pt" font-size="8pt" text-align="left">Protocol XYZ123</fo:block>
<fo:block line-height="14pt" font-size="8pt" text-align="center">Study XYZ123</fo:block>
<fo:block line-height="14pt" font-size="8pt" text-align="center">Listing of Demographic Data by Treatment Arm</fo:block>
<fo:block line-height="14pt" font-size="8pt" text-align="center">All Subjects</fo:block>
<fo:block text-align="left">
<!-- Here is where I need to add the current ARM value in a sub-title -->
<!-- fo:retrieve-marker ?? -->
</fo:block>
</fo:static-content>
<!-- Footers -->
<fo:static-content flow-name="xsl-region-after">
<fo:block line-height="14pt" font-size="8pt" text-align="left">A long explanatory text</fo:block>
<fo:block line-height="14pt" font-size="8pt" text-align="left">All subjects are included in the listing including the screen failures</fo:block>
<fo:block line-height="14pt" font-size="8pt" text-align="left">All measurements were taken at the screening visit</fo:block>
<fo:block line-height="14pt" font-size="8pt" text-align-last="left"> Page <fo:page-number/> of <fo:page-number-citation ref-id="end"/>
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<!-- Here I need to capture the value of the current arm -->
<!-- Set a marker ?? -->
<!-- Cannot use {{#:D}} to {{/:D}} as this captures values across all rows -->
<fo:table table-layout="fixed" width="100%" >
<fo:table-column column-width="2cm"/>
<fo:table-column column-width="6cm"/>
<fo:table-column column-width="2cm"/>
<fo:table-column column-width="3cm"/>
<fo:table-header border-bottom-style="solid" border-top-style="solid">
<fo:table-row space-after="10px">
<fo:table-cell>
<fo:block>Arm</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Site ID - Subject ID</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Age</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Gender</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body border-bottom-style="solid">
{{#:D}}
<fo:table-row keep-together.within-page="always">
<fo:table-cell>
<fo:block>{{arm}}</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>{{sitesubj}}</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>{{age}}</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>{{sex}}</fo:block>
</fo:table-cell>
</fo:table-row>
{{/:D}}
</fo:table-body>
</fo:table>
<fo:block id="end"/>
</fo:flow>
</fo:page-sequence>
</fo:root>
One of the problems here is the mixture of technologies and where to address the problem. Do I need to pre-summarize in Julia and pass another dictionary with just the 'Placebo' and 'Active' values to the template. Even so, there must be some mechanism to recognise position within the template. I don't think it possible to add XSL directives to the mix, so logic within the template eludes me. As the comments in the XSL-FO file suggest, maybe the way is to set and retrieve markers, but the recognition of the 'first row in a BY group' does not seem to be present. I hope I am wrong and this is possible.
The paging issue seems to have been solved by
<fo:table-row keep-together.within-page="always">
But this is not like saying 'when this condition is reached, throw a page.'
So, if anybody has suggestions, I'm more than happy to test them. Many thanks.
Since Mustache is, by design, 'logic-less', I would implement this by summarising in julia. Pass in an outer array. Each row in that array has two columns. The first column contains the "Arm", and the second column contains another array, containing the data for that "Arm".
In addition, the subheader should not be in static-content. It should be part of the flow content. Am I missing something here?
These changes, combined with keep-together should give you want you need.

XSLT new lines not being preserved

For some reason my spaces aren't being preserved in my final PDF after xslt. My desired output is:
Static
text bold.
Here's my xslt template:
<xsl:preserve-space elements="*" />
<xsl:strip-space elements="" />
<xsl:template match="coverPage">
<fo:block font-size="12pt" color="black" text-align="center">
<xsl:text>
Static
text
</xsl:text>
</fo:block>
<fo:block font-size="12pt" color="black" text-align="center" font-weight="bold">
<xsl:text>
bold.
</xsl:text>
</fo:block>
</xsl:template>
I think there are a few issues with your XSLT:
there is no need to enclose the text inside xsl:text elements, as those text nodes are not composed only of whitespace characters and therefore will never be stripped (see Whitespace stripping for more details)
for the same reason, there is no need to use xsl:preserve-space and xsl:strip-space, unless of course you need them for other reasons
preserving linefeeds in the transformation from XML to XSL-FO is just the (required) first step, but then you must preserve them during the processing of the XSL-FO file; in order to do this, you must use the linefeed-treatment property: linefeed-treatment="preserve"
a literal linefeed is equivalent to a
entity, so in your input you have 3 linefeeds between "Static" and "text", which will produce two empty lines when preserved; if that's not what you want, you have to remove some of them
the words "text" and "bold" are inside two different fo:block elements, so this means they will always be on different lines; if you want them to be placed one beside the other, those words must be inside fo:inline elements instead (and there must be an outer fo:block to contain them)
A final word of warning
While looking at an FO file the difference between a preserved linefeed and an ignored one is not immediately apparent, as it boils down to the presence of the linefeed-treatment attribute in an ancestor element (which could be quite far from the text node itself).
Clearer ways to force a line break in a specific position include:
using different fo:block elements, each one containing the text that should create a line (or several ones)
<fo:block>Static</fo:block>
<fo:block>text <fo:inline font-weight="bold">bold.</fo:inline></fo:block>
using an empty fo:block where a line break should be
<fo:block>
Static
<fo:block/>
text <fo:inline font-weight="bold">bold.</fo:inline>
</fo:block>

words don't break correctly

In a block I have a text. I have some trouble with the linefeedtreatment.
<fo:block>
<xsl:value-of select="text"/>
</fo:block>
The text Shows like this:
Master II Phase 1, Pha-
se 2, Phase 3
Must look like this:
Master II Phase 1,
Phase 2, Phase 3
I've tried "Keep-together.within-line" and "linefeed-treatment" but without any result.
You appear to have hyphenation enabled when you don't want it to be. Presumably your FO contains hyphenate="true" on some ancestor FO. See https://www.w3.org/TR/xsl11/#hyphenate
Add hyphenate="false" to the fo:block to disable hyphenation of the text in the block.
The other possibility is that you have soft-hyphen characters in your text. If hyphenate="false" doesn't solve the problem, please edit your question to add the XML for the text element that has the problem.