Book HomeXML in a Nutshell

13.3. Laying Out the Master Pages

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 master page also has a unique name given by a master-name attribute. For example, this element describes a master page named first that represents an 8.5 by 11 inch page with one 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 13-2. However, if the text were Hebrew, then the start region would be on the righthand 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 lefthand side, and the after on the righthand side. Other combinations are possible.

Figure 13-2

Figure 13-2. The five regions in a left-to-right, top-to-bottom writing system

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 half-inch margins on each side, representing the unprintable area on many common printers. The start and end regions are half an inch wide. The before and after regions are one 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>

13.3.1. Flowing Content into the Pages

Next we add a 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 into which region of the page its content will flow. 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 master page 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 parsed character data. 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 &amp; 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 13-1 through judicious use of the default templates:

<xsl:template match="dish|ingredient|directions|story">
  <fo:block><xsl:apply-templates/></fo:block>
</xsl:template>

13.3.2. Generating the Finished Document

We now have the minimum set of pieces needed to put together a full XSL-FO document. Example 13-2 is an XSLT stylesheet that transforms documents like Example 13-1 into XSL formatting objects documents.

Example 13-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 13-3 shows the complete XSL-FO document produced by running the cornbread recipe through an XSLT engine such as Xalan or SAXON 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 13-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 &amp; 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 onscreen 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 that runs on most platforms. At the time of this writing, it has some significant holes in its coverage but is making rapid progress. After you install FOP in the class path, this command line transforms the file cornbread.fo into a PDF document:

% java org.apache.fop.apps.Fop -fo cornbread.fo -pdf cornbread.pdf

FOP can also transform XSL-FO documents into plain text, raw PostScript, a PCL file, or SVG slides, or display it on the screen using the Java 2D API. This command produces the window shown in Figure 13-3.

Figure 13-3

Figure 13-3. The XSL-FO recipe document in FOP's AWT preview

There are several other programs for working with XSL-FO documents:



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.