3.11k likes | 3.23k Vues
Learn about the history and purpose of XSL-FO in specifying document rendering, its differentiation from CSS, and how to utilize this XML application-specific language effectively.
E N D
XSL Formatting Objects XSL-FO
Why XSL-FO? Some History • The history of HTML shows that, in the early days, both its designers and its users were confused about its purpose • Initially, it was intended for specifying the structure of documents for the web • Its tags included <h1> <p> <ol> <ul> <li> (See http://www.w3.org/History/19921103-hypertext/hypertext/WWW/MarkUp/Tags.html) • These documents were then displayed using whatever rendering choices were made by the displaying program
Why XSL-FO? Some History (contd.) • In the early days, there was some confusion • People did not make the distinction between structure and style • Even Tim Berners-Lee made the mistake of writing “Most of the tags are just style tags: this goes for the headings H1 to H6, the lists UL and OL with list elements LI, the glossary DL with elements DT and DD. ” (See http://lists.w3.org/Archives/Public/www-talk/1991SepOct/0003.html)
Why XSL-FO? Some History (contd.) • This confusion caused the mistaken introduction of rendering tags (and rendering attributes) into the language • For example: <b> <i> <tt> <font> • Elimination of this confusion led to the introduction of Cascading Style Sheets and the deprecation of rendering tags and attributes • It is now recognized that there should be a sharp distinction between the specification of structure and of rendering • This distinction was already recognized by the time that XML was developed
Why XSL-FO? Some History (contd.) • The structure/rendering distinction is reflected in the separation between XML and XSL • XML is used for specifying document structure • XSL is used for specifying document rendering • The W3 specification for XSL can be found here http://www.w3.org/TR/xsl/
Why XSL-FO? Some History (contd.) • XSLT is able to do only part of the job of rendering XML documents • XSLT is for specifying how to analyse the structure of an XML document in order to compute the appropriate rendering of the document • But XSLT must be complemented by a second notation in which we can specify the desired rendering • We have seen that HTML is sometimes used as the second notation • However, XSL Formatting Objects (XSL-FO) is the more general notation for specifying the desired rendering
Why XSL-FO? Some History (contd.) • It is common for XSLT to map XML documents into HTML documents • This is because HTML has a rendering semantics • However, HTML allows us to render XML documents only as web pages • using browsers as the rendering engines • Frequently, we need to render XML as other kinds of documents, including • PDF files, • Image files • We need another notation which can be used to specify the rendering of PDF files and images
Why XSL-FO? Some History (contd.) • XSL has two parts • XSLT can be used to analyse the structure of an XML document, in order to generate a document in some other notation • XSL-FO is one such other notation • XSL-FO is designed specifically for the purpose of describing the layout of documents • In this sense, its purpose is a little like that of CSS, • However, XSL-FO is quite different from CSS • A layout description given in XSL-FO can be used to generate a growing variety of documents, including • PDF files, • Image files
XSL-FO is an XML application-specific language • Every XSL-FO specification must be well-formed XML • For technical reasons, it is not possible to have a comprehensive DTD for XSL-FO • However, an unofficial DTD is here http://www.cs.ucc.ie/j.bowen/usefulResources/fo2000.dtd.html • Warning: this unofficial DTD was written by somebody from a company which produces a commercial FO processor program called XEP • The unofficial DTD contains some commercial extensions which are associated with the namespace http://www.renderx.com/XSL/Extensions • These extensions are identified in the DTD by use of the prefix rx:
XSL-FO is an XML application-specific language • The namespace for XSL-FO is http://www.w3.org/1999/XSL/Format • The prefix used is fo • The root element in XSL-FO has the tag name root • The declaration for this element in the unofficial DTD is <!ELEMENT fo:root (fo:layout-master-set, fo:declarations?,fo:page-sequence+)> <!ATTLIST fo:root xmlns:fo CDATA #REQUIRED> • Thus, the root element is of the form <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> … </fo:root>
First, let's revisit how we used XSLT to view XML files in browsers
A reminder: viewing XML in a web browser • The browser requests an XML document • The XML document refers to an XSLT stylesheet • The browser then requests the stylesheet • The browser's XSLT Engine generates HTML from XML+XSLT • The browser's HTML engine renders the HTML in the browser window
Using a browser's XSLT engine to generate HTML from XML ... <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html><head><title>Greetings</title></head> <body><xsl:apply-templates select="./names/name"/></body></html> </xsl:template> <xsl:template match="name"> <p>Hello, <xsl:value-of select="."/>!</p> </xsl:template> </xsl:stylesheet>
... Then rendering the HTML with the browser's HTML engine <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html><head><title>Greetings</title></head> <body><xsl:apply-templates select="./names/name"/></body></html> </xsl:template> <xsl:template match="name"> <p>Hello, <xsl:value-of select="."/>!</p> </xsl:template> </xsl:stylesheet>
What happens if we try the same thing with XSL-FO as we just did with HTML?
Generating XSL-FO from XML <?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:output method="xml" indent="yes"/> <xsl:template match="/"> <fo:root><fo:layout-master-set><fo:simple-page-master master-name="A4-portrait" page-height="29.7cm" page-width="21.0cm" margin="2cm"><fo:region-body/></fo:simple-page-master></fo:layout-master-set><fo:page-sequence master-reference="A4-portrait"><fo:flow flow-name="xsl-region-body"><xsl:apply-templates select="./names/name"/></fo:flow></fo:page-sequence></fo:root> </xsl:template> <xsl:template match="name"><fo:block>Hello, <xsl:value-of select="."/>!</fo:block> </xsl:template> </xsl:stylesheet>
How is the resultant XSL-FO rendered in the browser? <?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="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait"><fo:region-body/></fo:simple-page-master></fo:layout-master-set><fo:page-sequence master-reference="A4-portrait"> <fo:flow flow-name="xsl-region-body"> <fo:block>Hello, Tom! </fo:block> <fo:block>Hello, Dick! </fo:block> <fo:block>Hello, Harry! </fo:block> </fo:flow></fo:page-sequence></fo:root>
How is the resultant XSL-FO rendered in the browser? • The browser cannot render XSL-FO <?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="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait"><fo:region-body/></fo:simple-page-master></fo:layout-master-set><fo:page-sequence master-reference="A4-portrait"> <fo:flow flow-name="xsl-region-body"> <fo:block>Hello, Tom! </fo:block> <fo:block>Hello, Dick! </fo:block> <fo:block>Hello, Harry! </fo:block> </fo:flow></fo:page-sequence></fo:root>
How is the resultant XSL-FO rendered in the browser? • The browser cannot render XSL-FO • The fo: tags are simply ignored <?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="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait"><fo:region-body/></fo:simple-page-master></fo:layout-master-set><fo:page-sequence master-reference="A4-portrait"> <fo:flow flow-name="xsl-region-body"> <fo:block>Hello, Tom! </fo:block> <fo:block>Hello, Dick! </fo:block> <fo:block>Hello, Harry! </fo:block> </fo:flow></fo:page-sequence></fo:root>
How is the resultant XSL-FO rendered in the browser? • The browser cannot render XSL-FO • The fo: tags are simply ignored • We just see the included text <?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="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait"><fo:region-body/></fo:simple-page-master></fo:layout-master-set><fo:page-sequence master-reference="A4-portrait"> <fo:flow flow-name="xsl-region-body"> <fo:block>Hello, Tom! </fo:block> <fo:block>Hello, Dick! </fo:block> <fo:block>Hello, Harry! </fo:block> </fo:flow></fo:page-sequence></fo:root>
What went wrong? • The problem is that web browsers do not have engines for rendering XSL-FO • Instead, web browsers have engines for rendering HTML
So how do we render XSL-FO? • We need a different kind of program • We need a program which contains an FO engine • These programs are called FO processors • Usually they also contain an XSLT engine • They can generate various kinds of output, including PDF and image files
Generating XSL-FO from XML and then rendering the XSL-FO • Apache FOP is a commonly-used FO processor • fop contains both an XSLT engine and an FO engine • Example usage on the cs1 server: cs1> fop-xml names2.xml-xsl names2.xsl-pdf names2.pdf • This example command tells fop to apply an XSL stylesheet to an XML document and output a PDF file • The XML file need/should not contain an xml-stylesheet instruction
First stage of an XSLT stylesheet for generating XSL-FO from XML <?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:output method="xml" indent="yes"/> <xsl:template match="/"> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> … </fo:root> </xsl:template> </xsl:stylesheet>
Contents of the fo:root element • Element declaration: <!ELEMENT fo:root ( fo:layout-master-set, fo:declarations?, fo:page-sequence+ )> • Thus, the minimum contents of an fo:root element are: • fo:layout-master-set a description of the page layouts that are used in the document being specified • fo:page-sequence+ a set of specifications for one or more sequences of actual pages in the document
Minimum fo:root element • Example XSL-FO document <?xml version="1.0"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> … </fo:layout-master-set> <fo:page-sequence … > … </fo:page-sequence> </fo:root>
The layout-master-set • Declaration in the unofficial DTD is <!ELEMENT fo:layout-master-set ( fo:page-sequence-master*, fo:simple-page-master, ( fo:simple-page-master | fo:page-sequence-master )* ) > • Thus, the layout-master-set must contain at least one element of type fo:simple-page-master • Example XSL-FO document <?xml version="1.0"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> <fo:simple-page-master master-name=“…"> … </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence … > … </fo:page-sequence> </fo:root>
Page sequences refer to page masters • Each page sequence must refer to a page master <?xml version="1.0"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> <fo:simple-page-master master-name="someName"> … </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="someName"> … </fo:page-sequence> </fo:root>
How pages are modelled in XSL-FO • In the XSL-FO page model, a page in the document being specified contains several areas • The part of the page where the content will be placed is called the page-reference-area • There are four margins around the page-reference-area • These margins can be zero
How pages are modelled in XSL-FO (contd.) • The page-reference-area can be divided into five regions • Only the region-body is required • Most content will be placed in the region-body • The other regions may or may not be present • If the other regions are not present, the regions-body will be the same size as the page-reference-area
How pages are modelled in XSL-FO (contd.) • Unofficial DTD declaration for fo:simple-page-master is <!ELEMENT fo:simple-page-master (fo:region-body,fo:region-before?, fo:region-after?,fo:region-start?,fo:region-end?)>
How pages are modelled in XSL-FO (contd.) • Unofficial DTD declaration for fo:simple-page-master is <!ELEMENT fo:simple-page-master (fo:region-body,fo:region-before?, fo:region-after?,fo:region-start?,fo:region-end?)> <!ATTLIST fo:simple-page-master %margin-properties-CSS; master-name CDATA #REQUIRED page-height CDATA #IMPLIED page-width CDATA #IMPLIED media-usage CDATA #IMPLIED size CDATA #IMPLIED reference-orientation ( 0 | 90 | 180 | 270 | -90 | -180 | -270 | 0deg | 90deg | 180deg | 270deg | -90deg| - 180deg | -270deg | inherit ) #IMPLIED writing-mode ( lr-tb | rl-tb | tb-rl | lr | rl | tb | inherit ) #IMPLIED >
How pages are modelled in XSL-FO (contd.) • The definition, in the unofficial DTD, of the CSS-type margin properties is
How pages are modelled in XSL-FO (contd.) • The definition, in the unofficial DTD, of the CSS-type margin properties is <!ENTITY % margin-properties-CSS " margin CDATA #IMPLIED margin-bottom CDATA #IMPLIED margin-left CDATA #IMPLIED margin-right CDATA #IMPLIED margin-top CDATA #IMPLIED margin-after CDATA #IMPLIED margin-start CDATA #IMPLIED margin-end CDATA #IMPLIED margin-before CDATA #IMPLIED ">
Example XSL-FO document <?xml version="1.0"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> <fo:simple-page-master master-name="myPageType" page-height="29.7cm" page-width="21.0cm" margin="2cm"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="myPageType"> ...... </fo:page-sequence> </fo:root>
The region-body element • Declaration in the unofficial DTD is <!ELEMENT fo:region-body EMPTY> <!ATTLIST fo:region-body %region-properties; %margin-properties-CSS; column-count CDATA #IMPLIED column-gap CDATA #IMPLIED >
The region-body element • Declaration in the unofficial DTD is <!ELEMENT fo:region-body EMPTY> <!ATTLIST fo:region-body %region-properties; %margin-properties-CSS; column-count CDATA #IMPLIED column-gap CDATA #IMPLIED > <!ENTITY % region-properties " %border-padding-background-properties; %area-properties; region-name CDATA #IMPLIED"> <!ENTITY % area-properties " clip CDATA #IMPLIED overflow ( visible | hidden | scroll | auto | error-if-overflow | inherit ) #IMPLIED display-align ( auto | before | center | after | inherit ) #IMPLIED reference-orientation ( 0 | 90 | 180 | 270 | -90 | -180 | -270 | 0deg | 90deg | 180deg | 270deg | -90deg | -180deg | -270deg | inherit ) #IMPLIED writing-mode ( lr-tb | rl-tb | tb-rl | lr | rl | tb | inherit ) #IMPLIED ">
The fo:page-sequence element • Declaration in the unofficial DTD <!ELEMENT fo:page-sequence (fo:title?, fo:static-content*, fo:flow)> <!ATTLIST fo:page-sequence id CDATA #IMPLIED master-name CDATA #REQUIRED initial-page-number CDATA #IMPLIED force-page-count ( auto | even | odd | end-on-even | end-on-odd | no-force | inherit) #IMPLIED format CDATA #IMPLIED letter-value ( auto | alphabetic | traditional ) #IMPLIED grouping-separator CDATA #IMPLIED grouping-size CDATA #IMPLIED %inheritable-properties; > • Thus a minimal fo:page-sequence must have a master-name and must contain an fo:flow
The fo:flow element • Declaration in the unofficial DTD <!ELEMENT fo:flow ( %blocks; )+ > <!ATTLIST fo:flow %flow-properties; > <!ENTITY % blocks " %basic-blocks; | %out-of-lines; | %wrappers; "> <!ENTITY % flow-properties " id CDATA #IMPLIED flow-name CDATA #REQUIRED %inheritable-properties; "> <!ENTITY % basic-blocks " fo:block | fo:block-container | fo:table-and-caption | fo:table | fo:list-block "> • Thus a minimal fo:flow must have a flow-name (which specifies the region in which its content will be placed) and must contain at least one blocks entity • The simplest instance of blocks is an fo:block element
The fo:block element • Declaration in the unofficial DTD <!ELEMENT fo:block ( #PCDATA | fo:initial-property-set | %basic-inlines; | %basic-blocks; | %out-of-lines; | %wrappers; )* > <!ATTLIST fo:block %block-properties;> • The simplest content for an fo:block element is just some text
Example XSL-FO document <?xml version="1.0"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> <fo:simple-page-master master-name="myPageType" page-height="29.7cm" page-width="21.0cm" margin="2.0cm"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="myPageType"> <fo:flow flow-name="xsl-region-body"> <fo:block>Hello world</fo:block> </fo:flow> </fo:page-sequence> </fo:root>
Specifying lengths in XSL-FO • A length in XSL-FO is written as a real number followed by a unit qualification • Section 5.9.13 of the XSL specification http://www.w3.org/TR/xsl/#d0e5752 lists the allowable units as • cm • mm • in • pt (1/72 in) • pc (12 pt) • px • em (size of capital M in current font size)
The fop processor accepts XSL-FO files as input • Place the text on the previous slide in a file called demo.fo • Then run the command fop -fo demo.fo -pdf demo.pdf • A pdf file will be generated
The fop processor can output several types of file • Assume that demo.fo contains the source code shown on the previous slide • The command fop -fo demo.fo -png demo.png will output the document as png image • To see the full range of file types that can be generated, run the command fop -out list
Using XSLT to generate XSL-FO • Suppose we have the XML file shown • Suppose we want to generate the XSL-FO for the PDF document shown • Our XSLT program must • generate the "boiler-plate" XSL-FO when it finds the root node • and generate a sentence when it finds each country node • We will need two templates
The "boiler-plate" template <xsl:template match="/"> <fo:root> <fo:layout-master-set> <fo:simple-page-master master-name="A4-portrait" page-height="29.7cm" page-width="21.0cm" margin="2cm"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"> <fo:flow flow-name="xsl-region-body"> <xsl:apply-templates select="./countries/country"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template>
The country template <xsl:template match="country"> <fo:block> <xsl:value-of select="."/> is a country. </fo:block> </xsl:template>