This wiki has been archived and is now read-only.


From Print and Page Layout Community Group
Jump to: navigation, search

This is an experiment by the Print & Page Layout Community Group (PPLCG) in getting the area tree from an XSL formatter run as the result of calling an XSLT extension function in the same XSLT transform as will produce the "final" FO tree to be output for formatting as human readable pages.

It was initially developed in Java by Arved Sandstrom of MagicLamp Software following discussion on the public-ppl@w3.org mailing list. Other XSLT–XSL-FO combinations in Java and DotNet have followed. Further development now happens at https://github.com/pplcg/XSLTExtensions, with questions and comments happening on the public-ppl@w3.org mailing list.

The extension is available for Java and DotNet and uses either the Apache FOP XSL formatter or Antenna House Formatter (AH Formatter) to produce the area trees.

The single Java jar file covers four combinations of XSLT processor and XSL-FO formatter:

  • Saxon 9.5 (and later) and FOP
  • Saxon 9.5 (and later) and AH Formatter
  • Xalan and FOP
  • Xalan and AH Formatter

The DotNet version supports:

  • DotNet 4.0 and FOP
  • DotNet 4.0 and AH Formatter

Contributions of code for more combinations are more than welcome.


Available under the W3C license.

Example XSLT

The extension functions and templates are in 'ppl-extensions.xsl'. Functions and named templates for you to use are all in namespace of the PPL namespace URI:


Get the area tree for XSL-FO tree:

     as="document-node()?" />

Find the block corresponding to an ID in the FO tree:

     select="ppl:block-by-id($area-tree, key('boxes', true())[1]/@id)"
     as="element()" />

Find the block-progression-dimension of a block:

     as="xs:double" />


The best way to get an up-to-date version is to clone the Mercurial repository and build it yourself.

The most recent distribution is available at File:XSLTExtensions.zip

The extension requires the following libraries:


  • saxon9he.jar
  • xalan2-2.7.1.jar
  • fop-1.0.jar
  • xmlgraphics-commons-1.4.jar
  • avalon-framework-4.2.0.jar
  • commons-logging-1.1.1.jar
  • batik-all-1.7.jar
  • commons-io-1.4.jar
  • serializer-2.7.1.jar

Building it also requires Apache Ant.


  • DotNet FrameWork 4.0 Client Profile


Antenna House Formatter

  • Antenna House Formatter 6.1
  • pi.ep.xslt.transformer.app.exe File:DotNetXSLTExtProcessor.zip
  • fit pi.ep.xslt.transformer.app.exe.config as described in that file



Get the most recent (FOP-only) Windows distribution from File:FOPRunXSLTExt-windows-0.0.2.zip, unzip it on your system, and follow the instructions in the 'README' file.

1. Get and install Java JRE

2. Get and install Saxon

Saxon-HE is available from http://saxon.sourceforge.net/ as a Zip-encoded archive. Download the Zip file and extract its contents onto your local disk.

3. Get and install FOP 1.0

FOP distributions are available from http://xmlgraphics.apache.org/fop/download.html. Download the binary distribution of FOP 1.0 and extract its contents onto your local disk.

4. Edit 'runsaxon9he_fop10.bat' so the line beginning "set SAXON=" has the correct path to the Saxon-HE jar file on your system and so the line beginning "set FOP_HOME=" has the correct path to the "fop-1.0" folder that you extracted from the FOP binary distribution.

5. In the same directory as 'runsaxon9he_fop10.bat', run the following command:

     runsaxon9he_fop10.bat example1.xml example1_saxon9_fop10.xsl out/example1_saxon9_fop10.at


1. Get the most recent files from File:XSLTExtensions.zip, unzip it on your system, and follow the instructions in the 'README' file.

2. Get and install DotNet 4.0 FrameWork Client Profile

3. Get DotNetXSLTExtProcessor File:DotNetXSLTExtProcessor.zip

4. Apache FOP

5. Antenna House Formatter

  • Get and install Antenna House Formatter
  • open pi.ep.xslt.transformer.app.exe.config in an (XML) editor
  • follow instructions there and fit settings: Path and Version of XfoDotNet40Ctl61.dll

6. Copy all downloaded files in the same directory as rundotnet_fop11.bat or rundotnet_ahf61.bat

7. Run samples Apache FOP (in the same directory as rundotnet_fop11.bat)

     rundotnet_fop11.bat example1.xml example1.xsl out/example1_dotnet_fop11.at

8. Run samples Antenna House Formatter (in the same directory as rundotnet_ahf61.bat)

     rundotnet_ahf61.bat example1.xml example1.xsl out/example1_dotnet_ahf61.at

Rebuild packages


Building it also requires Apache Ant.


1. Get and install Microsoft Visual Studio 2010 (C#) (Express Edition and 2012 works, too)

2. Create a solution project in MS VS

3. Add C# projects to this solution

  • Antenna House Formatter: src\org\w3c\ppl\xslt\ext\ahf\dotnet\pi.ep.ppl.xslt.ext.ahf.dotnet\pi.ep.ppl.xslt.ext.ahf.dotnet.csproj
  • Apache FOP: src\org\w3c\ppl\xslt\ext\fop\dotnet\pi.ep.ppl.xslt.ext.fop.dotnet\pi.ep.ppl.xslt.ext.fop.dotnet.csproj

4. Antenna House Formatter

  • Get XfoDotNet40Ctl61.dll (in AHF instdir)
  • Copy it to: src\org\w3c\ppl\xslt\ext\ahf\dotnet\pi.ep.ppl.xslt.ext.ahf.dotnet\import

5. Apache FOP

  • Copy all IKVM.OpenJDK.*.dll s to src\org\w3c\ppl\xslt\ext\fop\dotnet\pi.ep.ppl.xslt.ext.fop.dotnet\import
  • Copy IKVM.Runtime.dll to src\org\w3c\ppl\xslt\ext\fop\dotnet\pi.ep.ppl.xslt.ext.fop.dotnet\import
  • Copy IKVM.Runtime.JNI.dll to src\org\w3c\ppl\xslt\ext\fop\dotnet\pi.ep.ppl.xslt.ext.fop.dotnet\import
  • Copy Fop11.dll to src\org\w3c\ppl\xslt\ext\fop\dotnet\pi.ep.ppl.xslt.ext.fop.dotnet\import


Example 1 - Area Tree

This just writes an area tree to a file.


runsaxon9he_fop10.bat example1.xml example1_saxon9_fop10.xsl out/example1_saxon9_fop10.at
rundotnet_fop11.bat example1.xml example1.xsl out/example1_dotnet_fop11.at


./runsaxon9he_fop10.sh example1.xml example.xsl out/example1_saxon9_fop10.at
./runsaxon9he_ahf61.sh example1.xml example1.xsl out/example1_saxon_ahf61.at
./runxalan_fop10.sh example1.xml example1.xsl out/example1_xalan_fop10.at
./runxalan_ahf61.sh example1.xml example1.xsl out/example1_xalan_ahf61.at

Example 3 - Rotate wide block

Rotates a fixed-size box if it is too wide for the page.

This is effectively a simplified version of requirement #10 from CustomerRequirements. That requirement is for knowing whether a table should be column-wide, page-wide, or rotated to to be page-high based on its formatted size. To do that, the stylesheet would have to get the sizes of the table when it's formatted to be column-wide, page-wide, and page-high and, based on those, decide which width and orientation to use for the table in the formatted result. This example reduces that to a single fixed-size block, analogous to the size of the formatted table, and the stylesheet just makes the single decision whether or not to rotate the block based on its formatted width.

The <box> element in 'example3.xml' specifies its formatted height and width:

  <box id="box001" width="8in" height="5in">

With those dimensions, if you transform 'example3.xml' with 'formatting.xsl' and format the result, the box is wider than the width of the page and some of the text is lost.

Error creating thumbnail: Unable to save thumbnail to destination

If you transform 'example3.xml' with 'example3_saxon9_fop10.xsl', which uses the extension function to make an area tree during the transform and makes decisions based on formatted areas, the box is rotated when it is too wide for the page.

Error creating thumbnail: Unable to save thumbnail to destination

Run the example using one of the command lines below then then run an XSL formatter on 'out/example3_saxon9_fop10.fo' to see the result.

You can change the box/@width value in 'example3.xml' and run it again to see whether or not the box is rotated.


runsaxon9he_fop10.bat example3.xml example3.xsl out/example3_saxon9.fo


./runsaxon9he_fop10.sh example3.xml example3.xsl out/example3_saxon9.fo
./runsaxon9he_ahf61.sh example3.xml example3.xsl out/example3_saxon9.fo

Example 4 - List item label width

Adjusts the lengths allowed for list items to exactly fit the formatted width of the list item labels.

This demonstrates a solution to requirement #9, "Ability to modify label field width in a single list when labels are large", from CustomerRequirements.

'example4.xml' includes two lists that, when transformed with 'formatting.xsl' and formatted, have list item label widths that are either too wide or too narrow for the labels in the lists.

Error creating thumbnail: Unable to save thumbnail to destination

When transformed with 'example4_saxon9_fop10.xsl' and formatted, the list item label widths are set based on the actual maximum formatted width of the labels in each list. The 'example4_saxon9_fop10.xsl' stylesheet does this by constructing a test document containing just the list item label texts, using the extension function to format that and get the area tree, and determining the maximum widths from the area tree. The document that is formatted mid-transform is, unlike in previous examples, a different document to the one used to produce the final output.

Error creating thumbnail: Unable to save thumbnail to destination

Example 5 - Copyfitting by adjusting 'font-size'

Adjusts the 'font-size' property until the formatted text fills a 'fo:block-container'.

The stylesheet includes a 'do-box' named template that -- based on the provided text and the initial values of minimum, optimum, and maximum font sizes, the tolerance for a good fit, and the maximum number of iterations -- runs the XSL formatter on the provided text and, when the size of the formatted text differs from the required size by more than the tolerance, iteratively calls itself again with adjusted font size limits until either the formatted size is within the tolerance or the maximum number of iterations is reached.

Error creating thumbnail: Unable to save thumbnail to destination


runsaxon9he_fop10.bat example5.xml example5.xsl out/example3.fo


./runsaxon9he_fop10.sh example5.xml example5.xsl out/example3.fo
./runsaxon9he_ahf61.sh example5.xml example5.xsl out/example3.fo


  • Arved Sandstrom
  • Tony Graham
  • Markus Wiedenmaier