XSL-FO 1.0 only defines one kind of master page, the fo:simple-page-master
. This represents a
standard rectangular page with margins on all four sides. This page
master also has a unique name given by a master-name
attribute. For example, this
element describes a page master named first
that represents an 8.5 11-inch page
with 1-inch margins on all four sides:
<fo:simple-page-master margin-right="1in" margin-left="1in" margin-bottom="1in" margin-top="1in" page-width="8.5in" page-height="11in" master-name="first"> <!-- Separate parts of the page go here --> </fo:simple-page-master>
The part of the page inside the margins is divided into five regions: the start region, the end region, the before region, the after region, and the body region. Where these fall on a page depends on the writing direction. In left-to-right, top-to-bottom languages like English, start is on the lefthand side, end is on the righthand side, before is on top, and after is on bottom, as diagramed in Figure 14-2. However, if the text were Hebrew, then the start region would be on the right-hand side of the page, and the end region would be on the lefthand side of the page. If the text were traditional Chinese, then the start would be on top, the end on bottom, the before on the righthand side, and the after on the lefthand side. Other combinations are possible.
These regions are represented by fo:region-start
, fo:region-end
, fo:region-before
, fo:region-after
, and fo:region-body
child elements of the
fo:simple-page-master
element. You
can place different content into each of the five regions. For
instance, the after region often contains a page number, and the
before region may contain the title of the book or chapter.
The body region and the corresponding fo:region-body
element are required. The
other four are optional. By default, the body region takes up the
entire page, and the other four regions have zero area. To specify
this simplest page, you add an empty fo:region-body
child element to the fo:simple-page-master
element like
this:
<fo:simple-page-master margin-right="1in" margin-left="1in"
margin-bottom="1in" margin-top="1in"
page-width="8.5in" page-height="11in"
master-name="first">
<fo:region-body/>
</fo:simple-page-master>
However, you can add extent
attributes to the four nonbody regions to specify the
height of the before and after regions and the width of the start and
end regions. Then the region body should have margin properties that
are at least as large as the extent of each region to push it out of
the way of each nonbody region. Otherwise, content placed in the body
will be drawn on top of content placed in the other four regions. For
example, this fo:simple-page-master
element has 0.5-inch margins on each side, representing the
unprintable area on many common printers. The start and end regions
are 0.5 inches wide. The before and after regions are 1 inch wide. The
body has margins that match the region sizes.
<fo:simple-page-master margin-right="0.5in" margin-left="0.5in" margin-bottom="0.5in" margin-top="0.5in" page-width="8.5in" page-height="11in" master-name="first"> <fo:region-before extent="0.5in"/> <fo:region-after extent="0.5in"/> <fo:region-start extent="0.5in"/> <fo:region-end extent="0.5in"/> <fo:region-body margin-top="1.0in" margin-bottom="1.0in" margin-left="0.5in" margin-right="0.5in"/> </fo:simple-page-master>
Most of the time, the details of the layout-master set are fixed
in the stylesheet. For example, here's the revised XSLT template that
includes a full fo:layout-master-set
:
<xsl:template match="/"> <fo:root> <fo:layout-master-set> <fo:simple-page-master margin-right="1in" margin-left="1in" margin-bottom="1in" margin-top="1in" page-width="8.5in" page-height="11in" master-name="first"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="first"> <!-- data to place on the page --> </fo:page-sequence> </fo:root> </xsl:template>
Next, add an fo:flow
child to the fo:page-sequence
where the actual text of
the transformed document appears. This element has a flow-name
attribute specifying which
region of the page its content will flow into. Possible values
include xsl-region-body
, xsl-region-start
, xsl-region-end
, xsl-region-before
, and xsl-region-after
.
The formatter instantiates a page based on the page master
named by the fo:page-sequence
's
master-reference
attribute, fills
one of its regions with content from the fo:flow
element until the page is full,
then instantiates a second page, fills it with more content from the
fo:flow
, instantiates a third
page, and continues this process until it's used up all the data in
the fo:flow
.
The fo:flow
element must
contain block-level formatting object elements. The most basic
of these is fo:block
. Others
include fo:block-container
,
fo:list-block
, fo:table
, and fo:table-and-caption
. We'll begin with the
most basic, fo:block
. A fo:block
can contain a combination of raw
text and formatting objects, such as fo:external-graphic
, fo:inline
, fo:page-number
, fo:footnote
, and even other fo:block
elements. For the moment, we'll
restrict ourselves to simple text. For example, here's a basic
fo:flow
for the recipe:
<fo:flow flow-name="xsl-region-body"> <fo:block>Southern Corn Bread</fo:block> <fo:block>1 cup flour</fo:block> <fo:block>4 tablespoons Royal Baking Powder</fo:block> <fo:block>1/2 teaspoon salt</fo:block> <fo:block>1 cup corn meal</fo:block> <fo:block>11/2 cups whole milk</fo:block> <fo:block>4 tablespoons melted butter</fo:block> <fo:block>Sift flour, baking powder, sugar & salt together. Add 1 cup corn meal. Beat egg in cup and add beaten egg and 11/2 cups whole milk to make a batter. Stir well. Add melted shortening and beat until light and thoroughly mixed. Pour into greased shallow pan or greased muffin rings. Bake in hot oven at 425° F for 25 minutes! Cut into squares if cooked in shallow pan.</fo:block> <fo:block>After my mother-in-law Marjorie Anderson died, Beth and I found this recipe written on the "extra recipes" page in a local cookbook in her cupboard. This was published by the The Episcopal Churchwomen, Church of Ascension, Mt. Sterling, Kentucky.</fo:block> </fo:flow>
Here's an XSLT template that produces the content of this
fo:flow
element (modulo
insignificant whitespace) from Example 14-1 through judicious
use of the default template rules:
<xsl:template match="dish|ingredient|directions|story"> <fo:block><xsl:apply-templates/></fo:block> </xsl:template>
We now have the minimum set of pieces needed to put together a full XSL-FO document. Example 14-2 is an XSLT stylesheet that transforms documents like Example 14-1 into XSL Formatting Objects documents.
Example 14-2. An XSLT to XSL-FO transform
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:template match="/"> <fo:root> <fo:layout-master-set> <fo:simple-page-master margin-right="1in" margin-left="1in" margin-bottom="1in" margin-top="1in" page-width="8.5in" page-height="11in" master-name="first"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="first"> <fo:flow flow-name="xsl-region-body"> <xsl:apply-templates/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="dish|ingredient|directions|story"> <fo:block><xsl:apply-templates/></fo:block> </xsl:template> </xsl:stylesheet>
Example 14-3 shows the complete XSL-FO document produced by running the cornbread recipe through an XSLT engine, such as Xalan, with this stylesheet. The whitespace is a little off because of the way XSLT treats whitespace in the transform document. However, this won't be significant when the document is rendered.
Example 14-3. An XSL-FO document describing a recipe for cornbread
<?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 margin-right="1in" margin-left="1in" margin-bottom="1in" margin-top="1in" page-width="8.5in" page-height="11in" master-name="first"><fo:region-body/></fo:simple-page-master> </fo:layout-master-set><fo:page-sequence master-reference="first"> <fo:flow flow-name="xsl-region-body"> <fo:block>Southern Corn Bread</fo:block> <fo:block> 1 cup flour </fo:block> <fo:block> 4 tablespoons Royal Baking Powder </fo:block> <fo:block> 1/2 teaspoon salt </fo:block> <fo:block> 1 cup corn meal </fo:block> <fo:block> 11/2 cups whole milk </fo:block> <fo:block> 4 tablespoons melted butter </fo:block> <fo:block> Sift flour, baking powder, sugar & salt together. Add 1 cup corn meal. Beat egg in cup and add beaten egg and 11/2 cups whole milk to make a batter. Stir well. Add melted shortening and beat until light and thoroughly mixed. Pour into greased shallow pan or greased muffin rings. Bake in hot oven at 425 F for 25 minutes. Cut into squares if cooked in shallow pan. </fo:block> <fo:block> After my mother-in-law Marjorie Anderson died, Beth and I found this recipe written on the "extra recipes" page in a local cookbook in her cupboard. This was published by the The Episcopal Churchwomen, Church of Ascension, Mt. Sterling, Kentucky. </fo:block> </fo:flow></fo:page-sequence></fo:root>
The final step in this process is to convert the formatting objects document into some other format that can be viewed on screen or on paper. This requires running a formatting program such as the Apache XML Project's open source FOP (http://xml.apache.org/fop/ ). FOP is a Java program. At the time of this writing, it has some significant holes in its coverage, but it is making progress. It includes shell scripts for DOS and Windows that set up the classpath and launch the Java program. For example, on Windows, this command line transforms the file cornbread.fo into a PDF document:
C:\> fop -fo cornbread.fo -pdf cornbread.pdf
FOP can also transform XSL-FO documents into plain text, raw PostScript, a PCL file, SVG slides, or display it on the screen using the Java 2D API. This command produces the window shown in Figure 14-3.
There are several other programs for working with XSL-FO documents:
RenderX's XEP (http://xep.xattic.com) is a payware Java XSL-FO-to-PDF converter program much like FOP.
Sebastian Rahtz's PassiveTEX (http://www.hcu.ox.ac.uk/TEI/Software/passivetex/ ) is an open source collection of TeX macros for converting XSL-FO documents to TeX. A reasonably modern TeX distribution is required.
The Antenna House XSL Formatter (http://www.antennahouse.com) is a payware Windows program that can print and display XSL-FO documents using the Windows GDI.
IBM's XSL Formatting Objects Composer (http://www.alphaworks.ibm.com/tech/xfc) is a free-as-in-beer Java program that implements a "substantial portion" of XSL Formatting Objects 1.0. It can display XSL-FO documents on the screen or convert them to PDF.