Sign In/My Account | View Cart  
advertisement


Listen Print

Printing from XML: An Introduction to XSL-FO
by Dave Pawson | Pages: 1, 2

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fo="http://www.w3.org/1999/XSL/Format">
  version="1.0">
  <xsl:output method="xml"/>

  <xsl:template match="/">
   <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <fo:layout-master-set>                  
      <fo:simple-page-master  
       master-name="simple"                 
                  page-height  ="29.7cm"       [1]
                  page-width   ="21cm"
                  margin-left  ="2.5cm"
		  margin-right ="2.5cm">
       <fo:region-body margin-top="3cm"/>      [2]
       </fo:simple-page-master>
 </fo:layout-master-set> 
 <fo:page-sequence 
               master-reference="simple">      [3]
   <fo:flow 
              flow-name="xsl-region-body">     [4]
        <xsl:apply-templates/>                 [5]
   </fo:flow>
 </fo:page-sequence>
</fo:root>
  </xsl:template>

  <xsl:template match="document">              [6]
   <fo:block>
    <xsl:apply-templates/>
   </fo:block>
  </xsl:template>


  <xsl:template match="head">                  [7]
   <fo:block>
      <xsl:apply-templates/>
    </fo:block>
  </xsl:template>

  <xsl:template match="para">                  [8]
    <fo:block>
     <xsl:apply-templates/>
    </fo:block>
  </xsl:template>

  <xsl:template match="em">                    [9]
   <fo:inline font-style="italic">
     <xsl:apply-templates/>
   </fo:inline>
  </xsl:template>


<xsl:template match="*">                       [10]
  <fo:block background-color="red">
   <xsl:apply-templates/>
  </fo:block>
 </xsl:template>

</xsl:stylesheet>

The Source Document

Before explaining the structure, the source document for which we are designing this stylesheet should be mentioned. I'm assuming a feed from a document class which has 4 elements, with the structure as shown below. I've kept it simple because it represents the vast majority of XML content meant for an XSL-FO document. It contains only two block items (head and para) and a single inline item (em).

Our document is contained in an outer document element, and a mix of head and para elements which contain some emphasis:

<document>
   <head>My very first xsl-fo document</head>
   <para>has an <em>important</em>  paragraph inside it</para>
</document>

A page size is specified at [1], using European sizes. Change these to your local paper size if it's different. I've added margins since content which extends to the edges of the page is unsightly.

At [2] I've added a top margin to the main region of the page. [3] and [4] are as before. At [5] we have a crucial difference: at this point, where previously I simply said "content", I now use the facilities of XSLT to instruct the XSLT engine to process the input document. At [6] the XSLT engine processes the document element of the input XML file by outputting an fo:block element, inside which all remaining content is placed. Since blocks can be nested quite happily in XSL-FO this isn't a problem. What it does do is ensure that any content which leaks -- that is, isn't handled explicitly by the stylesheet -- is still in a block.

At [7], [8], and [9] I'm back in the normal world of XML and XSLT. Matching a source document element and outputting an appropriate element from the XSL-FO vocabulary. The first two are identical and just need decorating, the latter is slightly different in that it is an inline formatting object and produces italic output.

[10] is a catch-all to show (in the output) which elements, if any, are not styled. Once styling is applied to all elements nothing will be processed by this template. It's good as a debugging option during development.

This stylesheet introduces two new elements. The first is the fo:block element, used for many elements in the stylesheet. This is the basic layout element which is used to wrap content; think of it as a p element in HTML.

The fo:inline element is a container for inline elements in XSL-FO. Each of these two elements has a whole range of properties, expressed syntactically as attributes, which are used to decorate the content that they wrap.

Starting New Pages

Let's extend the source document structure to include a section which should have a new page start point. So now the document might look like this:

<document>
  <section>
   <head>My very first xsl-fo document</head>
   <para>has an <em>important</em> paragraph inside it</para>
  </section>
  <section>
    <head>The second section, starting on a new page </head>
   <para>Some content in the second section</para>
  </section>
</document>

Now I need to style this addition, using one of the available properties of a block.

<xsl:template match="section">
  <fo:block break-before="page">
    <xsl:apply-templates/>
  </fo:block>
</xsl:template>

This tells the XSL-FO formatting engine to create a new page when it hits a section. All the content of that section is processed within that block. To make the head element stand out, I'll also improve the appearance by choosing a larger, bold font size and by adding a little space after the content.

<xsl:template match="head">        
   <fo:block    font-size="14pt"
		font-weight="bold"
                space-after="1cm"	
                space-after.conditionality = 'retain'
		>
      <xsl:apply-templates/>
   </fo:block>
</xsl:template>

That's it. To review: processing is a two stage process at its simplest. Give your source document and the above XSLT stylesheet to an XSLT processor, and the output should be a valid XSL-FO document. This can then be fed to an XSL-FO engine -- RenderX or Antenna House (both commercial, with trial options) or to PassiveTeX or FOP (non-commercial offerings).

You can download the files developed in this article here: xsl-fo-assets.zip.

Related Reading