Formatting Objects Basics
- To understand how XSL-FO works.
- To do a simple XSL-FO transform.
- To add flowing and static content to an XSL-FO document.
The purpose of XSL-FO
The purpose of XSL-FO is to provide a mechanism for formatting XML data for print, screen and other output media. XSL-FO, also known simply as XSL, is a specification of the World Wide Web Consortium and is closely related to XSLT. However, whereas XSLT is most often used for transforming XML into HTML or other XML structures, XSL-FO is most often used for formatting XML for print.
How XSL-FO Works
Transforming XML for print is accomplished by transforming an XML document to a Formatting Objects (FO) document, which itself is XML-based, via XSLT. The formatting objects processor is able to read the FO document and transform it for different types of print output. The most common and best supported print output is currently Adobe PDF.
In a moment, we'll take a look at our first FO document, but first let's look at how FO sees a page.
As you can see, the page is divided into regions. The main region is the region-body. The regions above and below the body are called region-before and region-after and the regions to the right and left of the body are called region-start and region-end. We will examine page layout more closely in the Page Layout lesson.
XSL-FO Document Parts
An XSL-FO document is divided into two main parts:
- One layout master set (layout-master-set), which specifies one or more page master templates (simple-page-master) to be used in the document.
- One or more page sequences, which contain the content of the document.
The following code sample shows how the page is broken up.
Code Sample: FoBasics/Demos/PageStructure.fo
<?xml version="1.0" encoding="utf-8"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <!-- Define page templates using simple-page-master formatting objects inside of a layout master set. These templates are used to specify the basic rules for content layout; for example, the page margin size. --> <!-- Define page sequences, which use the templates defined above. These page sequences contain the actual content to be output. --> </fo:root>
An XSL-FO Example
Let's now look at a complete, though simple, FO document.
Code Sample: FoBasics/Demos/HelloWorld.fo
<?xml version="1.0" encoding="utf-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="hello"
page-height="11in" page-width="8.5in" margin-top="1in"
margin-bottom="1in" margin-left="1in" margin-right="1in">
<fo:region-body margin-top="1in" margin-bottom=".5in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="hello">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="18pt" text-align="center" font-weight="bold">
Hello World!
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
The output is shown below.
![]()
All this simply to output "Hello World!"??? Yup. With FO, you need to do a little work to get things started. Let's break this code down.
The Root Element: root
The first thing to note is that this is an XML document with a root element of root with the namespace http://www.w3.org/1999/XSL/Format.
layout-master-set and simple-page-master
The layout-master-set formatting object (FO) holds simple-page-master FOs, which define page templates.
<fo:layout-master-set> <fo:simple-page-master master-name="hello" page-height="11in" page-width="8.5in" margin-top="1in" margin-bottom="1in" margin-left="1in" margin-right="1in"> <fo:region-body margin-top="1in" margin-bottom=".5in"/> </fo:simple-page-master> </fo:layout-master-set>
In this case, there is only one template and it is named "hello". The page height, width and margins are all defined in the simple-page-master FO.
Regions
The simple-page-master FO contains region settings in the form of the following child FOs.
- region-body
- region-start
- region-end
- region-before
- region-after
The locations of these regions are shown on the diagram under How XSL-FO Works. Our simple "Hello-World" document only uses the region-body.
page-sequence
The layout-master-set FO is followed by one or more page-sequence FOs, which must reference one of the simple-page-master templates by name. The page-sequence FOs contain the contents of the page or pages.
<fo:page-sequence master-reference="hello"> <!--Page contents--> </fo:page-sequence>
Notice that the value of the master-reference attribute matches the master-name defined in the simple-page-master FO.
flow and static-content
The contents of the page inside the page-sequence FO are either static, meaning they appear the same on each page or flowing, meaning they flow from one page to the next. Static content is contained in static-content FOs and flowing content is contained in flow FOs.
<fo:page-sequence master-reference="hello"> <fo:flow flow-name="xsl-region-body"> <!--flowing content--> </fo:flow> </fo:page-sequence>
This example only has a flow FO. In most cases, the region-body has flowing content and the other regions have static content.
block
Paragraphs, lists and other elements that generally are vertically separated with whitespace are called blocks. The block FO is used for separating and formatting generic blocks, such as paragraphs. In our "Hello-World" example, there is only one block, which contains the text "Hello World!" and sets its font size, font weight and alignment via attributes.
You may notice that the formatting properties of the block FO are Cascading Style Sheets properties. Formatting Objects use CSS for display properties, so, if you use CSS in web design, youâll find that most of your knowledge is transferrable to XSL-FO.
<fo:page-sequence master-reference="hello">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="18pt" text-align="center"
font-weight="bold">
Hello World!
</fo:block>
</fo:flow>
</fo:page-sequence>
Note that blocks can contain nested blocks, which can contain nested blocks, and so on.
Exercise: Using XSLT to Create FO
In this exercise, you will generate the FO document we have been working with in this lesson from an XML document using XSLT.
- Open FoBasics/Exercises/HelloWorld.xml. You will see that it is a very simple XML document.
- Open FoBasics/Exercises/HelloWorld.xsl for editing.
- Finish this XSLT document so that it transforms FoBasics/Exercises/HelloWorld.xml to output the equivalent of FoBasics/Demos/HelloWorld.fo shown earlier.
- To test your solution, transform FoBasics/Exercises/HelloWorld.xml against FoBasics/Exercises/HelloWorld.xsl and then run the result through an FO engine.
Static Content
Static content is added to page sequences with the static-content FO. Generally, static content is used in regions other than the body region. The example below adds a header and a footer to our "Hello-World" document.
Code Sample: FoBasics/Demos/HelloWorld-Static.fo
<?xml version="1.0" encoding="utf-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="hello" page-height="11in"
page-width="8.5in" margin-top="1in" margin-bottom="1in"
margin-left="1in" margin-right="1in">
<fo:region-body margin-top="1in" margin-bottom=".5in"/>
<fo:region-before extent=".5in" background-color="silver"/>
<fo:region-after extent=".5in" background-color="silver"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="hello">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-size="24pt">Hello World!</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
<fo:block font-size="24pt" text-align="right">
Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/>
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="36pt" text-align="center" font-weight="bold">
Hello World!
</fo:block>
<fo:block id="last-page"/>
</fo:flow>
</fo:page-sequence>
</fo:root>
The above code results in the following output.
![]()
Let's examine the new FOs we have added.
region-before and region-after
The region-before and region-after FOs have been added to the simple-page-master FO.
<fo:simple-page-master master-name="hello" page-height="11in" page-width="8.5in" margin-top="1in" margin-bottom="1in" margin-left="1in" margin-right="1in"> <fo:region-body margin-top="1in" margin-bottom=".5in"/> <fo:region-before extent=".5in" background-color="silver"/> <fo:region-after extent=".5in" background-color="silver"/> </fo:simple-page-master>
These FOs effectively create header and footer regions. The extent attribute specifies the header and footer height. In both cases, it is set to .5 inches. The background-color attribute specifies the background color.
static-content
<fo:static-content flow-name="xsl-region-before"> <fo:block font-size="12pt">Hello World!</fo:block> </fo:static-content><fo:static-content flow-name="xsl-region-after"> <fo:block font-size="12pt" text-align="right"> Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/> </fo:block> </fo:static-content>
The static-content FO is used to add content that will repeat for every page in the current page sequence. The flow-name attribute specifies the region in which this content will appear.
In this case, the first static-content causes the text "Hello World!" to be added to the header of every page in this sequence. The second static-content causes a right-aligned page number to be added to the footer of every page. Let's look at that one a little more closely.
<fo:static-content flow-name="xsl-region-after"> <fo:block font-size="12pt" text-align="right"> Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/> </fo:block> </fo:static-content>
The page-number FO is pretty straightforward. It simply inserts the current page number. The page-number-citation FO is used to reference the page number of an FO on another page by its unique id, in this case "last-page". If you look further down in the document, you'll see <fo:block id="last-page"/> at the bottom of the region-body flow. The purpose of placing this FO there is to mark the last page of the document.
Exercise: Creating a Multi-page Document
In this exercise, you will use what we have covered so far to create a multi-page FO document from an XML document.
- Open FoBasics/Exercises/WinnieThePooh.xml and examine its structure.
- Open FoBasics/Exercises/WinnieThePooh.xsl for editing.
- Modify the document so that it produces a document like FoBasics/Exercises/WinnieThePooh.pdf.
- To test your solution, transform FoBasics/Exercises/WinnieThePooh.xml against FoBasics/Exercises/WinnieThePooh.xsl.
Code Sample: FoBasics/Exercises/WinnieThePooh.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/Document">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="all"
page-height="11in" page-width="8.5in" margin-top="1in"
margin-bottom="1in" margin-left="1in" margin-right="1in">
<fo:region-body margin-top="1in" margin-bottom=".5in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="all">
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
Formatting Objects Basics Conclusion
In this lesson of the XML tutorial, we have covered the basics of XSL-FO. We will now look at some more advanced features.