Table of ContentsThis 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. Let us create the shortest XSL FO (XSLFO) document. <?xml version="1.0" encoding="iso-8859-1"?> 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 :-). 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:
Note a new formatting object —
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 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 [<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: 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"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
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:
By specifying a negative value for
<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
To complete this chapter, let's introduce attributes to position
blocks vertically with respect to each other: 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.
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"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):
You can specify each property for each border separately by writing several attributes
of the form <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 <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 <fo:block text-align="center"
border-top="dashed 1pt #C00000"
Finally, a single <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 —
<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 <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 <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
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 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 <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
The NoteUnder 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 <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,
<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
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"
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 —
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">
…
…
…
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:
The dimensions of the regions are calculated by the following algorithm:
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
Regions are named using a special
To put contents into side regions, a special formatting object —
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"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"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 Let's start with an ordinary bulleted list: <fo:list-block provisional-distance-between-starts="18pt"
Another example — using <fo:static-content flow-name="xsl-region-before"> <fo:list-block border-bottom="1pt gray ridge" 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">
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"
There is a special inline element for including graphics
into XSL FO (XSLFO) — Here's an example: <fo:block>
This text includes a picture:
<fo:external-graphic src="url('smile.gif')"
If you need a block-level graphic, you should wrap the element in
a <fo:block font-weight="bold"
keep-with-next.within-column="always">
It is also possible to create an image directly in the XSL FO (XSLFO), using the embedded SVG feature: <fo:block> Here is the image of a typical roadsign: <fo:instream-foreign-object content-height="1em">
Let us consider a simple example: <fo:block-container width="250pt" height="20pt"
border="1pt solid black"
reference-orientation="0">
Besides containers, <?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 border="0.25pt solid silver"
margin="0.5in"
padding="12pt"
reference-orientation="-90"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="my-page">
<fo:flow flow-name="xsl-region-body">
<fo:block>
Text and images on the page
<fo:external-graphic src="url('smile.gif')"
content-height="100%"
content-width="100%"/>
</fo:block>
<fo:block-container width="250pt" height="20pt"
border="1pt solid black"
reference-orientation="180">
XSL FO (XSLFO) has powerful means to deal with non-Western writing systems.
Lines can be made horizontal or vertical; character can be ordered
from any side; line stacking order on the page can also be varied.
To define ordering of charactes within lines and stacking direction
of lines into paragraphs, we use
NoteAs of version 4.0, XEP supports only horizontal writing modes: "lr-tb" and "rl-tb".
However, internationalization issues are too complex to be described by a single property. In right-to-left writing systems (Arabic and Hebrew), it is not uncommon to include fragments of text written in Latin alphabet; such text progresses left-to-right. The mechanism that permits mixing writing directions within the same fragment of text is called bidirectionality, or bidi for short. The Unicode standard defines rules to calculate ordering of characters in bidirectional text; the respective part of the Unicode, Annex #9: The Bidirectional Algorithm, is adopted by XSL FO (XSLFO).
However, in certain cases the Unicode bidi algoritm
is not enough to determine character ordering. For this purpose,
XSL defines a special element
The following example shows two block containers with different writing modes.
Both contain a mixture of English (left-to-right) and Hebrew (right-to-left)
text. The first container has <fo:block-container writing-mode="lr-tb">
In the following small code snippet, There are two kinds of links in XSL FO (XSLFO):
Both are achieved using the same formatting object —
<fo:basic-link internal-destination="smiley"
text-decoration="underline">Click here</fo:basic-link>
An external link must have an URI specified in the
<fo:basic-link external-destination="url('http://www.RenderX.com/')"
text-decoration="underline"
color="blue">RenderX Home</fo:basic-link>
Unlike HTML, no default formatting is applied to links in XSL FO (XSLFO);
you should provide character-level properties on
Note the
In XEP, URLs starting with explicit A leader is an object used in XSL FO (XSLFO) to create horizontal rules, lengthy white spaces, dot-filled tabs etc. Here is an example of a horizontal inline rule used to form a nice separator: <fo:block text-align="center">
<fo:leader leader-length="2in"
leader-pattern="rule"
alignment-baseline="middle"See also an example of leader usage in a section about page numbers.
To insert a footnote at the bottom of the page,
you should use a
Lists are often used to format footnote bodies. The example below shows a typical case: <fo:block> This text contains a footnote<fo:footnote>
Normally, footnotes are divided from the rest of the text by a
separator. Separators are created in a special
region named <fo:page-sequence>
<fo:static-content flow-name="xsl-footnote-separator">
<fo:block>
<fo:leader leader-pattern="rule"
leader-length="100%"
rule-style="solid"
rule-thickness="0.5pt"/>
</fo:block>
</fo:static-content>
…
…
…
Floats are similar to footnotes: they define a block that drifts to the top/left/right side of the page while the text flows around it. A typical use for floats is to put a picture, a table, etc. aside so that it does not disrupt the flow of the text. Here is an example of a top-float: <fo:block>
This text includes a floating picture.
<fo:float float="before">
<fo:block text-align="center"
border="1pt solid gray"
font="bold italic 9pt Helvetica">
<fo:block>
<fo:external-graphic src="url('smile.gif')"/>
</fo:block>
<fo:block>
Fig. 1: A Smiling Face
</fo:block>
</fo:block>
</fo:float>
This text follows the float anchor.
</fo:block>
Note
Due to implementation restrictions of XEP 4.0, top floats ( The next example shows how to create a dropcap using a side float: <fo:block intrusion-displace="line"
To insert the current page number, use
<fo:static-content flow-name="xsl-region-before">
<fo:block text-align="end">Page <fo:page-number/></fo:block>
</fo:static-content>
To insert a reference to a page where a certain element
resides, that element must have a unique <fo:external-graphic id="smiley" src="url('smile.gif')"/>
…
…
…
As shown on the "Smiling Face" diagram
(see page <fo:page-number-citation ref-id="smiley"/>), …
Page number citation can be used to obtain the total number of pages in the document: just place an empty block at the end of the text and refer to its page number, like in the example below: <fo:static-content flow-name="xsl-region-before">
<fo:block text-align="end">
Page <fo:page-number/>
of <fo:page-number-citation ref-id="terminator"/>
</fo:block>
</fo:static-content>
<fo:flow>
…
…
…
<fo:block id="terminator"/>
</fo:flow>
Another important use of page number citations is to create tables of contents and indices. The example below shows a typical TOC entry in XEP: <fo:block text-align-last="justify" Markers are used to change the contents of a side region according to the contents of the body region. A typical task performed with markers is to create running headers — to put the division title at the header of the page. Actual use of markers involves two formatting objects:
The contents of a
Here is a basic example of using markers: <fo:static-content flow-name="xsl-region-before">
<fo:block text-align="center">
<fo:retrieve-marker retrieve-class-name="division"/>
</fo:block>
</fo:static-content>
…
…
…
<fo:block>
PDF documents can have a number of information fields associated to them; these are displayed in Acrobat Reader when you choose from the menu. Standard fields are ‘Author’, ‘Title’, ‘Creator’, ‘Subject’, and ‘Keywords’. XSL FO (XSLFO) provides no means to set these values. XEP 4.0 provides a mechanism to set these fields from within the XSL FO (XSLFO) document, using additional formatting objects. To trace a clear distinction between objects comprised in the XSL 1.0 Recommendation and those added by RenderX, the namespace mechanism is used: any and all additional elements or properties will have a different namespace prefix, associated to another namespace:
We need two extension elements to express document information fields:
Let's see a code example containing this extension: <?xml version="1.0" encoding="iso-8859-1"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:rx="http://www.renderx.com/XSL/Extensions"
PDF documents can have an associated outline of their structure, commonly referred to as bookmarks. Being specific to a particular output format, bookmarks aren't covered by the XSL 1.0 Recommendation. XEP 4.0 implements three extension elements that enable bookmarks in PDF output:
Shown below is a typical markup of bookmarks for a document consisting of two chapters, each of them having two subchapters: …
…
…
</fo:layout-master-set>
<rx:outline>
<rx:bookmark internal-destination="chap_1">Building page number lists for back-of-the-book indexes is a common task. It is relatively easy to collect a list of references to locations of index terms in the text; but then, to turn it into a real index entry, one should exclude repeated page numbers and merge adjacent numbers into ranges. Neither of these two operations can be done by pure XSLT/XSL FO means. In this situation, introducing an extension looks inevitable. The task of building an index can be split in two fairly independent subtasks:
For the first task, XEP introduces a special extension attribute:
If the element bearing There is also a mechanism to specify ranges explicitly. Two extension elements serve for the purpose:
These two elements always form a pair:
The actual index entry is created by another extension element,
Note
In XEP 4.0, A basic entry in an index will look like this: <fo:inline rx:key="key.elephant">Elephants</fo:inline> live in Africa. …
<fo:inline rx:key="key.elephant">African elephants</fo:inline> have big ears …
…
<fo:block text-align="center" font="bold 16pt Futura">INDEX</fo:block>
<fo:block>
Elephants <rx:page-index>
<rx:index-item ref-key="key.elephant"/>
</rx:page-index>
</fo:block>
There are more attributes of
Besides that, <fo:inline rx:key="key.elephant">Elephants</fo:inline> live
in Africa. …
<fo:inline rx:key="key.elephant.primary">Elephant</fo:inline> is
a quadruped mammal. …
<fo:inline rx:key="key.elephant">African elephants</fo:inline> have big
ears …
…
<fo:block text-align="center" font="bold 16pt Futura">INDEX</fo:block>
<fo:block>
Elephants <rx:page-index>
<rx:index-item ref-key="key.elephant.primary"
font-weight="bold"
link-back="true"/>
The syntax for this extension is straightforward:
Here is a short example. A text is located on a two-column page; it starts with a title that spans all columns, and then continues with an abstract formatted into three columns. After the abstract, the text turns back to its primordial two-column state. <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:rx="http://www.renderx.com/XSL/Extensions">
<fo:layout-master-set>
<fo:simple-page-master>
<fo:region-body margin="1in" column-count="2"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="xsl-region-body">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="16pt" span="all">TITLE</fo:block>
<rx:flow-section column-count="3" column-gap="18pt">
<fo:block font-size="10pt">
Abstract occupies three columns …
</fo:block>
</rx:flow-section>
<fo:block>
Normal text continues in two columns as specified in the page master …
Congratulations! If you have read this far and understood how the above examples work, you are prepared to write your own XSL FO (XSLFO) stylesheets. You can find more examples of XSL FO (XSLFO) usage in the RenderX Test Suite, available at http://www.renderx.com/featurestest.html. There, you can find several dozens of test documents that illustrate and test virtually every aspect of XEP's functionality. Sample stylesheets for XSL FO (XSLFO) are also available from RenderX site. |
|||||
RenderX®, © 2005-2009 • Contact Us • Privacy Policy • Terms of Service • Site design by Dmitry Kirsanov Studio |
|||||