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/19921103hypertext/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> How do we use XSL-FO? 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:regionbody/></fo:simple-page-master></fo:layout-master-set><fo:page-sequence masterreference="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" pageheight="29.7cm" master-name="A4-portrait"><fo:region-body/></fo:simple-pagemaster></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" pageheight="29.7cm" master-name="A4-portrait"><fo:region-body/></fo:simple-pagemaster></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" pageheight="29.7cm" master-name="A4-portrait"><fo:region-body/></fo:simple-pagemaster></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" pageheight="29.7cm" master-name="A4-portrait"><fo:region-body/></fo:simple-pagemaster></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? 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 xmlstylesheet instruction Starting to write XSL-FO 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 pagereference-area • There are four margins around the pagereference-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 pagereference-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 | rltb | 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 mastername 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:tableand-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> The complete XSLT stylesheet <?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="./countries/country"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="country"> <fo:block> <xsl:value-of select="."/> is a country. </fo:block> </xsl:template> </xsl:stylesheet> Using FOP • Assume the XML file is called countries.xml • Assume the XSLT file is called countries.xsl • We can generate the PDF file thus fop -xml countries.xml -xsl countries.xsl -pdf countries.pdf • We can see the XSL-FO thus fop -xml countries.xml -xsl countries.xsl -foout countries.fo The XSL-FO that was generated <?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>France is a country.</fo:block> <fo:block>Germany is a country.</fo:block> <fo:block>Ireland is a country.</fo:block> </fo:flow> </fo:page-sequence> </fo:root> Block attributes • In the unofficial DTD, many attributes are defined for blocks Block attributes • In the unofficial DTD, many attributes are defined for blocks • We will consider just a a few at this stage <!ATTLIST fo:block %block-properties;> <!ENTITY % block-properties " id CDATA #IMPLIED %inheritable-properties; "> <!ENTITY % inheritable-properties " color CDATA #IMPLIED relative-align ( before | baseline | inherit ) #IMPLIED span ( none | all | inherit ) #IMPLIED %accessibility-properties; %absolute-or-relative-position-properties; %border-padding-background-properties; %border-precedence-properties; %aural-properties; %box-size-properties; %margin-properties-inline; %area-properties; %area-alignment-properties-inline; %character-properties; %table-properties; %list-properties; %float-properties; %line-related-properties; %leader-properties; %keeps-and-breaks-properties-block; %hyphenation-properties-block; %visibility-properties; "> Block attributes • In the unofficial DTD, many attributes are defined for blocks • We will consider just a a few at this stage <!ATTLIST fo:block %block-properties;> <!ENTITY % block-properties " id CDATA #IMPLIED %inheritable-properties; "> <!ENTITY % inheritable-properties " color CDATA #IMPLIED relative-align ( before | baseline | inherit ) #IMPLIED span ( none | all | inherit ) #IMPLIED %accessibility-properties; %absolute-or-relative-position-properties; %border-padding-background-properties; %border-precedence-properties; %aural-properties; %box-size-properties; %margin-properties-inline; %area-properties; %area-alignment-properties-inline; %character-properties; %table-properties; %list-properties; %float-properties; %line-related-properties; %leader-properties; %keeps-and-breaks-properties-block; %hyphenation-properties-block; %visibility-properties; "> A diagram of some block sttributes Block attributes (contd.) • Like a <p> or a <div> in HTML, a <block> in XSLFO specifies that some content should be displayed in a rectangular area that is visually separated by a new line • Like a CSS area, an XSLFO block area has attributes that we can control with CSS-like expressions • However, XSL-FO provides many more attributes than CSS • Before surveying all the attributes, let’s look at an example use Example use of block attributes in XSLT <?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="./countries/country"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="country"> <fo:block border-width="3mm" border-color="red" border-style="solid" space-before="5mm"> <xsl:value-of select="."/> is a country. </fo:block> </xsl:template> </xsl:stylesheet> Example contd: the XSL-FO generated <?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 space-before="5mm" border-style="solid" border-color="red" border-width="3mm"> France is a country.</fo:block> <fo:block space-before="5mm" border-style="solid" border-color="red" border-width="3mm"> Germany is a country.</fo:block> <fo:block space-before="5mm" border-style="solid" border-color="red" border-width="3mm"> Ireland is a country.</fo:block> </fo:flow> </fo:page-sequence> </fo:root> PDF based on new XSL-FO output Block area attributes (page 1) • Block space-before and space-after – These specify minimum, optimum and maximum amounts of space that must be separate a block from the blocks just before and after the current block – Will be considered in detail later Block area attributes (page 2) • Block Margin – – – – – margin margin-top margin-bottom margin-left margin-right Block area attributes (page 3) • Block Border – Border style attributes: • Overall border – border-style • Side borders (Absolute Orientation) – – – – border-top-style border-bottom-style border-left-style border-right-style • Sides borders (Orientation relative to writing-mode) – – – – border-before-style (sometimes same as border-top) border-after-style (sometimes same as border-bottom) border-start-style (sometimes same as border-left) border-end-style (sometimes same as border-right) – Possible values none | dotted | dashed | solid | double | groove | ridge Block area attributes (page 4) • Block Border (contd.) – Border color attributes: • • • • • • • • • border-color border-before-color border-after-color border-start-color border-end-color border-top-color (sometimes same as border-before) border-bottom-color (sometimes same as border-after) border-left-color (sometimes same as border-start) border-right-color (sometimes same as border-end) – Possible values • any predefined colour name • rgb(0-255,0-255,0-255) Block area attributes (page 5) • Block Border (contd.) – Border width attributes: • • • • • • • • • border-width border-before-width border-after-width border-start-width border-end-width border-top-width (sometimes same as border-before) border-bottom-width (sometimes same as border-after) border-left-width (sometimes same as border-start) border-right-width (sometimes same as border-end) Block area attributes (page 6) • Block Border (contd.) – Block Padding • • • • • • • • • padding padding-before padding-after padding-start padding-end padding-top (sometimes same as padding-before) padding-bottom (sometimes same as padding-after) padding-left (sometimes same as padding-start) padding-right (sometimes same as padding-end) Block area attributes (page 7) • Block Border (contd.) – Block Background • • • • background-color background-image background-repeat background-attachment (scroll or fixed) Specifying versus constraining properties • Some properties, for example border-color, can specify an exact value which will appear in the output document • However, the space-before and space-after properties can only constrain the set of possible values that will appear in the output document without being able to specify the exact value that will appear – The actual value will depend on the way that the FO engine handles conflicting constraints • We will now consider these two properties in some detail The space-before and space-after properties Example XML document • This is ex.xml. It contains a text element, which contains ten paragraph elements: <?xml version="1.0"?> <text> <paragraph> This is a sentence in paragraph1. This is a sentence. ... This is a sentence. </paragraph> .... <paragraph> This is a sentence in paragraph10. This is a sentence. ... This is a sentence. </paragraph> </text> • The next slide contains ex1.xsl, an XSLT stylesheet for processing this XML ex1.xsl generates a header block and paragraph blocks <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm"> <xsl:value-of select="."/></fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex1.xsl • Result is a two page PDF file fop -xml ex.xml -xsl ex1.xsl -pdf ex1.pdf • • Notice that the sixth paragraph is split across the page boundary The block specifications do not require any space between the blocks • Header block specification <fo:block font-size="50pt" border="solid blue 3mm"> Some text </fo:block> • Paragraph block specification <fo:block border="red solid 3mm"> <xsl:value-of select="."/> </fo:block> ex2.xsl Preventing paragraph blocks from crossing page boundaries <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" keep-together.within-page="always"> <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex2.xsl • The entire sixth paragraph is now on the second page The keep-together property • This property has three components, referring to three different contexts – within-line, – within-column, – within-page • Possible values – auto, which imposes no keep-together requirement – always, which always keeps the formatting object keep-together – <some integer>, which imposes a keep-together requirement of the specified strength, with bigger integers being stronger if there is ever a conflict • A description of how conflicts are resolved is given at http://www.w3.org/TR/xsl/#keepbreak ex3.xsl Requiring space-before the paragraph blocks <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" keep-together.within-page="always" space-before="4cm" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex3.xsl • The output now occupies 4 pages in PDF • There is 4 cm of space before each paragraph – except for a paragraph at the start of a page • Why is there no 4 cm space before a paragraph at the start of a page? Space specifiers • The space-before property specifies the space required before the area generated by an XSL-FO object • The space-after property specifies the space required after the area generated by an XSL-FO object • Each space-specifier has five components, with the default values indicated in parentheses – – – – – minimum (0 pt) optimum (0 pt) maximum (0 pt) conditionality (discard) precedence (0) • A space specifier like space-before="4cm" is actually a shorthand for space-before.minimum="4cm" space-before.optimum="4cm" space-before.maximum="4cm" space-before.conditionality="discard" space-before.precedence="0" The conditionality component of space specifiers • Even if a space-specifier exists for an XSL-FO object, the space may sometimes not be rendered • A space specifier is normally used to generate a space between the area generated by an XSL-FO object and the nearest visible mark on the page before of after that area • The nearest visible mark may come from – the content of a non-empty content rectangle – a non-zero border • the border need not belong to the next or previous area • it could belong to an embracing block – some padding (because padding may contain background) • the padding need not belong to the next or previous area • it could belong to an embracing block • If the area generated by an XSL-FO object is at the top of a page, there is no visible mark on the page before the area, so a spacebefore could be discarded • Similarly, if the area generated is at the bottom of a page, a spaceafter could be discarded Conditionality component of space specifiers (contd.) • The conditionality component of a space specifier can have one of two values: discard • this means that the space-before/after is not required if there is no visible mark on the page before/after the XSL-FO object which has this space specifier retain • this means that the space-before/after must always be generated, even if there is no visible mark on the page before/after the XSL-FO object which has this space specifier ex4.xsl Always requiring space-before the paragraph blocks <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" keep-together.within-page="always" space-before="4cm" space-before.conditionality="retain" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex4.xsl • Now, there is a 4 cm space before each paragraph at the start of a page Precedence of space specifiers • Sometimes, when two boxes follow each other, the first box may have a space-after and the second box may have a space-after • The formatting program does not automatically produce both of these spaces – the result would almost certainly be too much space between the boxes • Instead, the formatting program uses space precedence rules to decide which space to generate on the page • The value of the precedence component for a space specifier can be either – <some integer> – or the word force • By default, the precedence for a space specifier is 0 • The space precedence rules are on the next slide Space precedence rules • When two space specifiers are in conflict, the following rules are used • If either space precedence is force, the formatting program will generate a space equal to the sum of all specifiers with a precedence of force • Otherwise, the formatting program will use the numeric space precedences to decide what to do • If the specifiers have different numeric precedences, the specifier with the higher precedence is used • If the specifiers have the same numeric precedence, – the formatting program will generate a space somewhere in the range [smaller-minimum, bigger maximum] – initially, the formatting program will try to generate a space equal to the bigger-maximum ex5.xsl A force precedence wins <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" space-before="4cm" space-before.precedence="force" space-after="8cm" space-after.precedence="4" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex5.xsl • The 4cm spacebefore, with precedence=force beats the 8cm space-after • There is a 4 cm space between each pair of paragraphs ex6.xsl Two neighbouring specifiers with precedence=force <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" space-before="4cm" space-before.precedence="force" space-after="8cm" space-after.precedence="force" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex6.xsl • Both the 4cm space-before and 8 cm space-after have precedence=force • Each pair of paragraphs on the same page are separated by 12 cm ex7.xsl Two neighbouring specifiers with different numeric precedences <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" space-before="4cm" space-before.precedence="4" space-after="8cm" space-after.precedence="5" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex7.xsl • The 4cm space-before, with precedence=4, is beaten by the 8 cm space-after with precedence=5 • Each pair of paragraphs on the same page are separated by 8 cm ex8.xsl Two neighbouring specifiers with different numeric precedences <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" space-before="4cm" space-before.precedence="5" space-after="8cm" space-after.precedence="4" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex8.xsl • The 4cm spacebefore, with precedence=5, beats by the 8 cm spaceafter with precedence=4 • Each pair of paragraphs on the same page are separated by 4 cm ex9.xsl Two neighbouring specifiers with equal numeric precedences <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" space-before="4cm" space-before.precedence="4" space-after="8cm" space-after.precedence="4" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex9.xsl • Both the 4cm spacebefore and the 8cm space-after have precedence=4 • The actual space must be in the interval [4,8] • The larger optimum is 8cm, so it is tried • It is possible everywhere, so it is used everywhere A digression: the keep-with-previous and keep-with-next properties • Each of these properties has three components, referring to three different contexts – within-line, – within-column, – within-page • Possible values – auto, which imposes no keep-with-previous/next requirement – always, which always keeps the formatting object with the previous/next object – <some integer>, which imposes a keep-with-previous/next requirement of the specified strength, with bigger integers being stronger if there is ever a conflict • A description of how conflicts are resolved is given at http://www.w3.org/TR/xsl/#keepbreak ex10.xsl Generating a space different from the optimum <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" keep-together.within-page="always" keep-with-previous.within-page="5" space-before="4cm" space-before.precedence="4" space-after.minimum="5cm" space-after.optimum="12cm" spaceafter.maximum="12cm" space-after.precedence="4" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex10.xsl • • • • • Both the 4cm space-before and the 5-12cm space-after have precedence=4 The actual space must be in the interval [4,12] The larger optimum is 12cm, so it is tried everywhere However, the keep-together and keep-with-previous requirements mean that the optimum is possible only on the last page On the earlier pages, a smaller space is generated ex11.xsl Using a negative space-before to cause overwriting <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" space-before="-8mm" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex11.xsl • Each paragraph block, except that for paragraph 8, overwrites part of the previous block ex12.xsl Conflict between negative and positive space <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" space-before.maximum="-8mm" space-after.optimum="4mm" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex12.xsl • • • • • • The first paragraph is moved back 8mm, because there is no space conflict However, when a sequence of two paragraphs are on the same page, there is a space conflict For space-before, max=-8mm forces minimum and optimum to be -8mm, because they cannot exceed the maximum For space-after, opt=4mm forces the max to be 4mm as well, because optimum cannot exceed maximum. Minimum is the default of 0. Space generated must be in range [smaller-min, bigger-max]; that is, in [-8mm,4mm] The bigger optimum, of 4mm is tried everywhere and can be used everywhere ex13.xsl Another conflict between negative and positive space <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" space-before.maximum="-8mm" space-after.optimum="8cm" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> Result of processing XML with ex13.xsl • • • • • • • The first paragraph is moved back 8mm, because there is no space conflict However, when a sequence of two paragraphs are on the same page, there is a space conflict For space-before, max=-8mm forces minimum and optimum to be -8mm, because they cannot exceed the maximum For space-after, opt=8cm forces the max to be 8cm as well, because optimum cannot exceed maximum. Minimum is the default of 0. Space generated must be in range [smaller-min, bigger-max]; that is, in [-8mm,8cm] The bigger optimum, of 8cm is tried everywhere However, in all cases on the first page, a smaller value must be used ex14.xsl Another conflict involving negative space <?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: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"> <fo:block font-size="50pt" border="solid blue 3mm">Some text</fo:block> <xsl:apply-templates select="./text/paragraph"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="paragraph"> <fo:block border="red solid 3mm" space-before.maximum="-8mm" space-after.optimum="0mm" > <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet> A problem: the result of processing XML with ex14.xsl • • • • • • • • The processing by fop does not agree with what appears to be the rules The first paragraph should be moved back 8mm, because there is no space conflict However, when a sequence of two paragraphs are on the same page, there is a space conflict For space-before, max=-8mm should force minimum and optimum to be 8mm, because they cannot exceed the maximum For space-after, opt=0mm should force the max to be 0mm as well, because optimum cannot exceed maximum. Minimum should be default of 0. Space generated should be in range [smaller-min, bigger-max]; that is, in [8mm,0mm] The bigger optimum, of 0mm, should be tried everywhere However, A problem: the result of processing XML with ex14.xsl • • • • • • • • • The processing by fop does not agree with what appears to be the rules The first paragraph should be moved back 8mm, because there is no space conflict However, when a sequence of two paragraphs are on the same page, there is a space conflict For space-before, max=-8mm should force minimum and optimum to be 8mm, because they cannot exceed the maximum For space-after, opt=0mm should force the max to be 0mm as well, because optimum cannot exceed maximum. Minimum should be default of 0. Space generated should be in range [smaller-min, bigger-max]; that is, in [8mm,0mm] The bigger optimum, of 0mm, should be tried everywhere However, in all cases, -8mm is used Why? Dunno? The Area Model The Area Model • Almost everything in XSL-FO can be regarded as being placed in a rectangular box on the page – the page itself is a box – the regions with the page are boxes – the blocks within a region are boxes – each block contains boxes for lines – lines contain boxes for text and inline areas • This nesting of boxes is called the Area Model Box directions • Earlier, it was said that – border-before-color is sometimes the same as border-top-color, – – – – border-after-color is sometimes the same as border-bottom-color, border-start-color is sometimes the same as border-left-color, border-end-color is sometimes the same as border-right-color, etc. • These statements use the word "sometimes", because whether "before" means the same as "top", and so on, depends on the directions in which content is being added to a box • Content is added to a box using two directions, which will be illustrated on the next few slides – the block-progression direction – the inline-progression direction Box directions for normal Western text • In normal Western documents, the block-progression direction is top-to-bottom, so – before means the same as top – after means the same as bottom Box directions for normal Western text • In normal Western documents, the inline-progression direction is left-to-right, so – start means the same as left – end means the same as right Box directions for Semitic languages • In Semitic languages, the blockprogression direction is the same as in Western languages: top-to-bottom • However, the inline-progression direction is right-to-left, so – start means the same as right – end means the same as left One set of directions for Japanese • Japanese can be written in various ways One set of directions for Japanese • Japanese can be written in various ways • One possible way is to start at the topright corner and write downwards – so the inline-progression direction is top-to-bottom • so start means the same as top • so end means the same as bottom One set of directions for Japanese • Japanese can be written in various ways • One possible way is to start at the topright corner and write downwards – so the inline-progression direction is top-to-bottom • so start means the same as top • so end means the same as bottom • And then One set of directions for Japanese • Japanese can be written in various ways • One possible way is to start at the topright corner and write downwards – so the inline-progression direction is top-to-bottom • so start means the same as top • so end means the same as bottom • And then move to the left for the next column of characters One set of directions for Japanese • Japanese can be written in various ways • One possible way is to start at the topright corner and write downwards – so the inline-progression direction is top-to-bottom • so start means the same as top • so end means the same as bottom • And then move to the left for the next column of characters – so the block progression direction is right-to-left • so before means the same as right • so after means the same as left Writing-mode • The order in which a language appears on the page is called the writing-mode • The writing-mode for English is left-to-right, top-to-bottom (lr-tb) • Writing mode affects the direction of block-progression and inlineprogression • We can change these directions by using a style property called writing-mode • The values defined in the XSL-FO specification are lr-tb | rl-tb | tb-rl | tb-lr | bt-lr | bt-rl | lr-bt | rl-bt | lr-alternating-rl-bt | lralternating-rl-tb | lr-inverting-rl-bt | lr-inverting-rl-tb | tb-lr-in-lr-pairs | lr | rl | tb • The first letter-pair specifies the inline-progression direction • The second letter-pair specifies the block-progression direction • Not all of these writing modes are supported by all XSL-FO engines – for example, tb-lr gives an error message in Apache FOP • The next dew slides show some example usage We can set writing-mode in the simple-page-master tag <?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" writing-mode="rl-tb" > <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> Writing-mode example 1 <fo:simple-page-master margin="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait" writing-mode="rl-tb" > Writing-mode example 2 <fo:simple-page-master margin="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait" writing-mode="tb-rl" > Page regions and box directions A reminder: regions of a page • Earlier, we saw that XSL-FO treats a page as a collection of regions • But region-body is the only required region • If we want to use the optional regions, we must define them in the order specified in this DTD element definition <!ELEMENT fo:simple-page-master (fo:region-body, fo:region-before?, fo:region-after?, fo:region-start?, fo:region-end? )> The location of the regions • The regions do not always appear on the page in the positions show here • The locations shown here are simply those that the regions have in normal Western documents Location of the optional regions in normal Western layout • In normal Western documents, the writing-mode is lr-tb • So before/after/start/end have the meanings shown in this image Location of the optional regions in normal Western layout • In normal Western documents, the writing-mode is lr-tb • So before/after/start/end have the meanings shown in this image Location of the optional regions in normal Western layout • In normal Western documents, the writing-mode is lr-tb • So before/after/start/end have the meanings shown in this image <fo:simple-page-master margin="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait" writing-mode="lr-tb" > <fo:region-body margin="2cm"/> <fo:region-before extent="1.5cm" background-color="green" /> <fo:region-after extent="1.5cm" background-color="brown" /> <fo:region-start extent="1.5cm" background-color="blue" /> <fo:region-end extent="1.5cm" background-color="red" /> </fo:simple-page-master> Location of the optional regions in normal Semitic layout • In normal Semitic documents, the writing-mode is rl-tb • So before and after have the same meanings as in Western documents • But the meanings of start and end are the reverse of their meaning in Western style documents Location of the optional regions in normal Semitic layout • In normal Semitic documents, the writing-mode is rl-tb • So before and after have the same meanings as in Western documents • But the meanings of start and end are the reverse of their meaning in Western style documents – the blue and red regions are reversed from the previous slide Location of the optional regions in normal Semitic layout • In normal Semitic documents, the writing-mode is rl-tb • So before and after have the same meanings as in Western documents • But the meanings of start and end are the reverse of their meaning in Western style documents – the blue and red regions are reversed from the previous slide <fo:simple-page-master margin="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait" writing-mode="rl-tb" > <fo:region-body margin="2cm"/> <fo:region-before extent="1.5cm" background-color="green" /> <fo:region-after extent="1.5cm" background-color="brown" /> <fo:region-start extent="1.5cm" background-color="blue" /> <fo:region-end extent="1.5cm" background-color="red" /> </fo:simple-page-master> Western versus Semitic layout • The before (green) and after (brown) regions are in the same place • But the start (blue) and end (red) regions are reversed Apache FOP cannot handle optional regions in Japanese layout • We have seen that Japanese sometimes uses writing-mode=tb-rl • Apache FOP seems able to handle the text placement • But it does not seem able to handle the placement of the optional before/after/start/end regions <fo:simple-page-master margin="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait" writing-mode="tb-rl" > <fo:region-body margin="2cm"/> <fo:region-before extent="1.5cm" background-color="green" /> <fo:region-after extent="1.5cm" background-color="brown" /> <fo:region-start extent="1.5cm" background-color="blue" /> <fo:region-end extent="1.5cm" background-color="red" /> </fo:simple-page-master> Margins and regions body-region margins are measured from ... • When using the optional regions, it is essential to remember that margins for the content of the region-body are actually measured from the outside edges of body-region margins are measured from ... • When using the optional regions, it is essential to remember that margins for the content of the region-body are actually measured from the outside edges of the page-reference-area Margins and regions, Example 1 <fo:simple-page-master margin="0cm" …> <fo:region-body margin="1cm"/> <fo:region-before extent="0.5cm" background color="green" /> <fo:region-after extent="0.5cm" background-color="yellow" /> <fo:region-start extent="0.5cm" background-color="blue" /> <fo:region-end extent="0.5cm“ background-color=“red" /> Margins and regions, Example 1 <fo:simple-page-master margin="0cm" …> <fo:region-body margin="1cm"/> <fo:region-before extent="0.5cm" background color="green" /> <fo:region-after extent="0.5cm" background-color="yellow" /> <fo:region-start extent="0.5cm" background-color="blue" /> <fo:region-end extent="0.5cm“ background-color=“red" /> • The simple-page-master margin surrounds the page-reference-area, which is divided into five regions Margins and regions, Example 1 <fo:simple-page-master margin="0cm" …> <fo:region-body margin="1cm"/> <fo:region-before extent="0.5cm" background color="green" /> <fo:region-after extent="0.5cm" background-color="yellow" /> <fo:region-start extent="0.5cm" background-color="blue" /> <fo:region-end extent="0.5cm“ background-color=“red" /> • • The simple-page-master margin surrounds the page-reference-area, which is divided into five regions In this example we have a zero margin in the simple-page-master – so, here, the page-reference-area covers the entire page Margins and regions, Example 1 <fo:simple-page-master margin="0cm" …> <fo:region-body margin="1cm"/> <fo:region-before extent="0.5cm" background color="green" /> <fo:region-after extent="0.5cm" background-color="yellow" /> <fo:region-start extent="0.5cm" background-color="blue" /> <fo:region-end extent="0.5cm“ background-color=“red" /> • • • The simple-page-master margin surrounds the page-reference-area, which is divided into five regions In this example we have a zero margin in the simple-page-master – so, here, the page-reference-area covers the entire page The margin for the region-body pushes the content in from the outer edge of the page-reference-area Margins and regions, Example 1 <fo:simple-page-master margin="0cm" …> <fo:region-body margin="1cm"/> <fo:region-before extent="0.5cm" background color="green" /> <fo:region-after extent="0.5cm" background-color="yellow" /> <fo:region-start extent="0.5cm" background-color="blue" /> <fo:region-end extent="0.5cm“ background-color=“red" /> • • • • The simple-page-master margin surrounds the page-reference-area, which is divided into five regions In this example we have a zero margin in the simple-page-master – so, here, the page-reference-area covers the entire page The margin for the region-body pushes the content in from the outer edge of the page-reference-area The reason there is white space above and to the left of the content is that the region-body margin is wider than region-before and region-start Margins and regions, Example 2 <fo:simple-page-master margin=“2cm" …> <fo:region-body margin="1cm"/> <fo:region-before extent="0.5cm background color="green" /> <fo:region-after extent="0.5cm“ background-color="yellow" /> <fo:region-start extent="0.5cm" background-color="blue" /> <fo:region-end extent="0.5cm“ background-color=“red" /> Margins and regions, Example 2 <fo:simple-page-master margin=“2cm" …> <fo:region-body margin="1cm"/> <fo:region-before extent="0.5cm background color="green" /> <fo:region-after extent="0.5cm“ background-color="yellow" /> <fo:region-start extent="0.5cm" background-color="blue" /> <fo:region-end extent="0.5cm“ background-color=“red" /> • The page-reference area is smaller than the page, because the margin in the simple-page-master is greater than zero Margins and regions, Example 2 <fo:simple-page-master margin=“2cm" …> <fo:region-body margin="1cm"/> <fo:region-before extent="0.5cm background color="green" /> <fo:region-after extent="0.5cm“ background-color="yellow" /> <fo:region-start extent="0.5cm" background-color="blue" /> <fo:region-end extent="0.5cm“ background-color=“red" /> • The page-reference area is smaller than the page, because the margin in the simple-page-master is greater than zero • The content is 3cm inside the edge of the page because – the simple-page-master margin is 2cm – the region-body also has a margin, of 1cm Margins and regions, Example 3 • Margins for region-body must exceed the extents of the regionbefore, region-after, region-start and region-end • If not, the content of the region-body will appear in these other regions <fo:simple-page-master margin=“2cm" …> <fo:region-body margin="1cm"/> <fo:region-before extent=“1.5cm background color="green“ /> <fo:region-after extent=“1.5cm“ background-color="yellow“ /> <fo:region-start extent=“1.5cm" background-color="blue“ /> <fo:region-end extent=“1.5cm“ background-color=“red“ /> More on writing-mode Putting writing-mode in a different place • We have specified writing-mode as an attribute of a simple-pagemaster element <fo:simple-page-master margin="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait" writing-mode="tb-rl" > • However, instead, we could specify it as an attribute of the regionbody element <fo:simple-page-master margin="2cm" page-width="21.0cm" page-height="29.7cm" master-name="A4-portrait" > <fo:region-body margin="2cm" writing-mode="tb-rl" /> <fo:region-before extent="1.5cm" background-color="green"/> <fo:region-after extent="1.5cm" background-color="yellow"/> <fo:region-start extent="1.5cm" background-color="blue"/> <fo:region-end extent="1.5cm" background-color="red"/> </fo:simple-page-master> Writing-mode for region-body, Example 1 • Notice that setting writing-mode in the region-body does not affect the placement of the other regions • unlike setting writingmode in the simple-pagemaster, which did affect all the regions <fo:region-body margin="2cm“ writing-mode="rl-tb“ /> <fo:region-before extent="1.5cm" background-color="green"/> <fo:region-after extent="1.5cm" background-color="yellow"/> <fo:region-start extent="1.5cm" background-color="blue"/> <fo:region-end extent="1.5cm" background-color="red"/> Writing-mode for region-body, Example 2 <fo:region-body margin="2cm“ writing-mode="tb-rl“ /> <fo:region-before extent="1.5cm" background-color="green"/> <fo:region-after extent="1.5cm" background-color="yellow"/> <fo:region-start extent="1.5cm" background-color="blue"/> <fo:region-end extent="1.5cm" background-color="red"/> Where can writing-mode be specified? • The XSL-FO specification says that a writing-mode can be specified for the following elements: fo:simple-page-master, fo:region-*, fo:table, fo:block-container, fo:inline-container • However, not all of these element types are supported by all FO processors – For example, as of 2010, Apache FOP does not support fo:inline-container • However, let's use it in fo:block-container Using writing-mode in fo:block-container <?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 margin="2cm" writing-mode="lr-tb" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"> <fo:flow flow-name="xsl-region-body"> <fo:block-container writing-mode="lr-tb"> <fo:block>Hello, Tom!</fo:block> <fo:block>Hello, Dick!</fo:block> </fo:block-container> <fo:block-container writing-mode="rl-tb"> <fo:block>Hello, Harry!</fo:block> <fo:block>Hello, Mick!</fo:block> </fo:block-container> </fo:flow> </fo:page-sequence> </fo:root> Using writing-mode in fo:block-container <?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 margin="2cm" writing-mode="lr-tb" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"> <fo:flow flow-name="xsl-region-body"> <fo:block-container writing-mode="lr-tb"> <fo:block>Hello, Tom!</fo:block> <fo:block>Hello, Dick!</fo:block> </fo:block-container> <fo:block-container writing-mode="rl-tb"> <fo:block>Hello, Harry!</fo:block> <fo:block>Hello, Mick!</fo:block> </fo:block-container> </fo:flow> </fo:page-sequence> </fo:root> We can, of course, specify other attributes in fo:block-container <?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 margin="2cm" writing-mode="lr-tb" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"> <fo:flow flow-name="xsl-region-body"> <fo:block-container writing-mode="lr-tb" color="red"> <fo:block>Hello, Tom!</fo:block> <fo:block>Hello, Dick!</fo:block> </fo:block-container> <fo:block-container writing-mode="rl-tb" color="blue"> <fo:block>Hello, Harry!</fo:block> <fo:block>Hello, Mick!</fo:block> </fo:block-container> </fo:flow> </fo:page-sequence> </fo:root> Now we can see why XSL-FO provides before/start/end/after Now we can see why XSL-FO provides before/start/end/after • They let us specify style properties without worrying which writing-mode will be used <?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 margin="2cm" writing-mode="lr-tb" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"><fo:flow flow-name="xsl-region-body"> <fo:block-container> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Tom!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Dick!</fo:block> </fo:block-container> <fo:block-container> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Harry!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Mick!</fo:block> </fo:block-container> </fo:flow></fo:page-sequence></fo:root> Now we can see why XSL-FO provides before/start/end/after • They let us specify style properties without worrying which writing-mode will be used <?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 margin="2cm" writing-mode="lr-tb" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"><fo:flow flow-name="xsl-region-body"> <fo:block-container> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Tom!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Dick!</fo:block> </fo:block-container> <fo:block-container> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Harry!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Mick!</fo:block> </fo:block-container> </fo:flow></fo:page-sequence></fo:root> Now we can see why XSL-FO provides before/start/end/after • • They let us specify style properties without worrying which writing-mode will be used Below, each block is given a border at the start of the 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 margin="2cm" writing-mode="lr-tb" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"><fo:flow flow-name="xsl-region-body"> <fo:block-container> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Tom!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Dick!</fo:block> </fo:block-container> <fo:block-container> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Harry!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Mick!</fo:block> </fo:block-container> </fo:flow></fo:page-sequence></fo:root> Now we can see why XSL-FO provides before/start/end/after • • • They let us specify style properties without worrying which writing-mode will be used Below, each block is given a border at the start of the text In normal Western documents, these borders will be at the left side <?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 margin="2cm" writing-mode="lr-tb" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"><fo:flow flow-name="xsl-region-body"> <fo:block-container> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Tom!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Dick!</fo:block> </fo:block-container> <fo:block-container> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Harry!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Mick!</fo:block> </fo:block-container> </fo:flow></fo:page-sequence></fo:root> In Western documents start borders are at the left-hand side But in Semitic documents start borders should be at the right-hand side Why before/start/end/after are useful Why before/start/end/after are useful • We can specify style in a languageindependent way <?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 margin="2cm" writing-mode="lr-tb" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"><fo:flow flow-name="xsl-region-body"> <fo:block-container> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Tom!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Dick!</fo:block> </fo:block-container> <fo:block-container> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Harry!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Mick!</fo:block> </fo:block-container> </fo:flow></fo:page-sequence></fo:root> Why before/start/end/after are useful • We can specify style in a languageindependent way and then add writing-mode <?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 margin="2cm" writing-mode="lr-tb" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"><fo:flow flow-name="xsl-region-body"> <fo:block-container writing-mode="lr-tb"> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Tom!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Dick!</fo:block> </fo:block-container> <fo:block-container writing-mode="rl-tb"> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Harry!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Mick!</fo:block> </fo:block-container> </fo:flow></fo:page-sequence></fo:root> Why before/start/end/after are useful • We can specify style in a languageindependent way and then add writing-mode <?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 margin="2cm" writing-mode="lr-tb" /> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"><fo:flow flow-name="xsl-region-body"> <fo:block-container writing-mode="lr-tb"> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Tom!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Dick!</fo:block> </fo:block-container> <fo:block-container writing-mode="rl-tb"> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Harry!</fo:block> <fo:block border-start-style="solid" border-start-width="3mm"> Hello, Mick!</fo:block> </fo:block-container> </fo:flow></fo:page-sequence></fo:root> Static versus flow content • The definition of fo:page-sequence in the unofficial DTD is <!ELEMENT fo:page-sequence ( fo:title?, fo:static-content*, fo:flow ) > • The fo:title is intended for use in interactive user agents, so is not useful at present • The fo:flow defines content which is often longer than would fit on one page, so it flows along a sequence of pages • An fo:page-sequence can have several fo:static-content children • fo:static-content elements are used to define content that appears in the same place on each page • usually static content is placed in regions other than the region-body • for example, static content is often used to define headers and footers for pages Consider this two-page document • Each page has three regions – region-body – region-before (silver) – region-start (grey/gray) • The region-body contains flowing content • The region-start is empty • But the region-before has content – this content is the same on all pages – it is static content Larger view Specifying static content <?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 margin="3cm"/> <fo:region-before extent="2cm" background-color="silver"/> <fo:region-start extent="2cm" background-color="gray"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"> <fo:static-content flow-name="xsl-region-before"> <fo:block font-size="30pt">Greetings</fo:block> </fo:static-content> <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:block>Hello, Mick!</fo:block> <fo:block>Hello, Mick!</fo:block> .... <fo:block>Hello, Mick!</fo:block> </fo:flow> </fo:page-sequence> </fo:root> Location-dependent static content: page numbering <?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 margin="3cm"/> <fo:region-before extent="2cm" background-color="silver"/> <fo:region-after extent="2cm" background-color="silver"/> <fo:region-start extent="2cm" background-color="gray"/> </fo:simple-page-master></fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"> <fo:static-content flow-name="xsl-region-before"> <fo:block font-size="30pt">Greetings</fo:block> </fo:static-content> <fo:static-content flow-name="xsl-region-after"> <fo:block font-size="25pt">Page <fo:page-number/></fo:block> </fo:static-content> <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:block>Hello, Mick!</fo:block><fo:block>Hello, Mick!</fo:block> .... <fo:block>Hello, Mick!</fo:block> </fo:flow> </fo:page-sequence> </fo:root> Location-dependent static content: page numbering Page numbering • The page-sequence element has several attributes for page numbering • In the unofficial DTD, this element's attributes are <!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; > • • The attributes coloured red above control the values of the page numbers in the sequence The attributes coloured blue above control the appearance of the page numbers, – by controlling how these numbers are converted into strings Specifying initial-page number <?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 margin="3cm"/> <fo:region-before extent="2cm" background-color="silver"/> <fo:region-after extent="2cm" background-color="silver"/> <fo:region-start extent="2cm" background-color="gray"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait" initial-page-number="999" > <fo:static-content flow-name="xsl-region-before"> <fo:block font-size="30pt">Greetings</fo:block> </fo:static-content> <fo:static-content flow-name="xsl-region-after"> <fo:block font-size="25pt">Page <fo:page-number/></fo:block> </fo:static-content> <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:block>Hello, Mick!</fo:block> <fo:block>Hello, Mick!</fo:block> .... <fo:block>Hello, Mick!</fo:block> </fo:flow> </fo:page-sequence> </fo:root> Specifying initial-page number (contd.) <fo:page-sequence master-reference="A4-portrait" initial-page-number="999"> Specifying initial-page number (contd.) • In the example just shown, we set the initial-page-number to a specified number <fo:page-sequence master-reference="A4-portrait" initial-page-number="999"> • However, initial-page-number can also have one of these symbolic values auto | auto-odd | auto-even • The meaning of these depends on whether or not the current pagesequence is the first page-sequence in the document • They will not be considered at this stage Specifying the format for page numbers • • format="1" specifies that page numbers should be expressed in decimal notation and should use the minimum possible number of digits Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="1" > Specifying the format for page numbers • • format="1" specifies that page numbers should be expressed in decimal notation and should use the minimum possible number of digits Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="1" > Specifying the format for page numbers (contd.) • • format="0...1" specifies that page numbers should be expressed in decimal notation and should use at least the number of digits given Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="001" > Specifying the format for page numbers (contd.) • • format="0...1" specifies that page numbers should be expressed in decimal notation and should use at least the number of digits given Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="001" > Specifying the format for page numbers (contd.) • • format="i" specifies that page numbers should be expressed in lower-case Roman numerals Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="i" > Specifying the format for page numbers (contd.) • • format="i" specifies that page numbers should be expressed in lower-case Roman numerals Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="i" > Specifying the format for page numbers (contd.) • • format="I" specifies that page numbers should be expressed in upper-case Roman numerals Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="I" > Specifying the format for page numbers (contd.) • • format="I" specifies that page numbers should be expressed in upper-case Roman numerals Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="I" > Specifying the format for page numbers (contd.) • • Roman numerals can, of course, be used for large numbers Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="999" format="I" > Specifying the format for page numbers (contd.) • • Roman numerals can, of course, be used for large numbers Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="999" format="I" > Specifying the format for page numbers (contd.) • • format="a" specifies that page numbers should be expressed in lower-case Latin letters Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="a" > Specifying the format for page numbers (contd.) • • format="a" specifies that page numbers should be expressed in lower-case Latin letters Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="a" > Specifying the format for page numbers (contd.) • • format="A" specifies that page numbers should be expressed as upper-case Latin letters Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="A" > Specifying the format for page numbers (contd.) • • format="A" specifies that page numbers should be expressed as upper-case Latin letters Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="9" format="A" > Specifying the format for page numbers (contd.) • • Although it is rarely done, Latin letters can be used for large numbers Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="999" format="A" > Specifying the format for page numbers (contd.) • • Although it is rarely done, Latin letters can be used for large numbers Example <fo:page-sequence master-reference="A4-portrait" initial-page-number="999" format="A" > Specifying the format for page numbers (contd.) • The are three other number formatting attributes that we have not examined yet: letter-value ( auto | alphabetic | traditional ) #IMPLIED grouping-separator CDATA #IMPLIED grouping-size CDATA #IMPLIED • • The meaning of these three attributes is not yet implemented by Apache FOP So we will not consider them at this stage Forcing page count • The force-page-count attribute of a page-sequence element is used to impose a constraint on the number of pages in a page-sequence • If this constraint is not satisfied, an additional page will be added to the end of the sequence – This page becomes the "last" page of the sequence • The values that this attribute can have are • even - force an even number of pages in this page-sequence • odd - force an odd number of pages in this page-sequence • end-on-even - force the last page in this page-sequence to be an even page • • • end-on-odd - force the last page in this page-sequence to be an even page no-force - do not force either an even or odd number of pages auto - the meaning of this depends on whether or not the current page-sequence is the last page-sequence in the document; it will not be considered at this stage Forcing page count, Example 1 • This document really needs only two pages • But it has three pages, ... • Because we forced the page count to be odd <fo:page-sequence master-reference="A4-portrait" force-page-count="odd" > Forcing page count, Example 2 • This document really needs only two pages • But it has three pages, ... • Because we forced the page count to end on an even number force-page-count="end-on-even" • Since there are only two pages of content, we would still have needed only two pages • But we had specified that the first page number should be 100 <fo:page-sequence master-reference="A4-portrait" initial-page-number="100" force-page-count="end-on-even" > Accessing the current page number • The element <fo:page-number> produces an inline-area whose content is the page-number for the page on which the inline-area is placed Accessing the current page number • The element <fo:page-number> produces some inline text representing the page-number of the page on which the inline text is located <?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 margin="3cm"/> <fo:region-before extent="2cm" background-color="silver"/> <fo:region-after extent="2cm" background-color="silver"/> <fo:region-start extent="2cm" background-color="gray"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait" initial-page-number="999" > <fo:static-content flow-name="xsl-region-before"><fo:block font-size="30pt">Greetings</fo:block></fo:static-content> <fo:static-content flow-name="xsl-region-after"><fo:block font-size="25pt">Page <fo:page-number/></fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <fo:block>Hello, Tom! This is page <fo:page-number> </fo:block> <fo:block>Hello, Dick! This is page <fo:page-number> </fo:block> <fo:block>Hello, Harry! This is page <fo:page-number> </fo:block> <fo:block>Hello, Mick! This is page <fo:page-number> </fo:block> <fo:block>Hello, Mick! This is page <fo:page-number> </fo:block> .... <fo:block>Hello, Mick! This is page <fo:page-number> </fo:block> </fo:flow> </fo:page-sequence> </fo:root> Accessing the current page number (contd.) Accessing the current page number (contd.) • The text produced by the <fo:page-number> element depends on the page numbering format that is being used Accessing the current page number (contd.) • The text produced by the <fo:page-number> element depends on the page numbering format that is being used <?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 margin="3cm"/> <fo:region-before extent="2cm" background-color="silver"/> <fo:region-after extent="2cm" background-color="silver"/> <fo:region-start extent="2cm" background-color="gray"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait" initial-page-number="999" format="I" > <fo:static-content flow-name="xsl-region-before"><fo:block font-size="30pt">Greetings</fo:block></fo:static-content> <fo:static-content flow-name="xsl-region-after"><fo:block font-size="25pt">Page <fo:page-number/></fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <fo:block>Hello, Tom! This is page <fo:page-number> </fo:block> <fo:block>Hello, Dick! This is page <fo:page-number> </fo:block> <fo:block>Hello, Harry! This is page <fo:page-number> </fo:block> <fo:block>Hello, Mick! This is page <fo:page-number> </fo:block> <fo:block>Hello, Mick! This is page <fo:page-number> </fo:block> .... <fo:block>Hello, Mick! This is page <fo:page-number> </fo:block> </fo:flow> </fo:page-sequence> </fo:root> Accessing the current page number (contd.) Cross-referencing pages Cross-referencing pages • The last line of this document refers to the page containing the first line Cross-referencing pages • The last line of this document refers to the page containing the first line Cross-referencing pages (contd.) • The XSL-FO source-code for the document is shown below • It will be explained on the next slide <?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 margin="3cm"/><fo:region-before extent="2cm" background-color="silver"/><fo:region-after extent="2cm" backgroundcolor="silver"/><fo:region-start extent="2cm" background-color="gray"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"> <fo:static-content flow-name="xsl-region-before"><fo:block font-size="30pt">Greetings</fo:block></fo:static-content> <fo:static-content flow-name="xsl-region-after"><fo:block font-size="25pt">Page <fo:page-number/></fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <fo:block id="tomGreeting" >Hello, Tom!</fo:block> <fo:block>Hello, Dick! </fo:block><fo:block>Hello, Harry! </fo:block><fo:block>Hello, Mick! </fo:block> <fo:block>Hello, Mick! </fo:block> .... <fo:block>Hello, Mick! </fo:block> <fo:block>Hello, Thomas! Are you related to Tom? (See page <fo:page-number-citation ref-id="tomGreeting"/> ) </fo:block> </fo:flow> </fo:page-sequence> </fo:root> Cross-referencing pages (contd.) • The important part of the source code is <fo:block id="tomGreeting"> Hello, Tom! </fo:block> ... See page <fo:page-number-citation ref-id="tomGreeting"/> • • • The fo:page-number-citation element generates the cross-reference This element can be contrasted with the fo:page-number element as follows The fo:page-number element produces some inline text representing the number of the page on which the element itself is located (more precisely, the page containing the text generated by the element itself) • The fo:page-number-citation element produces some inline text representing the number of the page which contains some other element (more precisely, the page containing the text generated by the other element) • The other element is the element whose id attribute has a value equal to the value of the ref-id attribute of the fo:page-number-citation element Using cross-referencing in the page footer (contd.) • In the following document, each page has a footer of the form Page number1 of number2 • The second number is generated by a cross-reference to the page containing the last text in the document Using cross-referencing in the page footer (contd.) • In the following document, each page has a footer of the form Page number1 of number2 • The second number is generated by a cross-reference to the page containing the last text in the document Using cross-referencing in the page footer (contd.) • The source-code for the document is shown below <?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 margin="3cm"/><fo:region-before extent="2cm" background-color="silver"/><fo:region-after extent="2cm" backgroundcolor="silver"/><fo:region-start extent="2cm" background-color="gray"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="A4-portrait"> <fo:static-content flow-name="xsl-region-before"><fo:block font-size="30pt">Greetings</fo:block></fo:static-content> <fo:static-content flow-name="xsl-region-after"> <fo:block font-size="25pt"> Page <fo:page-number/> of <fo:page-number-citation ref-id="endOfText"/> </fo:block> </fo:static-content> <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:block>Hello, Mick! </fo:block> <fo:block>Hello, Mick! </fo:block> .... <fo:block id="endOfText">Hello, Mick!</fo:block> </fo:flow> </fo:page-sequence> </fo:root> Multiple page masters Multiple page masters • • • • • • • Until now, each document had only one simple-page-master This is because all our pages were intended to have the same layout However, frequently, we need to have different page layouts in a single document For example, if we are formatting a booklet which will be stapled, ... ... we will need to leave space for the stapling Left-hand pages will need a bigger margin on the right-hand side Right-hand pages will need a bigger margin on the left-hand-side Multiple page masters • • • • • • • Until now, each document had only one simple-page-master This is because all our pages were intended to have the same layout However, frequently, we need to have different page layouts in a single document For example, if we are formatting a booklet which will be stapled, ... ... we will need to leave space for the stapling Left-hand pages will need a bigger margin on the right-hand side Right-hand pages will need a bigger margin on the left-hand-side Multiple page masters (contd.) • The layout-master-set must contain a simple-page-master for each type of page payout that we need • We will also need to specify when each of these simple page masters should be used • This is done using a new type of element called a page-sequence-master • Elements of this type are declared in the layout-master-set • Remember that its definition in the unofficial DTD was <!ELEMENT fo:layout-master-set ( fo:page-sequence-master*, fo:simple-page-master, ( fo:simple-page-master | fo:page-sequence-master )* ) > • So our layout-master-set will look something like this <fo:layout-master-set> <fo:simple-page-master ...> ... </fo:simple-page-master> <fo:simple-page-master ...> ... </fo:simple-page-master> <fo:page-sequence-master ...> ... </fo:page-sequence-master> </fo:layout-master-set> Multiple page masters: the leftPage <fo:layout-master-set> <fo:simple-page-master master-name="leftPage" page-width="21.0cm" page-height="29.7cm" margin-left="1.0cm" margin-right="4.5cm" margin-top="1.0cm" margin-bottom="1.0cm"> <fo:region-before extent="1cm"/> <fo:region-after extent="1cm"/> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm" background-color="silver"/> </fo:simple-page-master> <fo:simple-page-master master-name="rightPage" page-width="21.0cm" page-height="29.7cm" margin-left="1.5cm" margin-right="1.0cm" margin-top="1.0cm" margin-bottom="1.0cm"> <fo:region-before extent="1cm"/> <fo:region-after extent="1cm"/> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm" /> </fo:simple-page-master> <fo:page-sequence-master master-reference="..."> ... </fo:page-sequence-master> </fo:layout-master-set> Multiple page masters: the rightPage <fo:layout-master-set> <fo:simple-page-master master-name="leftPage" page-width="21.0cm" page-height="29.7cm" margin-left="1.0cm" margin-right="4.5cm" margin-top="1.0cm" margin-bottom="1.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm" background-color="silver"/> <fo:region-before extent="1cm"/> <fo:region-after extent="1cm"/> </fo:simple-page-master> <fo:simple-page-master master-name="rightPage" page-width="21.0cm" page-height="29.7cm" margin-left="4.5cm" margin-right="1.0cm" margin-top="1.0cm" margin-bottom="1.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm" background-color="silver"/> <fo:region-before extent="1cm"/> <fo:region-after extent="1cm"/> </fo:simple-page-master> <fo:page-sequence-master master-reference="contents"> ... </fo:page-sequence-master> </fo:layout-master-set> Multiple page masters: the page-sequence-master <fo:layout-master-set> <fo:simple-page-master master-name="leftPage" page-width="21.0cm" page-height="29.7cm" margin-left="1.0cm" margin-right="4.5cm" margin-top="1.0cm" margin-bottom="1.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm" background-color="silver"/> <fo:region-before extent="1cm"/> <fo:region-after extent="1cm"/> </fo:simple-page-master> <fo:simple-page-master master-name="rightPage" page-width="21.0cm" page-height="29.7cm" margin-left="4.5cm" margin-right="1.0cm" margin-top="1.0cm" margin-bottom="1.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm" background-color="silver"/> <fo:region-before extent="1cm"/> <fo:region-after extent="1cm"/> </fo:simple-page-master> <fo:page-sequence-master master-name="contents"> ... </fo:page-sequence-master> </fo:layout-master-set> fo:page-sequence-master • Its definition in the unofficial DTD is <!ELEMENT fo:page-sequence-master ( ( fo:single-page-master-reference | fo:repeatable-page-master-reference | fo:repeatable-page-master-alternatives )+ ) > <!ATTLIST fo:page-sequence-master master-name CDATA #REQUIRED > • The different types of child element for a page-sequence-master serve different purposes • We need to specify when to use members of a set of alternative simple page masters • So we need to use the child element called fo:repeatable-page-master-alternatives fo:repeatable-page-master-alternatives • The definition of this element in the unofficial DTD is <!ELEMENT fo:repeatable-page-master-alternatives ( fo:conditional-page-master-reference+ ) > <!ATTLIST fo:repeatable-page-master-alternatives maximum-repeats CDATA #IMPLIED > • We see that it can contain multiple children elements of type fo:conditional-page-master-reference • Each of these specifies when to use a particular page master fo:conditional-page-master-reference • The definition of this element in the unofficial DTD is slightly wrong • It should be <!ELEMENT fo:conditional-page-master-reference EMPTY> <!ATTLIST fo:conditional-page-master-reference master-reference CDATA #REQUIRED page-position ( first | last | rest | any | inherit ) #IMPLIED odd-or-even ( odd | even | any | inherit ) #IMPLIED blank-or-not-blank ( blank | not-blank | any | inherit ) #IMPLIED > • This element specifies when a particular page master (identified by the master-reference attribute) should be used • The other attributes describe the conditions that must be satisfied when the particular page master is used Example page-sequence-master • Suppose we want the first page to be a rightPage • This means we want odd-numbered pages to use the rightPage master • And even-numbered pages to use the leftPage master Example page-sequence-master • Suppose we want the first page to be a rightPage • This means we want odd-numbered pages to use the rightPage master • And even-numbered pages to use the leftPage master <fo:page-sequence-master master-name="booklet"> <fo:repeatable-page-master-alternatives> <fo:conditional-page-master-reference master-reference="leftPage" odd-or-even="even" /> <fo:conditional-page-master-reference master-reference="rightPage" odd-or-even="odd" /> </fo:repeatable-page-master-alternatives> </fo:page-sequence-master> The page-sequence • Make the page-sequence refer to the booklet page-sequence-master <fo:page-sequence master-reference="booklet" initial-page-number="1" format="1" > <fo:static-content flow-name="xsl-region-before"> <fo:block font-size="20pt">Greetings</fo:block> </fo:static-content> <fo:static-content flow-name="xsl-region-after"> <fo:block font-size="20pt">Page <fo:page-number/></fo:block> </fo:static-content> <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:block>Hello, Mick!</fo:block> <fo:block>Hello, Mick!</fo:block> ... <fo:block>Hello, Mick!</fo:block> </fo:flow> </fo:page-sequence> The result • See that Page 1 is a rightPage and Page 2 is a leftPage Including images Including images • One way of including an image in a document is to use the fo:external-graphic element • Its definition in the unofficial DTD is <!ELEMENT fo:external-graphic EMPTY > <!ATTLIST fo:external-graphic %graphic-properties; src CDATA #IMPLIED > • The graphic properties are: <!ENTITY % graphic-properties " id CDATA #IMPLIED content-type CDATA #IMPLIED %accessibility-properties; %relative-position-properties; %aural-properties; %border-padding-background-properties; %margin-properties-inline; %area-alignment-properties-inline; %box-size-properties; %font-properties; %line-height-properties; %keeps-and-breaks-properties-atomic; content-height CDATA #IMPLIED content-width CDATA #IMPLIED scaling ( uniform | non-uniform | inherit ) #IMPLIED scaling-method ( auto | integer-pixels | resample-any-method | inherit ) #IMPLIED overflow ( visible | hidden | scroll | auto | error-if-overflow | inherit ) #IMPLIED "> Including images (contd.) • Example usage <fo:block text-align="end"> <fo:external-graphic src=“URL-or-path/to/some/image-file“/> content-width="99px" content-height="109px" /> </fo:block> Graphic inclusion, example 1 <?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 master-name="ordinaryPage"page-width="21.0cm" pageheight="29.7cm“ margin-left="1.0cm" margin-right="2.0cm"margin-top="1.0cm" margin-bottom="2.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm“ background-color="silver" /> <fo:region-before extent="1cm"/><fo:region-after extent="1cm"/></fo:simple-pagemaster></fo:layout-master-set> <fo:page-sequence master-reference="ordinaryPage“ initial-page-number="1" format="1" > <fo:static-content flow-name="xsl-region-before"><fo:block font-size="20pt">Greetings</fo:block> </fo:staticcontent> <fo:static-content flow-name="xsl-region-after"><fo:block font-size="20pt">Page <fo:pagenumber/></fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <fo:block> <fo:external-graphic src="man.gif" content-height="150pt" /> </fo:block> <fo:block>Hello, Tom!</fo:block><fo:block>Hello, Dick!</fo:block> <fo:block>Hello, Harry!</fo:block><fo:block>Hello, Mick!</fo:block>… <fo:block>Hello, Mick!</fo:block> </fo:flow> </fo:page-sequence> </fo:root> Graphic inclusion, example 1 (contd.) • Image in default position, at start/left side of block Graphic inclusion, example 2 <?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 master-name="ordinaryPage"page-width="21.0cm" pageheight="29.7cm“ margin-left="1.0cm" margin-right="2.0cm"margin-top="1.0cm" margin-bottom="2.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm“ background-color="silver" /> <fo:region-before extent="1cm"/><fo:region-after extent="1cm"/></fo:simple-pagemaster></fo:layout-master-set> <fo:page-sequence master-reference="ordinaryPage“ initial-page-number="1" format="1" > <fo:static-content flow-name="xsl-region-before"><fo:block font-size="20pt">Greetings</fo:block> </fo:staticcontent> <fo:static-content flow-name="xsl-region-after"><fo:block font-size="20pt">Page <fo:pagenumber/></fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <fo:block text-align="end”> <fo:external-graphic src="man.gif" content-height="150pt" /> </fo:block> <fo:block>Hello, Tom!</fo:block><fo:block>Hello, Dick!</fo:block> <fo:block>Hello, Harry!</fo:block><fo:block>Hello, Mick!</fo:block>… <fo:block>Hello, Mick!</fo:block> </fo:flow> </fo:page-sequence> </fo:root> Graphic inclusion, example 2 (contd.) • Image aligned to end/right side of block Images: floating • The definition of XSL-FO includes various elements and attributes which are designed for floating parts of a document • Unfortunately, these are not implemented in Apache FOP at present • So, if you really want to wrap text around an image you must emulate floating by using tables or by using negative spacebefore Graphic inclusion, example 3 <?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 master-name="ordinaryPage"page-width="21.0cm" page-height="29.7cm“ margin-left="1.0cm" marginright="2.0cm"margin-top="1.0cm" margin-bottom="2.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm“ background-color="silver" /> <fo:region-before extent="1cm"/><fo:region-after extent="1cm"/></fo:simple-page-master></fo:layout-master-set> <fo:page-sequence master-reference="ordinaryPage“ initial-page-number="1" format="1" > <fo:static-content flow-name="xsl-region-before"><fo:block font-size="20pt">Greetings</fo:block> </fo:static-content> <fo:static-content flow-name="xsl-region-after"><fo:block font-size="20pt">Page <fo:page-number/></fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <fo:block text-align="end”> <fo:external-graphic src="man.gif" content-height=“75pt" /> </fo:block> <fo:block space-before=“-75pt" margin-right="80pt"> This is a sentence. This is another sentence. This is another sentence. And this is another sentence. … And this is another sentence.</fo:block> <fo:block>Hello, Tom!</fo:block> <fo:block>Hello, Dick!</fo:block> <fo:block>Hello, Harry!</fo:block> <fo:block>Hello, Mick!</fo:block> <fo:block>Hello, Tom!</fo:block><fo:block>Hello, Dick!</fo:block> <fo:block>Hello, Harry!</fo:block><fo:block>Hello, Mick!</fo:block>… <fo:block>Hello, Mick!</fo:block> </fo:flow> </fo:page-sequence> </fo:root> Graphic inclusion, example 3 (contd.) • Negative space-before used to make text blocks “wrap” around image Hotlinks Hotlinks • Hotlinks can be created by using the fo:basic-link element • Its specification in the unofficial DTD is <!ELEMENT fo:basic-link ( %mixed-level; )* > <!ATTLIST fo:basic-link %inline-properties; external-destination CDATA #IMPLIED internal-destination CDATA #IMPLIED indicate-destination ( true | false ) #IMPLIED show-destination ( replace | new ) #IMPLIED destination-placement-offset CDATA #IMPLIED target-processing-context CDATA #IMPLIED target-presentation-context CDATA #IMPLIED target-stylesheet CDATA #IMPLIED > • Either the external-destination and internal-destination should be specified. – If both are specified, the system may either report an error or use the internal-destination property Hotlinks, example 1 <?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 master-name="ordinaryPage"page-width="21.0cm" page-height="29.7cm“ margin-left="1.0cm" marginright="2.0cm"margin-top="1.0cm" margin-bottom="2.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm“ background-color="silver" /> <fo:region-before extent="1cm"/><fo:region-after extent="1cm"/></fo:simple-page-master></fo:layout-master-set> <fo:page-sequence master-reference="ordinaryPage“ initial-page-number="1" format="1" > <fo:static-content flow-name="xsl-region-before"><fo:block font-size="20pt">Greetings</fo:block> </fo:static-content> <fo:static-content flow-name="xsl-region-after"><fo:block font-size="20pt">Page <fo:page-number/></fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <fo:block> <fo:basic-link internal-destination="endOfText"> Click-here-to-go-to-the-end-of-the-text </fo:basic-link> <fo:basic-link external-destination=“url('http://www.ucc.ie')"> Click-here-to-go-to-the-UCC-website </fo:basic-link> </fo:block> <fo:block text-align="end”><fo:external-graphic src="man.gif" content-height=“75pt" /></fo:block> <fo:block space-before=“-75pt" margin-right="80pt">This is a sentence. This is another sentence. This is another sentence. And this is another sentence. … And this is another sentence.</fo:block> <fo:block>Hello, Tom!</fo:block> <fo:block>Hello, Dick!</fo:block><fo:block>Hello, Harry!</fo:block><fo:block>Hello, Mick!</fo:block> <fo:block>Hello, Tom!</fo:block><fo:block>Hello, Dick!</fo:block> <fo:block>Hello, Harry!</fo:block><fo:block>Hello, Mick!</fo:block>… <fo:block id=“endOfText”>Hello, Mick!</fo:block> </fo:flow> </fo:page-sequence> </fo:root> Hotlinks example 1 (contd.) • Notice how the areas generated by the fo:basic-link elements - are inline areas and - have no decoration Hotlinks, example 2 – highlighting links Hotlinks, example 2 – highlighting links <?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 master-name="ordinaryPage"page-width="21.0cm" page-height="29.7cm“ margin-left="1.0cm" marginright="2.0cm"margin-top="1.0cm" margin-bottom="2.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm“ background-color="silver" /> <fo:region-before extent="1cm"/><fo:region-after extent="1cm"/></fo:simple-page-master></fo:layout-master-set> <fo:page-sequence master-reference="ordinaryPage“ initial-page-number="1" format="1" > <fo:static-content flow-name="xsl-region-before"><fo:block font-size="20pt">Greetings</fo:block> </fo:static-content> <fo:static-content flow-name="xsl-region-after"><fo:block font-size="20pt">Page <fo:page-number/></fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <fo:block> <fo:basic-link color="blue" text-decoration="underline" internal-destination="endOfText"> Click here to go to the end of the text </fo:basic-link> <fo:basic-link color="blue" text-decoration="underline" external-destination=“url('http://www.ucc.ie')"> Click here to go to the UCC website </fo:basic-link> </fo:block> <fo:block text-align="end”><fo:external-graphic src="man.gif" content-height=“75pt" /></fo:block> <fo:block space-before=“-75pt" margin-right="80pt">This is a sentence. This is another sentence. This is another sentence. And this is another sentence. … And this is another sentence.</fo:block> <fo:block>Hello, Tom!</fo:block> <fo:block>Hello, Dick!</fo:block><fo:block>Hello, Harry!</fo:block><fo:block>Hello, Mick!</fo:block> <fo:block>Hello, Tom!</fo:block><fo:block>Hello, Dick!</fo:block> <fo:block>Hello, Harry!</fo:block><fo:block>Hello, Mick!</fo:block>… <fo:block id=“endOfText”>Hello, Mick!</fo:block> </fo:flow> </fo:page-sequence> </fo:root> Hotlinks example 2 (contd.) • The appearance of links below is like the default in HTML • However, we can specify a completely different appearance if we wish Tables HTML versus FO tables • HTML tables have this hierarchy <table> <caption> <colgroup> <col> <thead> <tr> <th> <tbody> <tr> <td> <tfoot> <tr> <td> • XSL-FO tables have this hierarchy <fo:table-and-caption> <fo:table-caption> <fo:table> <fo:table-column> <fo:table-header> <fo:table-row> <fo:table-cell> <fo:table-body> <fo:table-row> <fo:table-cell> <fo:table-footer> <fo:table-row> <fo:table-cell> Example table <fo:table table-layout="fixed" border-width="1px" border-style="solid"> <fo:table-column column-width="3cm"/> <fo:table-column column-width="3cm"/> <fo:table-column column-width="3cm"/> <fo:table-header text-align="center" background-color="red"> <fo:table-row> <fo:table-cell padding="1mm" border-width="1px" border-style="solid"><fo:block font-weight="bold">City</fo:block></fo:table-cell> <fo:table-cell padding="1mm" border-width="1px" border-style="solid"><fo:block font-weight="bold">Location</fo:block></fo:table-cell> <fo:table-cell padding="1mm" border-width="1px" border-style="solid"><fo:block font-weight="bold">Population</fo:block></fo:table-cell> </fo:table-row> </fo:table-header> <fo:table-body background-color="blue"> <fo:table-row> <fo:table-cell padding="1mm" border-width="1px" border-style="solid"><fo:block>Dublin</fo:block></fo:table-cell> <fo:table-cell padding="1mm" border-width="1px" border-style="solid"><fo:block>East coast</fo:block></fo:table-cell> <fo:table-cell padding="1mm" border-width="1px" border-style="solid"><fo:block>1,200,00</fo:block></fo:table-cell> </fo:table-row> <fo:table-row> <fo:table-cell padding="1mm" border-width="1px" border-style="solid"><fo:block>Cork</fo:block></fo:table-cell> <fo:table-cell padding="1mm" border-width="1px" border-style="solid"><fo:block>South coast</fo:block></fo:table-cell> <fo:table-cell padding="1mm" border-width="1px" border-style="solid"><fo:block>200,000</fo:block></fo:table-cell> </fo:table-row> </fo:table-body> </fo:table> The result Table properties <!ENTITY % table-properties " border-collapse ( collapse | separate | inherit ) #IMPLIED border-spacing CDATA #IMPLIED border-separation CDATA #IMPLIED border-separation.inline-progression-dimension CDATA #IMPLIED border-separation.block-progression-dimension CDATA #IMPLIED caption-side ( before | after | start | end | top | bottom | left | right | inherit ) #IMPLIED empty-cells ( show | hide | inherit ) #IMPLIED table-layout ( auto | fixed | inherit ) #IMPLIED table-omit-header-at-break ( true | false | inherit ) #IMPLIED table-omit-footer-at-break ( true | false | inherit ) #IMPLIED "> Lists Lists • We create lists using the fo:list-block element • Its specification in the unofficial DTD <!ELEMENT fo:list-block ( fo:list-item+ ) > <!ATTLIST fo:list-block %block-properties;> • The specification for the fo:list-item is <!ELEMENT fo:list-item ( fo:list-item-label, fo:list-item-body ) > <!ATTLIST fo:list-item %block-properties;> • The specification for the fo:list-item-label is <!ELEMENT fo:list-item-label ( %blocks; )+ > <!ATTLIST fo:list-item-label %block-properties;> • The specification for the fo:list-item-body is <!ELEMENT fo:list-item-body ( %blocks;)+ > <!ATTLIST fo:list-item-body %block-properties;> List, example 1 • Here is a simple list List, example 1 • Here is a simple list <fo:list-block> <fo:list-item> <fo:list-item-label> <fo:block>1</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block>Hello Tom!</fo:block> </fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block>2</fo:block></fo:list-item-label> <fo:list-item-body><fo:block>Hello Dick!</fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> List, example 1 • Here is a simple list • However, it is too simple, as the next slide shows <fo:list-block> <fo:list-item> <fo:list-item-label> <fo:block>1</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block>Hello Tom!</fo:block> </fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block>2</fo:block></fo:list-item-label> <fo:list-item-body><fo:block>Hello Dick!</fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> The layout is wrong The layout is wrong What's wrong? • There are some attributes whose values we must consider • Before we continue with lists, we should look again at the attributes that are defined for blocks Block attributes (revisited) • Here, again, are the block attributes in the unofficial DTD <!ATTLIST fo:block %block-properties;> <!ENTITY % block-properties " id CDATA #IMPLIED %inheritable-properties; "> <!ENTITY % inheritable-properties " color CDATA #IMPLIED relative-align ( before | baseline | inherit ) #IMPLIED span ( none | all | inherit ) #IMPLIED %accessibility-properties; %absolute-or-relative-position-properties; %border-padding-background-properties; %border-precedence-properties; %aural-properties; %box-size-properties; %margin-properties-inline; %area-properties; %area-alignment-properties-inline; %character-properties; %table-properties; %list-properties; %float-properties; %line-related-properties; %leader-properties; %keeps-and-breaks-properties-block; %hyphenation-properties-block; %visibility-properties; "> margin-properties-inline <!ENTITY % margin-properties-inline " %margin-properties-block; space-start CDATA #IMPLIED space-start.minimum CDATA #IMPLIED space-start.optimum CDATA #IMPLIED space-start.maximum CDATA #IMPLIED space-start.precedence CDATA #IMPLIED space-start.conditionality ( retain | discard ) #IMPLIED space-end CDATA #IMPLIED space-end.minimum CDATA #IMPLIED space-end.optimum CDATA #IMPLIED space-end.maximum CDATA #IMPLIED space-end.precedence CDATA #IMPLIED space-end.conditionality ( retain | discard ) #IMPLIED "> margin-properties-block <!ENTITY % margin-properties-block " %margin-properties-CSS; space-after CDATA #IMPLIED space-after.minimum CDATA #IMPLIED space-after.optimum CDATA #IMPLIED space-after.maximum CDATA #IMPLIED space-after.precedence CDATA #IMPLIED space-after.conditionality ( retain | discard ) #IMPLIED space-before CDATA #IMPLIED space-before.minimum CDATA #IMPLIED space-before.optimum CDATA #IMPLIED space-before.maximum CDATA #IMPLIED space-before.precedence CDATA #IMPLIED space-before.conditionality ( retain | discard ) #IMPLIED start-indent CDATA #IMPLIED end-indent CDATA #IMPLIED "> start-indent and end-indent • • The start-indent attribute of a block-area specifies the distance from the start-edge of the content-rectangle of the containing reference-area to the start-edge of the content-rectangle of the block-area The end-indent attribute of a block-area specifies the distance from the end-edge of the content-rectangle of the containing reference-area to the end-edge of the content-rectangle of the block-area start-indent, example <?xml version="1.0" encoding="UTF-8"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set>...</fo:layout-master-set> <fo:page-sequence master-reference="ordinaryPage" initial-page-number="1" format="1" > <fo:static-content flow-name="xsl-region-before"> <fo:block font-size="20pt">Greetings</fo:block> </fo:static-content> <fo:static-content flow-name="xsl-region-after"> <fo:block font-size="20pt">Page <fo:page-number/> </fo:block> </fo:static-content> <fo:flow flow-name="xsl-region-body"> <fo:block> This is an example sentence. </fo:block> <fo:block start-indent="1cm"> This is another example sentence. </fo:block> </fo:flow> </fo:page-sequence> </fo:root> end-indent, example <?xml version="1.0" encoding="UTF-8"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set>...</fo:layout-master-set> <fo:page-sequence master-reference="ordinaryPage" initial-page-number="1" format="1" > <fo:static-content flow-name="xsl-region-before"> <fo:block font-size="20pt">Greetings</fo:block></fo:static-content> <fo:static-content flow-name="xsl-region-after"> <fo:block font-size="20pt">Page <fo:page-number/> </fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <fo:block> This is an example paragraph....This is an example paragraph. </fo:block> <fo:block background-color="red" start-indent="1cm" end-indent="1cm"> This is yet another example paragraph. ...This is yet another example paragraph. </fo:block> </fo:flow></fo:page-sequence></fo:root> Indents for for list item labels and bodies • The labels and bodies of list item can have indents • This gives us four attributes for controlling layout Example, to motivate producing "definition lists" • Suppose we want to render some of its content as an XSL-FO list which looks like a HTML definition list Example, to motivate producing "definition lists" • Consider this XML document • Suppose we want to render some of its content as an XSL-FO list which looks like a HTML definition list Example, to motivate producing "definition lists" • Consider this XML document • Suppose we want to render some of its content as an XSL-FO list which looks like a HTML definition list <towns> <town> <name>Dublin</name> <location>East coast of Ireland</location> <population>1,200,000</population> </town> <town> <name>Cork</name> <location>South coast of Ireland</location> <population>200,000</population> </town> </towns> Example, to motivate producing "definition lists" • Consider this XML document • Suppose we want to render some of its content as an XSL-FO list which looks like a HTML definition list <towns> <town> <name>Dublin</name> <location>East coast of Ireland</location> <population>1,200,000</population> </town> <town> <name>Cork</name> <location>South coast of Ireland</location> <population>200,000</population> </town> </towns> Example, using FO lists to produce "definition lists" <fo:flow flow-name="xsl-region-body"> <fo:block>Dublin</fo:block> <fo:list-block> <fo:list-item> <fo:list-item-label><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body><fo:block> East coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block> </fo:list-item-label> <fo:list-item-body><fo:block> 1,200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> <fo:block>Cork</fo:block> <fo:list-block> <fo:list-item> <fo:list-item-label"><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body"><fo:block> South coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block></fo:list-item-label> <fo:list-item-body><fo:block> 200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> Poor layout Poor layout "Definition" lists example (contd.) • Let's add some background-color, to help see where we are <fo:flow flow-name="xsl-region-body"> <fo:block>Dublin</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body><fo:block> East coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block> </fo:list-item-label> <fo:list-item-body><fo:block> 1,200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> <fo:block>Cork</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label"><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body"><fo:block> South coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block></fo:list-item-label> <fo:list-item-body><fo:block> 200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> "Definition" lists example (contd.) • Let's add some background-color, to help see where we are <fo:flow flow-name="xsl-region-body"> <fo:block>Dublin</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body><fo:block> East coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block> </fo:list-item-label> <fo:list-item-body><fo:block> 1,200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> <fo:block>Cork</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label"><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body"><fo:block> South coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block></fo:list-item-label> <fo:list-item-body><fo:block> 200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> The red areas are the list-blocks "Definition" lists example (contd.) • We can avoid the overlap by giving a start-indent to the bodies <fo:flow flow-name="xsl-region-body"> <fo:block>Dublin</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="4cm"> <fo:block> East coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block> </fo:list-item-label> <fo:list-item-body start-indent="4cm"><fo:block> 1,200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> <fo:block>Cork</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label"><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="4cm"> <fo:block> South coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="4cm"> <fo:block> 200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> "Definition" lists example (contd.) • We can avoid the overlap by giving a start-indent to the bodies <fo:flow flow-name="xsl-region-body"> <fo:block>Dublin</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="2cm"> <fo:block> East coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block> </fo:list-item-label> <fo:list-item-body start-indent="2cm"><fo:block> 1,200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> <fo:block>Cork</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label"><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="2cm"> <fo:block> South coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="2cm"> <fo:block> 200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> A bit better, but not good enough • Before • After "Definition" lists example (contd.) • To avoid overlap, the bodies need a bigger start-indent <fo:flow flow-name="xsl-region-body"> <fo:block>Dublin</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="4cm"> <fo:block> East coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block> </fo:list-item-label> <fo:list-item-body start-indent="4cm"><fo:block> 1,200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> <fo:block>Cork</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label"><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="4cm"> <fo:block> South coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="4cm"> <fo:block> 200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> "Definition" lists example (contd.) • To avoid overlap, the bodies need a bigger start-indent <fo:flow flow-name="xsl-region-body"> <fo:block>Dublin</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="4cm"> <fo:block> East coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block> </fo:list-item-label> <fo:list-item-body start-indent="4cm"><fo:block> 1,200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> <fo:block>Cork</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label"><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="4cm"> <fo:block> South coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="4cm"> <fo:block> 200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> No overlap, but perhaps the separation is too large? Controlling layout of list items • As we have seen, we can control the layout of list items by specifying the required indents for the labels and bodies of these items • But this can require a lot of experimentation, especially with "definition" lists • XSL-FO provides two functions to reduce the work • These are – label-end(), used to compute the end-indent for labels – body-start(), used to compute the start-indent for bodies • Let's try using body-start "Definition" lists example (contd.) • Using body-start to set the start-indent for the list item bodies <fo:flow flow-name="xsl-region-body"> <fo:block>Dublin</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> East coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block> </fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> 1,200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> <fo:block>Cork</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" > <fo:list-item> <fo:list-item-label"><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> South coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> 200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> Better than nothing, but not good enough • We need to use something else as well Block attributes (revisited) • Here, again, are the block attributes in the unofficial DTD <!ATTLIST fo:block %block-properties;> <!ENTITY % block-properties " id CDATA #IMPLIED %inheritable-properties; "> <!ENTITY % inheritable-properties " color CDATA #IMPLIED relative-align ( before | baseline | inherit ) #IMPLIED span ( none | all | inherit ) #IMPLIED %accessibility-properties; %absolute-or-relative-position-properties; %border-padding-background-properties; %border-precedence-properties; %aural-properties; %box-size-properties; %margin-properties-inline; %area-properties; %area-alignment-properties-inline; %character-properties; %table-properties; %list-properties; %float-properties; %line-related-properties; %leader-properties; %keeps-and-breaks-properties-block; %hyphenation-properties-block; %visibility-properties; "> list-properties • Here are the list-property attributes in the unofficial DTD <!ENTITY % list-properties " provisional-distance-between-starts CDATA #IMPLIED provisional-label-separation CDATA #IMPLIED "> • The values of these attributes are used by label-end() and bodystart() • The initial value of provisional-label-separation is 6.0pt • The initial value of provisional-distance-between-starts is 24.0pt Computing label-end() and body-start() • label-end() = width of the content-rectangle of the reference-area into which the list-block is placed - (the value of the provisional-distance-between-starts + the value of the start-indent + start-intrusion-adjustment - the value of the provisional-label-separation) of the closest ancestor fo:list-block • body-start() = the value of the start-indent + start-intrusion-adjustment + the value of the provisional-distance-between-starts of the closest ancestor fo:list-block "Definition" lists example (contd.) • Setting provisional-distance-between-starts <fo:flow flow-name="xsl-region-body"> <fo:block>Dublin</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" provisional-distance-between-starts="3cm" > <fo:list-item> <fo:list-item-label><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> East coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block> </fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> 1,200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> <fo:block>Cork</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red" provisional-distance-between-starts="3cm"> <fo:list-item> <fo:list-item-label"><fo:block> location: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> South coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> population: </fo:block></fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> 200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> The result This works, but … • The body-start() function worked but we still had to specify a value for provisional-distance-between-starts • The main advantage is that we did not need to specify this value in each of the list item bodies – We need to specify it only once for each list-block • But we still had to decide what the value should be and this required some experimentation, in order to find a distance which was long enough to prevent overlap with the longest label • It would be better if we could automatically compute the required distance • We can, indeed, automate the computation • But it must be done in XSLT, at the time the XSL-FO document is being generated A digression, back to XSLT Computing required provisional-distance-between-starts for FO list blocks • We need to compute a distance which will prevent overlap with the longest list-item-label • Since list-item-labels are derived from the tag names in the source XML document, we need to compute the length of the longest tag name Example XML document • Consider this XML document • Suppose we want to automatically compute the length of the longest tag name for the child elements of the <town> elements • The XSLT stylesheet on the next slide will do it <towns> <town> <name>Dublin</name> <location>East coast of Ireland</location> <population>1,200,000</population> </town> <town> <name>Cork</name> <location>South coast of Ireland</location> <population>200,000</population> </town> </towns> Example XML document • Consider this XML document • Suppose we want to automatically compute the length of the longest tag name for the child elements of the <town> elements • The XSLT stylesheet on the next slide will do it <towns> <town> <name>Dublin</name> <location>East coast of Ireland</location> <population>1,200,000</population> </town> <town> <name>Cork</name> <location>South coast of Ireland</location> <population>200,000</population> </town> </towns> Example XML document • Consider this XML document • Suppose we want to automatically compute the length of the longest tag name for the child elements of the <town> elements • The XSLT stylesheet on the next slide will do it <towns> <town> <name>Dublin</name> <location>East coast of Ireland</location> <population>1,200,000</population> </town> <town> <name>Cork</name> <location>South coast of Ireland</location> <population>200,000</population> </town> </towns> Example XML document • Consider this XML document • Suppose we want to automatically compute the length of the longest tag name for the child elements of the <town> elements • The XSLT stylesheet on the next slide will do it <towns> <town> <name>Dublin</name> <location>East coast of Ireland</location> <population>1,200,000</population> </town> <town> <name>Cork</name> <location>South coast of Ireland</location> <population>200,000</population> </town> </towns> XSL stylesheet to compute longest tagname <?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> <!-- We need look at only the first town --> <xsl:apply-templates select="./towns/town[position()=1]“ /> </fo:root> </xsl:template> <!-- Sort the children of the town by descending length of tagname and output the length of the tagname of the first member of the sorted list --> <xsl:template match="town"> <xsl:for-each select="./*"> <xsl:sort select="string-length(name())" order="descending"/> <xsl:if test="position()=1">maxLabelLength=<xsl:value-of select="string-length(name())"/></xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet> Unfortunately, … • • • • Unfortunately, there is a problem Apache FOP seems to have a bug in it The stylesheet shown on the previous slide is correct We can see this if we execute the stylesheet with another XSLT processor, the Saxon processor http://saxon.sourceforge.net/ • But Apache FOP does not execute it correctly • We will see this on the next few slides Executing the stylesheet with Apache FOP • Assume the XML document is in a file called towns.xml • Assume the XSLT stylesheet is in a file called towns.xsl • Use Apache FOP to place the output in a file called towns.fo fop -xml towns.xml -xsl towns.xsl -foout towns.fo • The resultant content in towns.fo is <?xml version="1.0" encoding="UTF-8"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">maxLabelLength=8</fo:root> • • • • But this is wrong The longest tagname is population, which is 10 characters long However, there is nothing wrong with the stylesheet, as we can see if we execute it with the Saxon processor The result is shown on the next slide Executing the stylesheet with Saxon • Again, assume the XML document is in a file called towns.xml • Again, assume the XSLT stylesheet is in a file called towns.xsl • Use Saxon to place the output in a file called towns.fo java -jar /usr/local/saxon/saxon9he.jar towns.xml towns.xsl > towns.fo • The resultant content in towns.fo is <?xml version="1.0" encoding="UTF-8"?> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">maxLabelLength=10</fo:root> • • This is correct The longest tagname is population, which is 10 characters long Using both Saxon and FOP • Since there is an error in FOP, we could use Saxon and FOP together • We could Saxon to generate an XSL-FO file from an XML file and an XSLT file java -jar /usr/local/saxon/saxon9he.jar towns.xml towns.xsl > towns.fo • We could then use Apache FOP to generate a PDF file from the XSL-FO file which was created by Saxon fop -fo towns.fo -pdf towns.pdf Back to generating XSL-FO lists A stylesheet which calculates the max label length • The next two slides provide an XSLT stylesheet which calculates the number of characters in the longest tagname • It then specifies that number of em units as the provisional distance between starts • The stylesheet uses three templates – One template generates the top-level structure of the XSL-FO document and calls a template which generates the XSL-FO output for each individual town – The template which generates the XSL-FO output for an individual town uses a third template to determine the provisional distance between starts which should be used in the list block for the town – The third template examines the does not consider the <name> child when trying to determine the length of the longest child tag – Note that the second and third templates both match <town> elements, but are distinguished from each other by having different mode attritbutes A stylesheet which calculates the max label length • The next two slides provide an XSLT stylesheet which calculates the number of characters in the longest tagname • It then specifies that number of em units as the provisional distance between starts • The stylesheet uses three templates – One template generates the top-level structure of the XSL-FO document and calls a template which generates the XSL-FO output for each individual town – The template which generates the XSL-FO output for an individual town uses a third template to determine the provisional distance between starts which should be used in the list block for the town – The third template examines the does not consider the <name> child when trying to determine the length of the longest child tag – Note that the second and third templates both match <town> elements, but are distinguished from each other by having different mode attritbutes A stylesheet which calculates the max label length • The next two slides provide an XSLT stylesheet which calculates the number of characters in the longest tagname • It then specifies that number of em units as the provisional distance between starts • The stylesheet uses three templates – One template generates the top-level structure of the XSL-FO document and calls a template which generates the XSL-FO output for each individual town – The template which generates the XSL-FO output for an individual town uses a third template to determine the provisional distance between starts which should be used in the list block for the town – The third template examines the does not consider the <name> child when trying to determine the length of the longest child tag – Note that the second and third templates both match <town> elements, but are distinguished from each other by having different mode attritbutes A stylesheet which calculates the max label length • The next two slides provide an XSLT stylesheet which calculates the number of characters in the longest tagname • It then specifies that number of em units as the provisional distance between starts • The stylesheet uses three templates – One template generates the top-level structure of the XSL-FO document and calls a template which generates the XSL-FO output for each individual town – The template which generates the XSL-FO output for an individual town uses a third template to determine the provisional distance between starts which should be used in the list block for the town – The third template examines the does not consider the <name> child when trying to determine the length of the longest child tag – Note that the second and third templates both match <town> elements, but are distinguished from each other by having different mode attritbutes A stylesheet which calculates the max label length • The next two slides provide an XSLT stylesheet which calculates the number of characters in the longest tagname • It then specifies that number of em units as the provisional distance between starts • The stylesheet uses three templates – One template generates the top-level structure of the XSL-FO document and calls a template which generates the XSL-FO output for each individual town – The template which generates the XSL-FO output for an individual town uses a third template to determine the provisional distance between starts which should be used in the list block for the town – The third template examines the does not consider the <name> child when trying to determine the length of the longest child tag – Note that the second and third templates both match <town> elements, but are distinguished from each other by having different mode attritbutes Stylesheet, page 1 <?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:layout-master-set> <fo:simple-page-master master-name="ordinaryPage“ page-width="21.0cm" page-height="29.7cm" margin-left="4.5cm" margin-right="1.0cm“ margin-top="1.0cm" margin-bottom="1.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm background-color="silver" /> <fo:region-before extent="1cm"/> <fo:region-after extent="1cm"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="ordinaryPage“ initial-page-number="1" format="1" > <fo:static-content flow-name="xsl-region-before"><fo:block font-size="20pt">Towns</fo:block></fo:static-content> <fo:static-content flow-name="xsl-region-after"><fo:block font-size="20pt">Page <fo:pagenumber/></fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <!– process each town using the template for outputFO mode --> <xsl:apply-templates select="./towns/town" mode="outputFO“ /> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> Stylesheet, page 2 <xsl:template match="town" mode="outputFO" > <fo:block><xsl:value-of select="name"/></fo:block> <fo:list-block> <xsl:attribute name="provisional-distance-between-starts"> <xsl:apply-templates select="." mode="getMaxLabel" />em </xsl:attribute> <xsl:for-each select="./*[not(name()='name')]"> <fo:list-item> <fo:list-item-label> <fo:block> <xsl:value-of select="name()"/>: </fo:block> </fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> <xsl:value-of select="."/> </fo:block> </fo:list-item-body> </fo:list-item> </xsl:for-each> </fo:list-block> </xsl:template> <xsl:template match="town" mode="getMaxLabel" > <xsl:for-each select="./*[not(name()='name')]"> <xsl:sort select="string-length(name())" order="descending"/> <xsl:if test="position()=1"><xsl:value-of select="string-length(name())"/></xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet> The resultant output • • • • Use Saxon to get the XSL-FO output Use fop to process the XSL-FO into PDF The result is shown below The separation is too long because we are using em units and this produces a length greater than that actually rendered for proportional fonts, in which different letters have different widths – Some people have introduced extensions to XSLT processors like Saxon in order to better estimate the actual rendered length of text – See, for example, http://www.innodata-isogen.com/knowledge_center/tools_downloads/saxon_extensions Another stylesheet which calculates max label length • The next two slides provide a different XSLT stylesheet which calculates the number of characters in the longest tagname • It differs from the previous one in that it assumes that all towns have the same set of child elements – so the length of the longest child tagname need be calculated only once, for the first town • The stylesheet uses three templates • One template generates the top-level structure of the XSL-FO document • This calls another template which examines the first town, to get the length of the longest child tagname • Then it calls yet another template which generates the XSL-FO output for each individual town • This stylesheet actually generates exactly the same XSL-FO as the previous one • The only difference is that it calculates the length of the provisional distance between starts just once, puts this value in a variable and passes it as a parameter to the template which processes individual towns Another stylesheet which calculates max label length <?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:layout-master-set> <fo:simple-page-master master-name="ordinaryPage“ page-width="21.0cm" page-height="29.7cm" margin-left="4.5cm" margin-right="1.0cm“ margin-top="1.0cm" margin-bottom="1.0cm"> <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm background-color="silver" /> <fo:region-before extent="1cm"/> <fo:region-after extent="1cm"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="ordinaryPage“ initial-page-number="1" format="1" > <fo:static-content flow-name="xsl-region-before"><fo:block font-size="20pt">Towns</fo:block></fo:static-content> <fo:static-content flow-name="xsl-region-after"><fo:block font-size="20pt">Page <fo:pagenumber/></fo:block></fo:static-content> <fo:flow flow-name="xsl-region-body"> <xsl:variable name="provisional-distance"> <!-- compute provisional separation between starts by looking at first town --> <xsl:apply-templates select="./towns/town[position()=1]" mode="getMaxLabel"/>em</xsl:variable> <xsl:apply-templates select="./towns/town" mode="outputFO"> <xsl:with-param name="provisional" select="$provisional-distance" /> </xsl:apply-templates> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> Another stylesheet which calculates max label length <xsl:template match="town" mode="outputFO" > <xsl:param name="provisional-distance"/> <fo:block><xsl:value-of select="name"/></fo:block> <fo:list-block> <xsl:attribute name="provisional-distance-between-starts"> <xsl:value-of select="$provisional-distance"/> </xsl:attribute> <xsl:for-each select="./*[not(name()='name')]"> <fo:list-item> <fo:list-item-label> <fo:block> <xsl:value-of select="name()"/>: </fo:block> </fo:list-item-label> <fo:list-item-body start-indent="body-start()"> <fo:block> <xsl:value-of select="."/> </fo:block> </fo:list-item-body> </fo:list-item> </xsl:for-each> </fo:list-block> </xsl:template> <xsl:template match="town" mode="getMaxLabel" > <xsl:for-each select="./*[not(name()='name')]"> <xsl:sort select="string-length(name())" order="descending"/> <xsl:if test="position()=1"><xsl:value-of select="string-length(name())"/></xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet> Bulleted lists "Bulleted" lists example • Just using body-start; no usage of provisional-distance-between-starts <fo:flow flow-name="xsl-region-body"> <fo:block>Dublin</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red"> <fo:list-item> <fo:list-item-label><fo:block> &#x2022; </fo:block></fo:list-item-label> <fo:list-item-body start-indent=" body-start() "> <fo:block>Location: East coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> &#x2022; </fo:block> </fo:list-item-label> <fo:list-item-body start-indent=" body-start() "> <fo:block>Population: 1,200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> <fo:block>Cork</fo:block> <fo:list-block start-indent="1cm" end-indent="1cm" background-color="red"> <fo:list-item> <fo:list-item-label"><fo:block> &#x2022; </fo:block></fo:list-item-label> <fo:list-item-body start-indent=" body-start() "> <fo:block>Location: South coast of Ireland </fo:block></fo:list-item-body> </fo:list-item> <fo:list-item> <fo:list-item-label><fo:block> &#x2022; </fo:block></fo:list-item-label> <fo:list-item-body start-indent=" body-start() "> <fo:block>Population: 200,000 </fo:block></fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> The result A useful website • See http://www.stylusstudio.com/w3c/xslfo/