Text Layout

1. New element on right hand page
2. Vertical positioning of page contents in XSL FO
3. right to left writing mode
4. Vertical centred text.
5. Text align vs text-align-last
6. Is there a way to introduce soft line breaks into XSL:FO output?
7. White space problems?
8. left to right and right to left, perhaps for Arabic or Hebrew?
9. Capitalize first letter
10. Vertical alignment of fo:inlines
11. Preserve all spaces
12. Handling white space, of varying size!
13. Text flow round a shape

1.

New element on right hand page

Nikolai Grigoriev


> 2. I need chapters and some elements of the front matter to start on a
> right hand page. I am currently attempting to apply the break-before
> ="odd-page" attribute to the fo:block element corresponding to the element
> that needs to start on the right page but it is not working - all I get is
> a standard page break. Am I doing something wrong or is there another way
> to achieve this?

An alternative solution would be to put chapters in separate page sequences and control the length of the preceding page sequence:

<fo:page-sequence force-page-count="end-on-even">....

This eventually adds a blank page so that the last page in the sequence is always even-numbered. (That's how it is done in the PDF for XSL CR).

2.

Vertical positioning of page contents in XSL FO

Jeni Tennison

To vertically align at the bottom, you need to set the display-align property on the fo:region-body formatting object to 'after'. That aligns the content of the page to the bottom of the page, but if the page can be filled up, then it will be completely filled up, so I'm not sure that's what you want to do.

Instead, I think you want to set the margin-top of the fo:region-body in the fo:simple-page-master used for the first page of the chapter to 33% or 50%, so that the region in which the content can be placed only starts a third or half way down the page in the first place. Obviously that means having different fo:simple-page-masters for different pages, so you need to use a fo:page-sequence-master to control it.

3.

right to left writing mode

Max Froumentin


> how does one make a fo:block to write from left to right and not top to
> bottom?
> Thanx

Look at the Writing Mode properties at The rec

Cyrilo rognon adds

First answer : You can use the reference-orientation property if your fo processor supports it.

Second answer : What are you trying to do ? do you want the whole document to be re-oriented or just some part of it ?

ref orientation may be applied to region, so it does a good job if you want start region with a verticaly aligned text. If the whole document is targeted (an entire page I mean), you could use the page size setting to simulate the reference-orientation property, since it is not very well supported by now.

4.

Vertical centred text.

Ken Holman



>is there any other possibility to place a block vertically centered on a
>page?

The following works for me in Antenna House where the first page sequence centres text in a two-inch high box and the second page sequence centres the text on the page:

<page-sequence master-reference="frame-pages">

<flow flow-name="frame-body">

<block-container border-style="solid" height="2in" display-align="center">
   <block text-align="center">Centred text</block>
</block-container>

</flow>

</page-sequence>

<page-sequence master-reference="frame-pages">

<flow flow-name="frame-body">

<block-container border-style="solid" height="100%" display-align="center">
   <block text-align="center">Centred text</block>
</block-container>

</flow>

</page-sequence>

Of course the border is optional, but it helps me see what is going on.

5.

Text align vs text-align-last

David Tolpin



> Is "text-align-last" has higher priority over "text-align" or not?

This is not a question of priorities or precedences. text-align does not apply to the last line of a paragraph; if text-align-last is not set, it is the same as text-align unless text-align is justify; in which case text-align-last is start.

The Recommendation is unambigious:


7.15.10.  text-align-last  

XSL Definition: 
Value: relative | start | center | end | justify | inside | outside | left |
right | inherit 
Initial: relative 
Applies to: fo:block 
Inherited: yes 
Percentages: N/A 
Media: visual 

Values have the following meanings:

relative

If text-align is justify, then the alignment of the last line, and of any line ending in U+000A, will be start. If text-align is not justify, text-align-last will use the value of text-align.

Ken adds

>The question: which alignation should be used for the 1-line blocks if 
>"text-align" is not the same to "text-align-last"

text-align-last= only applies to the last line in a block and a 1-line block is considered the last line for justification (note that it is also considered the first line for other things like text-indent=, <initial-property-set>, etc.).


>and why?

Think about paragraph printing in a newspaper or in a novel: You read a long 7-line paragraph and the first 6-lines are justified side-to-side, the last line is not justified and just ends in the middle of the line.

The next paragraph is short at, say, only 5 words ... would you expect those words to be justified from side to side? Nope! You would expect it to be short, just like the last line of a multiple line block.

The nuance about this issue is the use of justify ... if you use anything other than justify, say "center" or "end", it applies to all lines of the block. But if you use "justify" it *doesn't* apply to the last line of the block, for the reasons described above.

If you wanted the entire block to be justified side to side (and you *do* when doing entries in tables of content that have leaders on the last line) you have to specify *both* text-align= and text-align-last=.

6.

Is there a way to introduce soft line breaks into XSL:FO output?

David Tolpin



> I have two URLs in table cells, that breaks in this manner:
>   ht-
>   ttp://somemachine/path/to/some-
>   where

> And that looks a bit silly.

Soft linebreaks are called zero-width space in Unicode, 200B hexadecimal. Insert &\x200B; during preprocessing at points where you want the URL to be broken, turn hyphenation off for that part of the text and don't use an FO processor that breaks line when it is not asked to.

7.

White space problems?

Ken Holman


>We're having a white space problem.  When we render to PDF/Printer, all 
>white space is removed between variables and all blank lines in the 
>document (<fo:block font-family="Helvetica" font-size="12pt"
>white-space-collapse="false" space-after="0.05pt" />) are also removed.

There are four parameters to play with, not just one ... there is also a shorthand that sets all four parameters:

   - the shorthand:  white-space="pre"

   - sets the following:   linefeed-treatment="preserve"
                           white-space-collapse="false"
                           white-space-treatment="preserve"
                           wrap-option="no-wrap"

If you use a monospaced font and the shorthand or the explicit properties you will get the effect usually desired for program code listings in reports, which is what I think you are asking for.

8.

left to right and right to left, perhaps for Arabic or Hebrew?

J.Pietschmann



> Now that I am turning my attention to our language requirements (Hebrew & 
> Arabic), I would like this character to "flip" and point the opposite 
> direction. There is no corresponding left-pointing-arrow in the Dingbat 
> Font.

> Is there any fo:magic I could use to achieve this? 

XSLFO supports Unicode BIDI. Check out the BIDI properties of the arrow, if it's mirrored, it will flip automatically in a rl writing mode context. I suspect it isn't mirrored though. The properties can be found here

9.

Capitalize first letter

David Tolpin



> I was wondering if there is an xsl technique or function which I can use
> to create text with initial capitalizations e.g.
>
> "New York" = initcap("NEW york")
>
> The closest I found is translate("NEW york","abcd..z","ABCD..Z") which is
> not what I really need.

If you need it in the presentation form, then it can be done by text-transform="capitalize" in XSL 1.0 (XSL FO). I think text-transform: capitalize is present in CSS too.

This will not create capitalized text, but rather will represent the text as capitalized.

Use XSLT to select the first letter, (substring function) then use the text-transform property.

10.

Vertical alignment of fo:inlines

Victor Vishnyakov



> I want to do the following:

> I need one textline with different font-families and/or font-sizes. I 
> managed this problem with using fo:inline elements within a fo:block.

> now I need to vertically center all fo:inline elements. so, for 
> example, I have the text "big letters" with font-size="2.0mm" directly 
> followed by the text "small letters" with font-size="1.0mm". I need 
> the text "small letters" to appear vertically centered.

Take a look at "7.13.2. alignment-baseline" chapter in the XSL-FO specification. The value "central" or "middle" is might be what you are looking for.

11.

Preserve all spaces

David Carlisle

To make the text appear just as it is in the xml file do the following.

<fo:block white-space-treatment="preserve"
          linefeed-treatment="preserve"
          whitespace-collapse="false"
          font-family="monospace">
   <!-- YOUR CODE HERE -->
<fo:block>

12.

Handling white space, of varying size!

Jirka Kosek


> fixed spaces need to be easily entered, correctly processed and properly
> output at the desired width. Period.

Indeed. You can use Unicode characters to specify these fine tuned spacing and add following XSLT code into transformation to get proper spacing in output.

<xsl:template match="text()">
   <xsl:call-template name="space.2000.subst">
     <xsl:with-param name="string" select="."/>
   </xsl:call-template>
</xsl:template>

<!-- You can adjust width of spaces by parameters. Empty value means 
that space is not converted to fo:leader -->
<xsl:param name="space.enquad.width">0.5em</xsl:param> <!-- U+2000 -->
<xsl:param name="space.emquad.width">1em</xsl:param>   <!-- U+2001 -->
<xsl:param name="space.enspace.width">0.5em</xsl:param><!-- U+2002 -->
<xsl:param name="space.emspace.width">1em</xsl:param><!-- U+2003 -->
<xsl:param name="space.3emspace.width">0.33em</xsl:param><!-- U+2004 -->
<xsl:param name="space.4emspace.width">0.25em</xsl:param><!-- U+2005 -->
<xsl:param name="space.6emspace.width">0.16em</xsl:param><!-- U+2006 -->
<xsl:param name="space.figspace.width"></xsl:param><!-- U+2007 -->
<xsl:param name="space.punctspace.width"></xsl:param><!-- U+2008 -->
<xsl:param name="space.thinspace.width">0.2em</xsl:param><!-- U+2009 -->
<xsl:param name="space.hairspace.width">0.1em</xsl:param><!-- U+200A -->

<xsl:template name="space.2000.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x2000;') and 
$space.enquad.width != ''">
       <xsl:call-template name="space.2001.subst">
        <xsl:with-param name="string" select="substring-before($string, 
'&#x2000;')"/>
       </xsl:call-template>
       <fo:leader leader-length="{$space.enquad.width}"/>
       <xsl:call-template name="space.2000.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x2000;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="space.2001.subst">
        <xsl:with-param name="string" select="$string"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="space.2001.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x2001;') and 
$space.emquad.width != ''">
       <xsl:call-template name="space.2002.subst">
        <xsl:with-param name="string" select="substring-before($string, 
'&#x2001;')"/>
       </xsl:call-template>
       <fo:leader leader-length="{$space.emquad.width}"/>
       <xsl:call-template name="space.2001.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x2001;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="space.2002.subst">
        <xsl:with-param name="string" select="$string"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="space.2002.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x2002;') and 
$space.enspace.width != ''">
       <xsl:call-template name="space.2003.subst">
        <xsl:with-param name="string" select="substring-before($string, 
'&#x2002;')"/>
       </xsl:call-template>
       <fo:leader leader-length="{$space.enspace.width}"/>
       <xsl:call-template name="space.2002.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x2002;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="space.2003.subst">
        <xsl:with-param name="string" select="$string"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="space.2003.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x2003;') and 
$space.emspace.width != ''">
       <xsl:call-template name="space.2004.subst">
        <xsl:with-param name="string" select="substring-before($string, 
'&#x2003;')"/>
       </xsl:call-template>
       <fo:leader leader-length="{$space.emspace.width}"/>
       <xsl:call-template name="space.2003.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x2003;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="space.2004.subst">
        <xsl:with-param name="string" select="$string"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="space.2004.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x2004;') and 
$space.3emspace.width != ''">
       <xsl:call-template name="space.2005.subst">
        <xsl:with-param name="string" select="substring-before($string, 
'&#x2004;')"/>
       </xsl:call-template>
       <fo:leader leader-length="{$space.3emspace.width}"/>
       <xsl:call-template name="space.2004.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x2004;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="space.2005.subst">
        <xsl:with-param name="string" select="$string"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="space.2005.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x2005;') and 
$space.4emspace.width != ''">
       <xsl:call-template name="space.2006.subst">
        <xsl:with-param name="string" select="substring-before($string, 
'&#x2005;')"/>
       </xsl:call-template>
       <fo:leader leader-length="{$space.4emspace.width}"/>
       <xsl:call-template name="space.2005.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x2005;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="space.2006.subst">
        <xsl:with-param name="string" select="$string"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="space.2006.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x2006;') and 
$space.6emspace.width != ''">
       <xsl:call-template name="space.2007.subst">
        <xsl:with-param name="string" select="substring-before($string, 
'&#x2006;')"/>
       </xsl:call-template>
       <fo:leader leader-length="{$space.6emspace.width}"/>
       <xsl:call-template name="space.2006.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x2006;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="space.2007.subst">
        <xsl:with-param name="string" select="$string"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="space.2007.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x2007;') and 
$space.figspace.width != ''">
       <xsl:call-template name="space.2008.subst">
        <xsl:with-param name="string" select="substring-before($string, 
'&#x2007;')"/>
       </xsl:call-template>
       <fo:leader leader-length="{$space.figspace.width}"/>
       <xsl:call-template name="space.2007.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x2007;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="space.2008.subst">
        <xsl:with-param name="string" select="$string"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="space.2008.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x2008;') and 
$space.punctspace.width != ''">
       <xsl:call-template name="space.2009.subst">
        <xsl:with-param name="string" select="substring-before($string, 
'&#x2008;')"/>
       </xsl:call-template>
       <fo:leader leader-length="{$space.punctspace.width}"/>
       <xsl:call-template name="space.2008.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x2008;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="space.2009.subst">
        <xsl:with-param name="string" select="$string"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="space.2009.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x2009;') and 
$space.thinspace.width != ''">
       <xsl:call-template name="space.200A.subst">
        <xsl:with-param name="string" select="substring-before($string, 
'&#x2009;')"/>
       </xsl:call-template>
       <fo:leader leader-length="{$space.thinspace.width}"/>
       <xsl:call-template name="space.2009.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x2009;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="space.200A.subst">
        <xsl:with-param name="string" select="$string"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="space.200A.subst">
   <xsl:param name="string"/>

   <xsl:choose>
     <xsl:when test="contains($string, '&#x200A;') and 
$space.hairspace.width != ''">
       <xsl:value-of select="substring-before($string, '&#x200A;')"/>
       <fo:leader leader-length="{$space.hairspace.width}"/>
       <xsl:call-template name="space.200A.subst">
        <xsl:with-param name="string" select="substring-after($string, 
'&#x200A;')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:value-of select="$string"/>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

I will add this code into the DocBook XSL stylesheets, so it will just works for them.

13.

Text flow round a shape

Eliot Kimber


> I am trying to determine how to specify making text flow around a shape,
> like a circle.  I don't have a specific flow order scenario, I only
> trying to understand the how-to's and constraints to do so.

There is no automatic way to do this in XSL-FO--the best you can do is flow text around two sides of a box using side floats.

With care you might be able to simulate it by using side floats, one per line of text, to move the text out of the way of the shape and then use an absolutely-positioned block container to overlay the shape where you've created a void in the text, but I can't imagine this could be done automatically, at least not without a lot of effort.

Eliot later added

It just occurs to me that with XSL 1.1 you could do it by having a sequence of one-line-high body regions that go around the shape, connected using a flow map. It would be tedious to code but it should work. It would require a separate page master just for that page, which implies a very specialized page sequence to use the master (unless it's a repeating style element like an article opener or something).

Hmmm. Now that I think about it, it should be possible to achieve a number of graphical layout effects using this approach that are not possible in 1.0.