DEVELOPER'S ZONE 

 SHOP 


 SEARCH 

 LIVE HELP 
[logo]
 Products
 Demos
 Stories
 Solutions
 Support
 Download
 Customers
 Partners
 Company
 Sitemap

 Support Home


 XSL Tutorial


 XEP User Guide


 AFP Reference


 VisualXSL User Guide


 Announcements


 Support List


 Product Updates



Download Now!



RenderX offers all our software on a trial basis so that our prospects can easily see why thousands of customers have selected XEP to meet their needs.

Why not download a trial version today and see for yourself!

XSL Formatting Objects Tutorial

Nikolai Grigoriev


Introduction

This document gives a quick, learn-by-example introduction to XSL Formatting Objects. I don't discuss subtle details of implementation, but rather provide a series of examples of how to perform routine tasks with XEP — an XSL formatter developed by RenderX, Inc. It is not a manual of XSL FO (XSLFO) in general, and some examples given here may not work in other XSL FO (XSLFO) formatters, or give different results.

This tutorial was conceived as a means to facilitate reading of XSL 1.0 Recommendation of October 15, 2001. The normative text is available from W3C site: http://www.w3.org/TR/2001/REC-xsl-20011015/. You should obtain a copy of XSL 1.0 Recommendation, and refer to it for a complete description of objects and properties mentioned here.

XEP 4.0 also implements several extensions to the XSL 1.0 Recommendation: they add support for useful functionality that cannot be expressed by standard XSL Formatting Objects. The last chapters of this document discuss available extensions in more detail. Needless to say, the extensions are proprietary and incompatible with other XSL formatters; please avoid their use whenever possible.

Readers who aren't XEP users can download an evaluation copy of XEP from http://www.renderx.com/download/index.html, and run the proposed examples to see how the formatter works. This manual is also available in XML format with an associated XSL FO (XSLFO) stylesheet; browsing its source code may also be interesting (and instructive).

XEP covers more of the spec than was needed for this manual. Please refer to XEP product documentation for a full list of supported elements and properties.

“Hello, World!”

Let us create the shortest XSL FO (XSLFO) document.

<?xml version="1.0" encoding="iso-8859-1"?>1

<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">2
  <fo:layout-master-set>3
    <fo:simple-page-master master-name="my-page">
      <fo:region-body margin="1in"/>
    </fo:simple-page-master>
  </fo:layout-master-set>

  <fo:page-sequence master-reference="my-page">4
    <fo:flow flow-name="xsl-region-body">5
      <fo:block>Hello, world!</fo:block>6
    </fo:flow>
  </fo:page-sequence>
</fo:root>
      
1

This is an XML declaration. XSL FO (XSLFO) belongs to XML family, so this is obligatory.

2

Root element. The obligatory namespace attribute declares the XSL Formatting Objects namespace.

3

Layout master set. This element contains one or more declarations of page masters and page sequence masters — elements that define layouts of single pages and page sequences. In the example, I have defined a rudimentary page master, with only one area in it. The area should have a 1 inch margin from all sides of the page.

4

Page sequence. Pages in the document are grouped into sequences; each sequence starts from a new page. Master-reference attribute selects an appropriate layout scheme from masters listed inside <fo:layout-master-set>. Setting master-reference to a page master name means that all pages in this sequence will be formatted using this page master.

5

Flow. This is the container object for all user text in the document. Everything contained in the flow will be formatted into regions on pages generated inside the page sequence. Flow name links the flow to a specific region on the page (defined in the page master); in our example, it is the body region.

6

Block. This object roughly corresponds to <DIV> in HTML, and normally includes a paragraph of text. I need it here, because text cannot be placed directly into a flow.

Now we can save this document into a file and compile it using XEP 4.0. to produce a PDF file. Open it with Acrobat Reader, and enjoy :-).

Font and Text Attributes

Let us now enrich the text with character-level formatting. Several properties control font styles — family, size, color, weight, etc. Let's look at some examples:

<fo:block font-family="Times" font-size="14pt">
  Hello, world!
</fo:block>
    

Font family is Times, and font size is 14 points.

<fo:block font-family="Times" font-size="14pt" font-style="italic">
  <fo:inline color="red">H</fo:inline>ello,
  <fo:inline font-weight="bold">world!</fo:inline>
</fo:block>
    

Same as above, plus:

  • the whole text is italicized (font-style="italic");

  • the first letter of the first word is written in red (color="red");

  • the second word is written in bold font (font-weight="bold").

Note a new formatting object — <fo:inline>. It corresponds to <SPAN> in HTML, and ascribes formatting to chunks of text within a block.

Font properties are inheritable. It means that, once defined for a formatting object, they apply to all formatting objects inside it. That's why the first inline sequence affects only the color of the font, leaving its family, size, and slant unmodified. Inheritable properties can be put almost everywhere on the formatting objects tree; as a rule, you specify default font for a document by applying these properties to <fo:flow>, <fo:page-sequence> or even <fo:root>.

To reduce typing, you can use a shorthand notation for setting font attributes as a group. For example, the above example can be rewritten as follows:

<fo:block font="italic 14pt Times">
  <fo:inline color="red">H</fo:inline>ello,
  <fo:inline font-weight="bold">world!</fo:inline>
</fo:block>
    

The font property has the following syntax:

[<style, weight, and/or variant>] <size>[/<line height>] <family>

It sets all mentioned attributes to specified values, and resets all other font-related attributes to their default values, overriding inherited values. Be careful when using this feature: font="14pt Times" is not equivalent to a conjunction of font-size="14pt" & font-family="Times"!

Let's now build a full XSL FO (XSLFO) example with font attributes introduced above, and some new ones:

<?xml version="1.0" encoding="iso-8859-1"?>

<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <fo:layout-master-set>
    <fo:simple-page-master master-name="my-page">
      <fo:region-body margin="1in"/>
    </fo:simple-page-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="my-page">
     <fo:flow flow-name="xsl-region-body" font="12pt Times"1>
       <fo:block font="italic 24pt Helvetica">
         <fo:inline color="red">F</fo:inline>ont
         <fo:inline color="red">A</fo:inline>ttributes
       </fo:block>
       <fo:block>2
         The inherited font for this block is 12pt Times.
       </fo:block>
       <fo:block>
         Font attributes:
         <fo:inline color="red">colored</fo:inline>,
         <fo:inline font-weight="bold">bold</fo:inline>,
         <fo:inline font-style="italic">italic</fo:inline>,
         <fo:inline font-size="75%">small</fo:inline>,
         <fo:inline font-size="133%">large</fo:inline>.
       </fo:block>
      <fo:block>
         Text attributes:3
         <fo:inline text-decoration="underline">underlined</fo:inline>,
         <fo:inline letter-spacing="3pt"> expanded </fo:inline>,
         <fo:inline word-spacing="6pt">
           text with extra spacing between words
         </fo:inline>,
         <fo:inline text-transform="uppercase">all capitals</fo:inline>,
         <fo:inline text-transform="capitalize">capitalized</fo:inline>,
         text with <fo:inline baseline-shift="sub"
         font-size="smaller">subscripts</fo:inline>
         and <fo:inline baseline-shift="super"
         font-size="smaller">superscripts</fo:inline>.
      </fo:block>
    </fo:flow>
  </fo:page-sequence>
</fo:root>
      
1

A common font for the whole flow is specified.

2

This block inherits font attributes from the flow.

3

In this block, I introduce several other text-level properties:

text decoration

underline/overline/strikethrough;

letter and word spacing

a positive value expands text, a negative value condenses it;

text transformations

upper/lower case, capitalize;

shifted text

subscripts and superscripts.

Blocks

Text Alignment, Line Height

Let's consider this piece:

<fo:block line-height="1.5" text-align="justify">
  This is an example of double-justified text.
  The space between lines is 1.5 of the nominal font height.
</fo:block>
    

The line-height property specifies the line height: it can be expressed as a length, as a numeric value, or as a percent. Numbers and percents are interpreted as multiples to the nominal font height.

Text-align property defines the alignment of the text within the block. XSL FO (XSLFO) uses a specific coordinate system for referring to block edges: instead of ‘left’ and ‘right’, side alignment is expressed in terms of inline progression direction. For Western scripts, glyphs on the line are placed from left to right; therefore, left-aligned text will have text-align="start", and right-aligned text will have text-align="end". Two other values are "center" and "justify" (same as in CSS). You can also use other CSS values for this property — "left" is a synonym for start, and "right" is a synonym for end.

Let's look into a more complicated example:

<fo:block text-align="justify" text-indent="1in"
          text-align-last="end" last-line-end-indent="1in">
  This is an example of double-justified text with an indented first line.
  The last line of the text is aligned to the right, and indented
  by 1 inch from the right.
</fo:block>
    

This fragment should be formatted as follows:

  • text is double justified (text-align);

  • the first line is indented by 1 inch from the left (text-indent);

  • the last line is aligned to the right (text-align-last);

  • the last line is indented by 1 inch from the right (last-line-end-indent).

By specifying a negative value for text-indent / last-line-end-indent, it is possible to create outdents. To make the text stay within the limits, two more properties are used that control indentation of the text as a whole:

<fo:block text-align="start" text-indent="-1in"
          text-align-last="end" last-line-end-indent="-1in"
          start-indent="1in" end-indent="1in">
  This is an example of left-aligned text with an outdented first line.
  The last line of the text is aligned to the right, and outdented
  by 1 inch from the right.
</fo:block>
    

The names of properties start-indent and end-indent follow the same logic as the values for text-indent: start-indent controls white space added at the beginning of every line, and end-indent adds a margin at the end of every line.

To complete this chapter, let's introduce attributes to position blocks vertically with respect to each other: space-before and space-after. Their names also derive from the writing-mode approach: ‘before’ means “before the first line”, and ‘after’ implies “after the last line”.

Spaces are more complicated than indents: they aren't specified as a single value, but rather as a vector of several components — minimum, optimum, and maximum value for the space. Components can be assigned separately: an attribute name will consist of a property name followed by a component name, separated by a dot. You can also assign all numeric components the same value by using the attribute name without a component qualifier; this is what you normally do in most cases.

An important property of spaces is that they aren't additive: if there are several space specifiers between two blocks (e.g. space-after on a preceding block and space-before on a following block), a single space value is choosen so as to satisfy all applicable constraints. Apparently, spaces merge and don't sum up. (The real rules for space resolution are more complicate; please refer to the XSL FO (XSLFO) specs).

The fragment below illustrates the use of spaces:

<fo:flow flow-name="xsl-region-body" font="14pt Times">
  <fo:block font-size="24pt"
            text-align="center"
            space-before="30pt"
            space-before.conditionality="retain"1
            space-after="12pt">The Jabberwocky</fo:block>
  <fo:block font-style="italic"
            text-align="end"
            space-before="12pt"
            space-after="9pt">Lewis Carroll</fo:block>
  <fo:block start-indent="1.5in" space-after="9pt">
    <fo:block>&#8217;2Twas brillig, and the slithy toves</fo:block>
    <fo:block>Did gyre and gimble in the wabe:</fo:block>
    <fo:block>All mimsy were the borogoves,</fo:block>
    <fo:block>And the mome raths outgrabe.</fo:block>
  </fo:block>
  <fo:block start-indent="1.5in" space-after="9pt">
    <fo:block>&#8220;3Beware the Jabberwock, my son!</fo:block>
    <fo:block>The jaws that bite, the claws that catch!</fo:block>
    <fo:block>Beware the Jubjub bird, and shun</fo:block>
    <fo:block>The frumious Bandersnatch!&#8221;4</fo:block>
  </fo:block>
</fo:flow>
      
1

By default, space-before at the top of the page and space-after at the bottom of the page are suppressed. To force them, specify .conditionality="retain".

2

&#8217; is a UCS code for right single quote. XEP addresses all characters by their Unicode values.

34

&#8220; and &#8221; are UCS codes for left and right double quotes.

Borders, Padding, and Background

Blocks may have borders from either side. Sides can be addressed either in an absolute orientation scheme (left, right, top, and bottom), or in a writing-mode relative scheme (resp. start, end, before, and after).

Every border has the following properties, that may get the following values in XSL FO (XSLFO):

color

one of 16 predefined HTML system colors, or an RGB value;

style

solid, dashed, dotted, double, inset, outset, groove, ridge, or none;

width

thin, medium, thick, or an explicit width specification.

You can specify each property for each border separately by writing several attributes of the form border-{side}-{property}:

<fo:block border-top-color="black"
          border-top-style="solid"
          border-top-width="thick"
          text-align="center">
  Thick black border at the top
</fo:block>
    

You can also specify properties for all the four sides as a whole, using a shorthand notation border-{property}:

<fo:block border-color="gray"
          border-style="groove"
          border-width="medium"
          text-align="center">
  Medium gray groove around the whole block
</fo:block>
    

You can also group properties that refer to one side into a single shorthand attribute border-{side}. However, only absolutely oriented side names (top, bottom, left, and right) are permitted in this position. An example:

<fo:block text-align="center"
          border-top="dashed 1pt #C00000"1
          border-bottom="1pt dashed #C00000">
  1pt dashed red border at the top and bottom
</fo:block>
      
1

Elements inside the attribute can be specified in any order, separated by spaces.

Finally, a single border attribute can accumulate properties that are ascribed to all the four sides:

<fo:block border="thin silver ridge"
          text-align="center">
  Thin silver ridge around the whole block
</fo:block>
    

When printed, a block may be split by a page break or a column break. What happens to the borders adjacent to the breakline? For some block types, you may want to box every part of the original block separately, i.e. draw a border line where the break occurs; this is the default behaviour in XSL FO (XSLFO). For some other blocks, you may prefer to “keep the box open” suppressing borders at column/page breaks. This behavior is controlled by a special component of the border's width — border-{side}-width.conditionality:

<fo:block border="thin blue groove"
          border-before-width.conditionality="discard"
          border-after-width.conditionality="discard">
  If this block happens to be split by a page break,
  no line will be drawn on either side of the break.
</fo:block>
    

Only writing-mode oriented sides (before, after, start, and end) are permitted in the conditional border expressions.

Once you have set a border around an object, you normally want to specify a padding between the text and the border. This is done by padding-{side} attributes:

<fo:block border="thin solid navy"
          text-align="center"
          padding-before="18pt"
          padding-bottom="18pt">
  <fo:block border="thin solid maroon">
    The outer block has a 18 pt padding from top and bottom
  </fo:block>
</fo:block>
    

There also exists a shorthand padding attribute:

<fo:block border="thin solid navy"
          text-align="center"
          padding="2cm">
  <fo:block border="thin solid maroon">
    The outer block has a 2 cm padding from all sides
  </fo:block>
</fo:block>
    

You can also specify several numbers as a value for padding attributes:

  • if there are two values, the top and bottom paddings are set to the first value and the right and left paddings are set to the second;

  • if there are three values, the top is set to the first value, the left and right are set to the second, and the bottom one is set to the third;

  • if there are four values, they apply to the top, right, bottom, and left, respectively.

Example:

<fo:block border="thin solid navy"
          text-align="center"
          padding="1cm 3cm">
  <fo:block border="thin solid maroon">
    The outer block has 1 cm padding from top and bottom,
    and 3 cm padding from right and left.
  </fo:block>
</fo:block>
    

Like borders, padding may be conditional at page breaks: specifying padding-{side}.conditionality="discard" suppresses padding before or after a page break. Like for borders, only writing-mode oriented sides (before, after, start, and end) are permitted in this position.

To complete the picture, let's learn how to set backgrounds for blocks.

Blocks may have different backgrounds — colored or even decorated with a graphic. To specify a color for the background, use background-color property:

<fo:block color="yellow"
          background-color="red"
          padding="12pt"
          text-align="center">
  Yellow on red
</fo:block>
    

To add a background image to the block, you should

  • specify image source — background-image;

  • specify image position — background-position;

  • specify whether the image should be repeated along any of the axes — background-repeat.

The background-image attribute specifies an URI of the bitmap image file. XEP handles HTTP, FTP, and file system resource locators in URIs. An unqualified URI is treated as a path to a file in the local file system; if the path is relative, it is calculated from the location of the source XSL FO (XSLFO) document (rather than from the current directory where XEP is run). Note also the url('…') function-like wrapper around the file name: this is required by the XSL 1.0 Recommendation. (XEP recognizes unwrapped URLs, too).

Note

Under Win32, absolute pathnames may contain a colon after the disk letter. These colons confuse Java URI resolver: the disk letter is treated as protocol name. Use an unabridged file URI:

file:/C:/XEP/myimage.jpg

Example:

<fo:block border="0.5pt solid silver"
          background-image="url('spots.jpg')"
          padding="18pt"
          text-align="center">
  The whole background tiled with colored spots
</fo:block>
    

By default, an image specified in background-image tiles the whole block. To insert only a single instance, disable tiling by setting background-repeat="no-repeat":

<fo:block border="0.5pt solid silver"
          background-image="url('spots.jpg')"
          background-repeat="no-repeat"
          background-position-horizontal="center"
          background-position-vertical="center"
          padding="18pt"
          text-align="center">
  A single image placed 18pt to the right
  and 6pt below the upper left corner.
</fo:block>
    

The position of the image within the block is controlled by two properties, background-position-horizontal and background-position-vertical. The background-position shorthand property from CSS2 can also be used:

<fo:block border="0.5pt solid silver"
          background-image="url('spots.jpg')"
          background-repeat="repeat-y"
          background-position="left center"
          background-color="silver"
          padding="18pt"
          text-align="center">
  A stripe made of coloured spots along the left edge of the block;
  the rest of the block has a silver background.
</fo:block>
    

XSL Recommendation defines no method to scale the background image. To do it, you have to recur to RenderX add-ons; see description of rx:background-content-width, rx:background-content-height, and rx:background-scaling extension properties in the documentation for XEP 4.0.

Page Layout

Page Sequence Masters

So far, I have used only single page masters in examples. In this section, more complex cases will be analyzed. To start, let's design a page sequence with two page masters: one for the first page, the other one for the rest of the document.

<?xml version="1.0" encoding="iso-8859-1"?>

<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <fo:layout-master-set>
    <fo:simple-page-master master-name="first-page">
      <fo:region-body margin="1in" border="thin silver ridge"1
                                      padding="6pt"/>
    </fo:simple-page-master>
    <fo:simple-page-master master-name="all-pages">
      <fo:region-body margin="1in"/>
    </fo:simple-page-master>
    <fo:page-sequence-master master-name="my-sequence">2
      <fo:single-page-master-reference master-reference="first-page"/>3
      <fo:repeatable-page-master-reference master-reference="all-pages"/>4
    </fo:page-sequence-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="my-sequence"5>
    <fo:flow flow-name="xsl-region-body" font="72pt Times">
       <fo:block space-before="2in" space-after="2in">6
         First block
       </fo:block>
      <fo:block break-before="page" space-before="2in" space-after="2in">7
         Second block
       </fo:block>
      <fo:block break-before="page" space-before="2in" space-after="2in">
         Third block
       </fo:block>
    </fo:flow>
  </fo:page-sequence>
</fo:root>
      
1

In XSL FO (XSLFO), you can specify borders, padding, and background on regions in exactly the same way as you do it on blocks. The first page in this example will have a border around it, while others will remain borderless.

2

The page sequence master defines the chain of page masters to use for a page sequence.

3

<fo:single-page-master-reference> inserts a single page master in the chain.

4

<fo:repeatable-page-master-reference> makes the specified page masters repeat up to the end of the chain.

5

Note that master-reference attribute of a <fo:page-sequence> can refer to either a <fo:page-sequence-master> or a <fo:simple-page-master>. In the latter, all pages generated by this <fo:page-sequence> will use the same page master.

67

Spaces are not inheritable: you cannot specify them on a surrounding block. There's no alternative to specifying them explicitly on every block involved.

You can also specify different page masters for odd and even pages, blank pages, first/last pages, etc. This is achieved by using a more complex sequence specifier — <fo:repeatable-page-master-alternatives>. It contains one or more <fo:conditional-page-master-reference> elements; each of these elements specifies a name of a page master and a set of conditions that should be satisfied for this page master to apply. When generating a page chain, the alternatives inside <fo:conditional-page-master-reference> are looked from left to right, and the first one for which all the conditions hold will be chosen.

In the example below, the first page will have a thin silver border around it, and all other pages will have a border along the inside edge of the body area (left for even pages, right for odd ones).

  <fo:layout-master-set>
    <fo:simple-page-master master-name="first-page">
      <fo:region-body margin="1in" border="thin solid silver"
                                   padding="6pt"/>
    </fo:simple-page-master>
    <fo:simple-page-master master-name="odd-page">
      <fo:region-body margin="1in" border-right="medium gray ridge"
                                   padding-right="6pt"/>
    </fo:simple-page-master>
    <fo:simple-page-master master-name="even-page">
      <fo:region-body margin="1in" border-left="medium gray ridge"
                                   padding-left="6pt"/>
    </fo:simple-page-master>
    <fo:page-sequence-master master-name="my-sequence">
      <fo:repeatable-page-master-alternatives>
        <fo:conditional-page-master-reference page-position="first"
                                              master-reference="first-page"/>
        <fo:conditional-page-master-reference odd-or-even="odd"
                                              master-reference="odd-page"/>
        <fo:conditional-page-master-reference odd-or-even="even"
                                              master-reference="even-page"/>
      </fo:repeatable-page-master-alternatives>
    </fo:page-sequence-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="my-sequence">
    …
    …
    …
    

Areas, Flows, Static Contents

So far, I only placed the contents into the body region of the page master. There are other regions on the page, used to display static elements of page layout — headers, footers, and sidebars. Inside page master, there may be up to five region specifications:

<fo:region-body>

the central part of the page; required

<fo:region-before>

header region

<fo:region-after>

footer region

<fo:region-start>

left sidebar region

<fo:region-end>

right sidebar region

The dimensions of the regions are calculated by the following algorithm:

  1. The page size is controlled by page-height and page-width properties of the <fo:simple-page-master>. There also exists a size shorthand property to set the page size. Worth noting are "portrait" and "landscape" values to set the default page size with different orientation.

  2. The size of region-body is determined by margins around it (calculated from page bounding rectangle).

  3. All other regions stick to the correspondent edge on the page. Their width/height is given by the extent property. Note that side regions does not influence the position of the region-body; so, the correspondent margin of the region-body must be wide enough for the side regions to fit — not less than the extent of the correspondent side region.

  4. To control the allocation of page corners to either sidebars or headers/footers, a special precedence attribute is used on side regions: if set to "true", its bearer captures the corner. In case of equal precedences, headers/footers win.

All regions may have borders, padding and background. However, the XSL 1.0 Recommendation is contradictory with respect to borders and padding on all region areas but <fo:region-body>: the respective properties are listed, but there is a notice in the text that requires borders and padding to be 0. XEP implements borders and padding on all regions, but you are warned.

Regions are named using a special region-name property. This property has a different default value for each of the regions:

  • "xsl-region-body" for <fo:region-body>,

  • "xsl-region-before" for <fo:region-before>,

  • "xsl-region-after" for <fo:region-after>,

  • "xsl-region-start" for <fo:region-start>,

  • "xsl-region-end" for <fo:region-end>.

To put contents into side regions, a special formatting object — <fo:static-content> — is placed inside <fo:page-sequence>. It is bound to a specific region by the flow-name property that should match the region-name of a region in a page-master. The contents of a <fo:static-content> is formatted in the respective region on every page produced by this page-master.

Let us now look at the examples. The simplest example just adds a header to “Hello, world!”:

  <fo:layout-master-set>
    <fo:simple-page-master master-name="my-page">
      <fo:region-body margin="1.5in 1in"1/>
      <fo:region-before extent="1.5in"
                        padding="6pt 1in"
                        border-bottom="0.5pt silver solid"
                        display-align="after"2/>
    </fo:simple-page-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="my-page">
    <fo:static-content flow-name="xsl-region-before"3
                       font="italic 10pt Times">
       <fo:block>"Hello, world!" Example</fo:block>
    </fo:static-content>
    <fo:flow flow-name="xsl-region-body">
       <fo:block>Hello, world!</fo:block>
    </fo:flow>
  </fo:page-sequence>
      
1

Margins can be set by multiple values inside the margin shorthand: assignment of values to sides is the same as for padding.

2

display-align specifies the alignment of the contents inside the area. It is a common technique to set it to "before" for headers.

3

The default name for the header region is used.

Another example uses sidebars. It draws a right sidebar on odd pages, and a left sidebar on even pages:

  <fo:layout-master-set>
    <fo:simple-page-master master-name="even-page">
      <fo:region-body margin="1in 1.5in"
                      column-count="2"1 column-gap="0.5in"/>
      <fo:region-start extent="1.5in"
                       region-name="my-left-sidebar"
                       reference-orientation="90"2
                       padding="6pt 1in"
                       border-right="0.5pt silver solid"3
                       display-align="after"/>
    </fo:simple-page-master>
    <fo:simple-page-master master-name="odd-page">
      <fo:region-body margin="1in 1.5in"
                      column-count="3"4 column-gap="0.5in"/>
      <fo:region-end   extent="1.5in"
                       region-name="my-right-sidebar"
                       reference-orientation="-90"
                       padding="6pt 1in"
                       border-left="0.5pt silver solid"
                       display-align="after"/>
    </fo:simple-page-master>
    <fo:page-sequence-master master-name="my-sequence">
      <fo:repeatable-page-master-alternatives>
        <fo:conditional-page-master-reference odd-or-even="odd"
                                            master-reference="odd-page"/>
        <fo:conditional-page-master-reference odd-or-even="even"
                                            master-reference="even-page"/>
      </fo:repeatable-page-master-alternatives>
    </fo:page-sequence-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="my-sequence">
    <fo:static-content flow-name="my-left-sidebar"
                          font="italic 10pt Times">
       <fo:block text-align="end">
         Left sidebar on an even page
       </fo:block>
    </fo:static-content>
    <fo:static-content flow-name="my-right-sidebar"
                          font="italic 10pt Times">
       <fo:block text-align="start">
         Right sidebar on an odd page
       </fo:block>
    </fo:static-content>
    …
    …
    …
      
14

Body region may have multiple columns; other regions may not. The last attribute specifies the gap between columns.

Note

Number of columns may differ across pages within a single flow. In this example, all odd pages will have three columns while all even pages will have two.

2

reference-orientation attribute specifies rotation of coordinate axes for the region; its value is an angle of rotation counterclockwise (in degrees; must be multiple of 90; negative values rotate clockwise).

3

Note that sides of the region are referenced with respect to the original (not rotated) orientation!

More Complex Structures

Lists

Lists in XSL FO (XSLFO) are much more than just a bulleted sequence of paragraphs: it is a general-purpose mechanism to align two blocks adjacent to each other. It may be used to format ordinary lists, footnotes, image lists, and even to produce some table-like layout patterns.

A list is created by a <fo:list-block> object. Inside it, there are one or more <fo:list-item> elements. Each list item contains one <fo:list-item-label> followed by one <fo:list-item-body>. These two elements contain blocks that are aligned vertically and placed side-by-side.

Let's start with an ordinary bulleted list:

<fo:list-block provisional-distance-between-starts="18pt"1
               provisional-label-separation="3pt"2>
  <fo:list-item>
    <fo:list-item-label end-indent="label-end()"3>
      <fo:block>&#x2022;4</fo:block>
    </fo:list-item-label>
    <fo:list-item-body start-indent="body-start()"5>
       <fo:block>First item</fo:block>
    </fo:list-item-body>
  </fo:list-item>
  <fo:list-item>
    <fo:list-item-label end-indent="label-end()">
      <fo:block>&#x2022;</fo:block>
    </fo:list-item-label>
    <fo:list-item-body start-indent="body-start()">
       <fo:block>Second item</fo:block>
    </fo:list-item-body>
  </fo:list-item>
</fo:list-block>
      
1

This property specifies how far the left side of the label is distant from the left side of the body.

2

This property specifies the separation between the right side of the label and the left edge of the body.

3

end-indent attribute specifies the offset of the right edge of <fo:list-item-label> from the right edge of the reference area (i.e. page). A special label-end() function sets it to the value calculated from provisional-distance-between-starts and provisional-label-separation values. However, this is not a default value: you have to specify end-indent="label-end()" on each <fo:list-item-label> in the list. Alternatively, you can use an explicit value of end-indent.

4

This is a Unicode for a round bullet.

5

start-indent attribute specifies the left offset of the <fo:list-item-body> from the left. A special body-start() function sets it to the value calculated from provisional-distance-between-starts. Like for the <fo:list-item-label>, this is not a default value; don't forget to specify it on each <fo:list-item-body>.

Another example — using <fo:list-block> to align text in a header:

<fo:static-content flow-name="xsl-region-before">
  <fo:list-block border-bottom="1pt gray ridge"1 padding-after="6pt">
    <fo:list-item>
      <fo:list-item-label end-indent="3in">2
      <fo:block text-align="start">RenderX XSL FO (XSLFO) Manual</fo:block>
      </fo:list-item-label>
      <fo:list-item-body start-indent="3in">3
        <fo:block text-align="end">List Example</fo:block>
      </fo:list-item-body>
    </fo:list-item>
  </fo:list-block>
</fo:static-content>
      
1

<fo:list-block> and <fo:list-item> are block-level elements, and can get margins (including space-before/space-after and indents), keep & break constraints, borders, padding, and background. Please note that <fo:list-item-body> and <fo:list-item-label> aren't considered blocks in the spec, and cannot have borders or background.

23

Instead of using label-end()/body-start() technique, you may also specify indents explicitly like in this example. To use this method, you should know the width of the parent reference area to avoid overlapping of item labels to item bodies.

Tables

Tables in XSL FO (XSLFO) resemble HTML ones: they are made of cells grouped into rows; rows are further grouped into row groups — table header, table footer, and table bodies (one or more). There are also column descriptors. Table model is rather evolved: please refer to the spec for further details. Here, I limit myself to a couple of core examples.

A basic 2x2 table:

<fo:table border="0.5pt solid black" text-align="center">
  <fo:table-body>
    <fo:table-row>
      <fo:table-cell padding="6pt" border="0.5pt solid black">1
        <fo:block> upper left </fo:block>
      </fo:table-cell>
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> upper right </fo:block>
      </fo:table-cell>
    </fo:table-row>
    <fo:table-row>
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> lower left </fo:block>
      </fo:table-cell>
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> lower right </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </fo:table-body>
</fo:table>
      
1

Table cells can have borders, padding, and background; they cannot have margins. The table itself may have all attributes a normal block may have, except for padding.

A more complicated example includes explicit column width assignment and cells spanning multiple grid units:

<fo:table border="0.5pt solid black"
          text-align="center"
          border-spacing="3pt"1>
  <fo:table-column column-width="1in"/>
  <fo:table-column column-width="0.5in" number-columns-repeated="2"2/>
  <fo:table-header>3
    <fo:table-row>
      <fo:table-cell padding="6pt"
                     border="1pt solid blue"
                     background-color="silver"
                     number-columns-spanned="3"4>
        <fo:block text-align="center" font-weight="bold">
          Header
        </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </fo:table-header>
  <fo:table-body>
    <fo:table-row>
      <fo:table-cell padding="6pt"
                     border="1pt solid blue"
                     background-color="silver"
                     number-rows-spanned="2"5>
        <fo:block text-align="end" font-weight="bold">
          Items:
        </fo:block>
      </fo:table-cell>
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> 1 : 1 </fo:block>
      </fo:table-cell>
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> 1 : 2 </fo:block>
      </fo:table-cell>
    </fo:table-row>
    <fo:table-row>6
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> 2 : 1 </fo:block>
      </fo:table-cell>
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> 2 : 2 </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </fo:table-body>
</fo:table>
      
1

border-spacing corresponds to CELLSPACING attribute of the HTML table model.

2

This is a column specifier that sets the width for the second and the third column. Instead of repeating the same specifier for two consecutive columns, I have used an number-columns-repeated attribute: it just clones the description the specified number of times.

3

Table header is a row group like <fo:table-body>. It is repeated at the top of page after page breaks unless you specify table-omit-header-at-break="true" on the embracing <fo:table>.

4

This cell will span three columns horizontally.

5

This cell will span two rows vertically.

6

This row contains only two cells; the first grid unit is already occupied by the cell spanning from the previous row.

Graphics

There is a special inline element for including graphics into XSL FO (XSLFO) — <fo:external-graphic>. The source image is specified by the src attribute whose value is a URI. XEP handles HTTP, FTP, data and filesystem resource locators in URIs. An unqualified URI is treated as a path to a file in the local file system; if the path is relative, it is calculated from the location of the source XSL FO (XSLFO) document.

Here's an example:

<fo:block>
  This text includes a picture:
  <fo:external-graphic src="url('smile.gif')"1
                       content-height="1em"2 content-width="1em"3/>
</fo:block>
      
1

Note the url('…') function-like wrapper around the file name: this is required by the XSL 1.0 Recommendation. (XEP recognizes unwrapped URLs, too).

23

In this example, the height and the width of the image are expressed in units relative to the nominal font size. This is a convenient technique to scale small inlined images proportionally to the text height.

If you need a block-level graphic, you should wrap the element in a <fo:block>, like in the example below:

<fo:block font-weight="bold"
          keep-with-next.within-column="always">1
  Figure 1: A Smiling Face
</fo:block>
<fo:block>
    <fo:external-graphic src="url('smile.gif')"
                         content-height="200%" content-width="200%"/>2
</fo:block>
      
1

This property “glues” the figure caption to the figure itself.

2

content-width and content-height expressed as percents denote scaling the image from its original