Chapter 13. XSL Formatting Objects (XSL-FO)

CONTENTS

  •  13.1 XSL Formatting Objects
  •  13.2 The Structure of an XSL-FO Document
  •  13.3 Laying Out the Master Pages
  •  13.4 XSL-FO Properties
  •  13.5 Choosing Between CSS and XSL-FO

The last chapter covered CSS; this chapter discusses XSL-FO. In distinct contrast to CSS, XSL-FO is a complete XML application for describing the precise layout of text on a page. It has elements that represent pages, blocks of text on the pages, graphics, horizontal rules, and more. Most of the time, however, you don't write XSL-FO directly. Instead, you write an XSLT stylesheet that transforms your document's native markup into XSL-FO. The application rendering the document reads the XSL-FO and displays it to the user. Since no major browsers currently support direct rendering of XSL-FO documents, there's normally a third step in which another processor transforms the XSL-FO into a third format, such as PDF or TEX.

Once again we demonstrate the features of XSL-FO by applying it to the simple well-formed XML document shown in Example 12-1 in the last chapter and repeated here in Example 13-1 for convenience.

Example 13-1. Marjorie Anderson's recipe for Southern Corn Bread
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <recipe source="Marjorie Anderson">   <dish>Southern Corn Bread</dish>   <ingredients>     <ingredient>       <quantity>1 cup</quantity>       <component>flour</component>     </ingredient>     <ingredient>       <quantity>4 tablespoons</quantity>       <component>Royal Baking Powder</component>     </ingredient>     <ingredient>       <quantity>1/2 teaspoon</quantity>       <component>salt</component>     </ingredient>     <ingredient>       <quantity>1 cup</quantity>       <component>corn meal</component>     </ingredient>     <ingredient>       <quantity>11/2 cups</quantity>       <component>whole milk</component>     </ingredient>     <ingredient>       <quantity>4 tablespoons</quantity>       <component>melted butter</component>     </ingredient>   </ingredients>   <directions>     <step>Sift flour, baking powder, sugar &amp; salt together.</step>     <step>Add 1 cup corn meal.</step>     <step>       Beat egg in cup and add beaten egg and 11/2 cups whole        milk to make a batter. Stir well.     </step>     <step>       Add melted shortening and beat until light and thoroughly mixed.     </step>     <step>       Pour into greased shallow pan or greased muffin rings.     </step>     <step>       Bake in hot oven at <temperature>425  F</temperature> for       <duration>25 minutes</duration>.     </step>     <step optional="yes">       Cut into squares if cooked in shallow pan.     </step>   </directions>   <story>     After my mother-in-law <person>Marjorie Anderson</person> 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, <city>Mt. Sterling</city>,     <state>Kentucky</state>.   </story> </recipe>

13.1 XSL Formatting Objects

An XSL-FO document describes the layout of a series of nested boxes or areas that are placed on one or more pages. These boxes contain text or occasionally other items, such as an external image or a horizontal rule. There are four kinds of boxes:

  • Block areas

  • Inline areas

  • Line areas

  • Glyph areas

Block and inline areas are created by particular elements in the formatting objects document. Line and glyph areas are created by the formatter as necessary. For the most part, the rendering engine decides exactly where to place the boxes and how big to make them, based on their contents. However, you can specify properties for these boxes that adjust both their relative and absolute position, spacing, and size on a page. Most of the time the individual boxes don't overlap. However, they can be forced to do so by setting the properties absolute-position, left, top, right, and top on the boxes.

Considered by itself, each box has a content area in which its content, generally text but possibly an image or a rule, is placed. This content area is surrounded by a padding area of blank space. An optional border can surround the padding. The size of the area is the combined size of the border, padding, and content. The box may also have a margin that adds blank space outside the box's area, as diagramed in Figure 13-1.

Figure 13-1. Content, padding, border, and margin of an XSL-FO area

figs/xian2_1301.gif

Text properties such as font family, font size, alignment, and font weight can be applied by attaching the appropriate properties to one of the boxes that contains the text. Text takes on the properties specified on the nearest enclosing box. Properties are set by attaching attributes to the elements that generate the boxes. For the most part these properties have the same semantics as the CSS properties of the same name. Only the syntax for applying the properties to particular ranges of text is different.

The elements in the XSL-FO document do not map in a one-to-one fashion to the boxes on the page. Instead, the XSL-FO document contains a slightly more abstract representation of the document. The formatting software uses the XSL-FO elements to decide which boxes to create and where to place them. In the process it will split the large blocks, which the XSL-FO document describes with fo:block elements, into smaller line and glyph areas. It may also split single block areas that the XSL-FO document describes into multiple block areas if a page break is required in the middle of a large block, though XSL-FO does let you prevent these breaks if necessary. The formatter also generates the correct number of pages for the content that's found. In short, the XSL-FO document contains hints and instructions that the formatter uses to decide what items to place where on which pages, but you do not need to specify the exact position of each and every box.

13.2 The Structure of an XSL-FO Document

The root element of all XSL-FO documents is fo:root. This element normally declares the fo prefix, which must be mapped to the http://www.w3.org/1999/XSL/Format namespace URI. As always, the prefix can change as long as the URI stays the same. In this chapter, we assume that the prefix fo has been associated with http://www.w3.org/1999/XSL/Format. Thus a typical FO document looks like this:

<?xml version="1.0" encoding="UTF-8"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">   <!-- Formatting object elements --> </fo:root>

Of course this normally isn't written directly as here. Instead, it's formed by an XSLT template like this one:

<xsl:template match="/">   <fo:root>     <xsl:apply-templates/>   </fo:root> </xsl:template>

The fo:root element must contain two things, a fo:layout-master-set and a fo:page-sequence . The fo:layout-master-set contains elements describing the overall layout of the pages themselves, that is, how large the pages are, whether they're in landscape or portrait mode, how wide the margins are, and so forth. The fo:page-sequence contains the actual text that will be placed on the pages, along with the instructions for formatting that text as italic, 20 points high, justified, and so forth. It has a master-reference attribute identifying the particular master page that will be used to layout this content. Adding these elements, a formatting objects document looks like this:

<?xml version="1.0" encoding="UTF-8"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">   <fo:layout-master-set>     <!-- page masters -->   </fo:layout-master-set>   <fo:page-sequence master-reference="first">     <!-- data to place on the page -->   </fo:page-sequence> </fo:root>

The formatting engine uses the layout master set to create a page. Then it adds content to the page from the fo:page-sequence until the page is full. Then it creates the next page in the sequence and places the next batch of content on that page. This process continues until all the content has been positioned.

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. The five regions in a left-to-right, top-to-bottom writing system

figs/xian2_1302.gif

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. The XSL-FO recipe document in FOP's AWT preview

figs/xian2_1303.gif

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

  • RenderX's XEP (http://www.renderx.com/FO2PDF.html) is a payware Java XSL-FO-to-PDF converter program much like FOP.

  • Sebastian Rahtz's PassiveTEX (http://users.ox.ac.uk/~rahtz/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/xslformatter.html) 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-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.

13.4 XSL-FO Properties

The finished document shown in Figure 13-3 is quite Spartan. It simply breaks the original XML document into a few separate paragraphs. After quite a lot of work, it still hasn't reached the polish that was achieved much more simply with CSS back in the last chapter in Example 12-2 and Figure 12-1. Adding the sparkle of different fonts, bold headlines, bulleted lists, and other desirable features requires setting the relevant properties on the individual formatting objects. These are set through optional attributes of the formatting object elements like fo:block. The good news is that most of the property names and semantics are exactly the same as they are for CSS. For example, to make the text in an fo:block element bold, add a font-weight attribute with the value bold, like this:

<fo:block font-weight="bold">Southern Corn Bread</fo:block>

The similarity with the equivalent CSS rule is obvious:

dish { font-weight: bold }

The property name is the same. The property value is the same. The meaning of the property is the same. Similarly, you can use all the font-weight keywords and values like lighter and 100, 200, 300, 400, etc. that you learned for CSS. Only the syntactic details of how the value bold is assigned to the property font-weight and how that property is then attached to the dish element has changed. When XSL-FO and CSS converge, they do so closely.

Many other properties come across from CSS by straight extrapolation. For instance, in Example 12-2 the dish element was formatted with this rule:

dish    {   display: block;   font-family: Helvetica, Arial, sans-serif;   font-size: 20pt;   font-weight: bold;   text-align: center }

In XSL-FO, it will be formatted with this XSLT template:

<xsl:template match="dish">   <fo:block font-family="Helvetica, Arial, sans-serif" font-size="20pt"             font-weight="bold" text-align="center">     <xsl:apply-templates/>   </fo:block> </xsl:template>

Similarly, the margin properties set the margins on the various elements:

<xsl:template match="directions|story">   <fo:block margin-top="12pt" margin-left="4pt">     <xsl:apply-templates/>   </fo:block> </xsl:template>

In a few cases CSS properties become XSL-FO elements rather than attributes. For instance, to format the ingredients as a bulleted list, we have to use the fo:list-block, fo:list-item, fo:list-item-label, and fo:list-item-body elements. This XSLT template does that:

<xsl:template match="ingredient">   <fo:list-item>              <!-- Unicode Bullet Character -->     <fo:list-item-label>&#x2022;</fo:list-item-label>     <fo:list-item-body><xsl:apply-templates/></fo:list-item-body>   </fo:list-item> </xsl:template>

We now have the pieces needed to put together a more attractive XSL-FO document. Example 13-4 is an XSLT stylesheet that transforms documents like Example 12-1 into XSL-FO documents.

Example 13-4. An XSLT-to-XSL-FO transform
<?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: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="recipe">     <fo:block font-family="Times, 'Times New Roman', serif"               font-size="12pt">       <xsl:apply-templates/>     </fo:block>   </xsl:template>   <xsl:template match="dish">     <fo:block font-family="Helvetica, Arial, sans-serif" font-size="20pt"               font-weight="bold" text-align="center">       <xsl:apply-templates/>     </fo:block>   </xsl:template>   <xsl:template match="directions|story">     <fo:block margin-top="12pt" margin-left="4pt">       <xsl:apply-templates/>     </fo:block>   </xsl:template>   <xsl:template match="ingredients">     <fo:list-block><xsl:apply-templates/></fo:list-block>   </xsl:template>   <xsl:template match="ingredient">     <fo:list-item>                <!-- Unicode Bullet Character -->       <fo:list-item-label>         <fo:block>&#x2022;</fo:block>       </fo:list-item-label>       <fo:list-item-body>         <fo:block><xsl:apply-templates/></fo:block>       </fo:list-item-body>     </fo:list-item>   </xsl:template> </xsl:stylesheet>

Example 13-5 shows the XSL-FO document produced by applying the previous transform to the cornbread recipe in Example 12-1. The whitespace has been cleaned up a little by hand, though that won't affect the final rendered result.

Example 13-5. 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 font-family="Times, 'Times New Roman', serif"                  font-size="12pt">       <fo:block font-family="Helvetica, Arial, sans-serif"         font-size="20pt" font-weight="bold"          text-align="center">Southern Corn Bread</fo:block>   <fo:list-block>     <fo:list-item><fo:list-item-label><fo:block> </fo:block>     </fo:list-item-label><fo:list-item-body><fo:block>       1 cup       flour     </fo:block></fo:list-item-body></fo:list-item>     <fo:list-item><fo:list-item-label><fo:block> </fo:block>     </fo:list-item-label><fo:list-item-body><fo:block>       4 tablespoons       Royal Baking Powder     </fo:block></fo:list-item-body></fo:list-item>     <fo:list-item><fo:list-item-label><fo:block> </fo:block>     </fo:list-item-label><fo:list-item-body><fo:block>       1/2 teaspoon       salt     </fo:block></fo:list-item-body></fo:list-item>     <fo:list-item><fo:list-item-label><fo:block> </fo:block>     </fo:list-item-label><fo:list-item-body><fo:block>       1 cup       corn meal     </fo:block></fo:list-item-body></fo:list-item>     <fo:list-item><fo:list-item-label><fo:block> </fo:block>     </fo:list-item-label><fo:list-item-body><fo:block>       11/2 cups       whole milk     </fo:block></fo:list-item-body></fo:list-item>     <fo:list-item><fo:list-item-label><fo:block> </fo:block>     </fo:list-item-label><fo:list-item-body><fo:block>       4 tablespoons       melted butter     </fo:block></fo:list-item-body></fo:list-item>   </fo:list-block>   <fo:block margin-top="12pt" margin-left="4pt">     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 margin-top="12pt" margin-left="4pt">     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:block></fo:flow></fo:page-sequence></fo:root>

This document can be run through a formatter to produce a PDF file for viewing. Figure 13-4 shows the final result of this process.

Figure 13-4. The recipe document after conversion from XSL-FO to PDF

figs/xian2_1304.gif

XSL-FO does add a number of properties that CSS doesn't provide. To name just a few, XSL-FO has properties to control hyphenation, insert leaders, specify the number of columns on a page, and determine where page breaks occur and which paragraphs must be kept together. CSS has none of these. For the most part, XSL-FO's properties are a superset of CSS's properties.

13.5 Choosing Between CSS and XSL-FO

CSS is a very straightforward, easy-to-learn, easy-to-use language for formatting web pages. To the extent that CSS has gotten a reputation as buggy and difficult to use, that's mostly because of inconsistent, nonstandard browser implementations. Opera 4.0 and later, Netscape 6.0 and later, and Mozilla provide extensive support for most features of CSS Level 2 with only a few minor bugs. Internet Explorer's support is much weaker, but borders on usable.

It's hard to imagine any text-based web site you can't produce by using XSLT to transform a document into HTML and then applying a CSS stylesheet. Alternately, you can transform the XML document into another XML document and apply the CSS stylesheet to that. If the element content in the original XML document is in fact exactly what you want to display in the output document, in the correct order, you can even omit the XSLT transformation step, as we did in Examples Example 12-1 and Example 12-2 in the last chapter.

Perhaps most importantly, CSS is already well understood by web designers and well supported by current browsers. XSL-FO is not directly supported by any browsers. To view an XSL-FO document, you must first convert it into the inconvenient PDF format. PDF does not adjust as well as HTML to the wide variety of monitors and screen sizes in use today. Viewing it inside a web browser requires a special plug-in. The limited third party tools that support XSL-FO are beta quality at best. Personally, we see little reason to use anything other than CSS on the Web.

On the other hand, XSL-FO does go beyond CSS in some respects that are important for high-quality printing. For example, XSL-FO offers multiple column layouts; CSS doesn't. XSL-FO can condition formatting on what's actually in the document; CSS can't. XSL-FO allows you to place footnotes, running headers, and other information in the margins of a page; CSS doesn't. XSL-FO lets you insert page numbers and automatically cross-reference particular pages by number; CSS doesn't. And for printing, the requirement to render into PDF is much less limiting and annoying since the ultimate delivery mechanism is paper anyway. CSS Level 3 will add some of these features, but it will still focus on ease-of-use and web-based presentation rather than high-quality printing. Once the software is more reliable and complete, XSL-FO should be the clear choice for professionally typeset books, magazines, newspapers, and other printed matter that's rendered from XML documents. It should be very competitive with other solutions like Quark XPress, TEX, troff, and FrameMaker. CSS does not even attempt to compete in this area.

The bottom line is this: CSS is right for web pages; XSL-FO is right for printed matter. XSLT is a crucial step in getting an input document ready for eventual presentation with either CSS or XSL-FO.

 

CONTENTS


XML in a Nutshell
XML in a Nutshell, 2nd Edition
ISBN: 0596002920
EAN: 2147483647
Year: 2001
Pages: 28

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net