XSL-FO

Dans ces notes, je regarde ce qu'est XSL-FO et je compare sa puissance à celle d'autres outils.

Introduction

XSL-FO est un schéma XML (ça veut dire que c'est comme du HTML, mais que les balises portent d'autres noms : par exemple, pour un paragraphe, on ne dira pas <p>, mais <block>) conçu pour pouvoir un peu mieux contrôler la typographie qu'avec HTML : le document est plus destiné à être imprimé (PDF ou PostScript) qu'à être lu sur un écran.

On part généralement d'un document XML « normal », i.e., ne contenant pas d'informations typographiques mais décrivant la structure logique de son contenu. Ensuite, on transforme (par exemple, avec XSLT) ce document XML en un document XSL-FO -- on obtient alors un autre document XML, qui contient uniquement des informations typographiques. Dans un deuxième temps, on convertit (avec un logiciel comme FOP) ce fichier en quelque chose d'imprimable (PDF ou PostScript).

Pour les férus d'histoire, XSL-FO est un mélange de CSS (utilisé pour les pages Web) et de DSSSL (obsolète : c'était l'équivalent, encore plus limité, de XSL-FO pour SGML).

Documentation

Voici quelques uns des documents sur XSL-FO qu'on peut trouver sur Internet et que j'ai utilisés.

What is XSL-FO?

http://www.xml.com/lpt/a/2002/03/20/xsl-fo.html

Introduction très générale

Using XSL Formatting Objects (1)

http://www.xml.com/lpt/a/2001/01/17/xsl-fo/index.html

Introduction plus précise : on écrit un peu de code non trivial

Using XSL Formatting Objects (2)

http://www.xml.com/lpt/a/2001/01/24/xsl-fo/index.html

Exemples réels, détaillés, avec un peu de XSLT. En particulier, explications des attributs de <block>, <inline>, des listes (et aussi un tableau).

Using XSL FO with XEP 2.7

http://www.renderx.com/Tests/doc/html/tutorial.html

Si on ne doit lire qu'un seul document sur XSL-FO, c'est celui-là que je conseille.

Chapter 18 of the XML Bible, Second Edition : XSL Formatting Objects

http://www.ibiblio.org/xml/books/bible2/chapters/ch18.html

XSL-FO Reference

http://zvon.org/xxl/xslfoReference/Output/index.html

IBM DeveloperWorks

Ils ont quelques articles sur XSL-FO -- et d'ailleurs, je crois que c'est ce qu'ils utilisent pour produire la version PDF de leurs pages.

http://www-106.ibm.com/developerworks/xml/library/x-xslfo/?dwzone=xml
http://www-106.ibm.com/developerworks/xml/library/x-dbrep/index.html

Ils ont aussi quelques tutoriels, mais il faut préalablement s'enregistrer sur leur site -- c'est très compliqué : je l'ai fait une fois (pour un autre tutoriel, qui était d'ailleurs très bien) et je n'ai jamais recommencé.

http://www-105.ibm.com/developerworks/education.nsf/xml-onlinecourse-bytitle/40B28792D6FC7F908525683B0052F7F2?OpenDocument

FOP

http://xml.apache.org/fop/

C'est le convertisseur "XSL-FO -> autre chose" le plus utilisé. Il est libre et écrit en Java.

XEP

Un concurrent (commercial) de FOP. Toujours en Java.

FOA (Formatting Objects Authoring)

http://foa.sourceforge.net/

Permet d'utiliser XSLT et XSL-FO sans avoir à écrire de code XSLT ou XSL-FO. C'était initialement un logiciel développé par HP, qui est devenu libre par la suite. C'est encore du Java et je n'ai pas osé essayer.

Exemples

Pour me convaincre de l'intéret de XSL-FO, j'aimerais avoir des exemples de documents PDF réalisés avec, aussi variés et et impressionnants que ceux qui accompagnent ConTeXt.

http://www.pragma-ade.com/

Mais je n'en ai pas trouvé. Voici juste quelques exemples simplistes.

Une lettre (on dirait une page Web imprimée, mais bien imprimée, un peu comme s'il s'agissait de la version imprimable d'une page Web).

http://foa.sourceforge.net/examples/mybank/MyBank.pdf

Un livre (aucune césure, double tiret au lieu du tiret moyen, espaces parasites -- pourtant, on peut avoir quelque chose de correct).

http://foa.sourceforge.net/examples/darkness/Darkness.pdf

Un peu plus impressionnant, mais en fait il y a simplement une commande PostScript qui fait ça -- avec PSTricks ou MetaPost, c'est très facile.

http://www.renderx.com/Tests/linebreak.pdf

Critiques

Absence de programmes qui implémentent complètement XSL-FO. Par exemple :

FOP does not currently support region-start and region-end.

As currently configured, the FO to PDF converter requires
the content of the header area to be the same on all
pages; thus you must specify <fo:static-content> rather
than a variable <fo:flow> to fill the xsl-region-before.

This chapter is based on the October 15, 2001
Recommendation of the XSL specification. However, most
software does not implement all of the the final
recommendation for XSL. In fact, so far there are only a
few standalone programs that convert XSL-FO documents into
PDF files. There are no Web browsers that can display a
document written with XSL formatting objects. Eventually,
of course, this should be straightened out as more vendors
implement XSL formatting objects.

Future versions of XSL-FO will add other kinds of page
masters, possibly including non-rectangular pages.

Rendu différent d'un programme à l'autre. En particulier, les algorithmes ce césure et de découpage des paragraphes en lignes ne sont pas imposés par le standard et peuvent être implémentés n'importe comment (comme dans Word).

XSL-FO ne manipule que des blocs rectangulaires. Et si je veux qu'un paragraphe ait une forme bizarre (la forme d'un rond, ou d'un coeur, par exemple) ? Et si je veux qu'un paragraphe épouse la forme d'une image ? Idem, mais l'image est au milieu du texte, qui se trouve à la fois à gauche et à droite ? (ça n'est pas rigoureusement impossible avec LaTeX, mais ça n'est pas très raisonnable)

Les notes de bas de page sont plus rudimentaires que sous TeX. Par exemple, sous TeX, on peut avoir plusieurs types de notes de bas de page, les notes normales, en bas de la page, et d'autres notes (par exemple, la liste des notions nouvelles introduites sur la page -- voir le TeXbook --, ou des références bibliographiques).

Il ne me semble pas qu'il y ait des note marginales (\marginpar en LaTeX), i.e., des objet flottants que l'on met dans la marge et que l'on essaye, si possible, de ne pas déplacer.

La gestion des objets flottants est elle aussi très rudimentaire -- et cela dépend de l'implémentation. Par exemple :

Only top-floats (float="before") are now implemented in XEP.

On ne dispose pas de tout la puissance de PDF. Certaines implémentation proposent d'y accéder (par exemple FOP http://xml.apache.org/fop/extensions ou XEP http://www.renderx.com/XSL/Extensions) mais ce n'est pas standardisé. A contrario, l'intégration de ConTeXt et de PDF est sans faille.

Il ne me semble pas qu'on puisse obtenir des graphiques qui dépendent de la taille du texte (comme avec les overlays de ConTeXt (ou de PSTricks)), qui servent par exemple à mettre un fond coloré (ou plus complexe) en dessous d'un morceau de texte, ce fond s'adaptant à la taille du texte.

Quid des graphiques ? En LaTeX (avec PSTricls ou MetaPost), on peut mettre du texte à l'intérieur de graphiques, par exemple, quand on dessine un graphe ou un arbre, le graphique va tenir compte de ta taille du texte. Certes, on peut mettre du SVG, qui lui-même peut contenir du texte, mais ce texte (à l'intérieur du dessin SVG) peut-il être mis en forme avec la même finesse que le texte alentours (césure, justification, etc.) ?

Peut-on mettre des mathématiques (en MathML) ? Si oui (s'il y a un logiciel qui accepte ça -- peut-être ceux qui qui convertissent le XSL-FO en TeX ?), comment fait-on pour taper du MathML ? avec quel éditeur ? Je rappelle qu'une formule simple, comme E=mc^2 (qui s'écrirait exactement comme ça en TeX), prend presque une page en MathML...

Si les seuls logiciels capables de convertir du XSL-FO avec une typographie correcte et en reconnaissant MathML sont en fait des convertisseurs vers TeX, quel est l'avantage de XSL-FO ? C'est plus pénible à écrire et moins facile à configurer que ConTeXt.

Conclusion

Préférer ConTeXt.

  http://www.pragma-ade.com/

Exemple de document

Voici un document XSL-FO (la plupart du temps, ces fichiers ont pour extension *.fo : cherchez sur votre disque dur, il doit y en avoir plein).

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.w3.org/1999/XSL/Format" 
      font-size="16pt">

<layout-master-set>
  <simple-page-master 
     margin-right="15mm" 
     margin-left="15mm" 
     margin-bottom="15mm" 
     margin-top="15mm" 
     page-width="210mm" 
     page-height="297mm" 
     master-name="bookpage"
  >
     <region-body 
       region-name="bookpage-body"
       margin-bottom="5mm" 
       margin-top="5mm" 
    />
  </simple-page-master>
</layout-master-set>

<page-sequence master-name="bookpage">
  <title>Hello world example</title>
  <flow flow-name="bookpage-body">
    <block>Hello XSLFO!</block>
  </flow>
</page-sequence>

</root>

Il faut aussi un programme pour convertir le FO en quelque chose d'utilisable : nous utiliserons FOP.

fop 1.fo 1.pdf

Espace de nommage

Le fichier aurait pu commencer par

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

et toutes les balises seraient de la forme <fo:balise> au lieu de <balise>. (Ca permet de mélanger plusieurs schémas, par exemple, pour mettre du MathML ou du SVG à l'intérieur d'un document).

Description des pages

La seule chose compliquée dans l'exemple précédent, c'est le bloc <layout-master-set>. Il permet de définir un ou plusieurs "page-paster", i.e., des « formats » de page. Par exemple, un pour la page de titre et un autre pour les pages normales.

Mais il pourrait y en avoir plus, par exemple, un pour la page de titre, un pour les page de gauche (resp. droite) du texte, un pour les pages de gauche (resp. droite) des appendices, un pour les pages de gauche (resp. droite) qui contiennent une illustration ou un tableau qui occupe toute la page, etc.. On y précise la taille de la page et celle des marges.

On peut ensuite mettre le texte : le bloc <flow> désigne quelque chose qui peut s'étendre sur plusieurs pages.

Voici un exemple plus compliqué.

<fo:layout-master-set>
  <fo:simple-page-master master-name="cover"
      page-height="12cm"
      page-width="12cm"
      margin-top="0.5cm"
      margin-bottom="0.5cm"
      margin-left="1cm"
      margin-right="0.5cm">
  </fo:simple-page-master>

  <fo:simple-page-master master-name="leftPage"
      page-height="12cm"
      page-width="12cm"
      margin-left="0.5cm"
      margin-right="1cm"
      margin-top="0.5cm"
      margin-bottom="0.5cm">
  </fo:simple-page-master>

  <fo:simple-page-master master-name="rightPage"
      page-height="12cm"
      page-width="12cm"
      margin-left="1cm"
      margin-right="0.5cm"
      margin-top="0.5cm"
      margin-bottom="0.5cm">
  </fo:simple-page-master>

  <!-- more info will go here -->
</fo:layout-master-set>

Flow

Après la description des pages, vient le corps du document (que l'on appelerait <body> en HTML, mais qui s'appelle ici <flow>). XSL-FO peut décider de le répartir sur plusieures pages différentes.

<page-sequence master-name="bookpage">
  <title>Hello world example</title>
  <flow flow-name="bookpage-body">
    <block>Hello XSLFO!</block>
  </flow>
</page-sequence>

Autre exemple.

<fo:page-sequence master-name="cover">
<fo:flow flow-name="xsl-region-body">
    <fo:block font-family="Helvetica" font-size="18pt"
        text-align="end">
        Spanish Review Handbook
    </fo:block>
    <fo:block font-family="Helvetica" font-size="12pt"
        text-align="end" space-after="36pt">
        Copyright &#169; 2001 J. David Eisenberg
    </fo:block>
    <fo:block text-align="end">
        A Catcode Production
    </fo:block>
</fo:flow>
</fo:page-sequence>

Autre exemple.

<fo:page-sequence master-name="cover">
<fo:flow flow-name="xsl-region-body">
    <fo:block font-family="Helvetica" font-size="18pt"
        text-align="end">
        Spanish Review Handbook
    </fo:block>
    <fo:block font-family="Helvetica" font-size="12pt"
        text-align="end" space-after="36pt">
        Copyright &#169; 2001 J. David Eisenberg
    </fo:block>
    <fo:block text-align="end">
        A Catcode Production
    </fo:block>
</fo:flow>
</fo:page-sequence>

<block> et <inline>

<block> est à l'équivalent de <p> en HTML : cela correspond à un (ou plusieurs) paragraphes (en TeX, on dirait que c'est du matériel en mode vertical).

<inline> est l'équivalent de <div> en HTML : c'est un morceau de paragraphe (en TeX, on dirait que c'est du matériel en mode horizontal).

Chacune de ces balises accepte un nombre incroyable d'attributs (donc il ne faut surtout pas taper cela à la main : il faudrait alors répéter les attributs d'un paragraphe à chaque nouveau paragraphe -- c'est donc XSLT qui va se charger de cette tâche fastidieuse).

En voici quelques uns.

font-size="12pt"
font-style="italic"
font-weight="bold"
font-family="Courier"

linefeed-treatment="preserve" 
white-space-collapse="false"  
white-space-treatment="preserve" 

color="green"

space-before="6pt" 
space-after="6pt"

En voici plein d'autres.

font-stretch
font-variant (small-caps)
background-color
background-image
background-repeat
background-attachment (scroll or fixed)

border-location-info
  where: location is one of before, after, start, end, top, bottom, left, or right; info is one of style, width, or color

padding-location="before|after|start|end|top|bottom|left|right"
margin-location="top|bottom|left|right"
text-align="start|end|left|right|center"
text-align-last (for last line of text in block ); values can be 
text-indent (first line)
start-indent
end-indent
wrap-option (no-wrap or wrap)
widows
orphans (determining how many lines must be left 
        at top or bottom of a page) 
break-after
break-before (when to do page or column breaks)
reference-orientation (rotated text in 90-degree increments)

On peut laisser une latitude de choix plus grande à XSL-FO, à la manière des "1ex plus 3pt minus 3pt" de LaTeX.

<fo:block
  text-indent="1em"
  font-family="sans-serif" font-size="12pt"
  space-before.minimum="2pt"
  space-before.maximum="6pt"
  space-before.optimum="4pt"
  space-after.minimum="2pt"
  space-after.maximum="6pt"
  space-after.optimum="4pt">
This handbook covers the major topics in Spanish, but is by
no means complete. 
<fo:block>

Je constate que souvent on ne précise que la valeur « optimale ».

space-before.optimum="20pt"

Certains attributs peuvent avoir plusieures valeurs.

<fo:block font-family="'New York', 'Times New Roman', serif">

On peut utiliser diverses fonctions à l'intérieur des attributs.

space-before.optimum="12pt div 2" 
font-size="inherited-property-value(font-size) div 2"

D'autres fonctions :

label-end()
body-start()

Graphiques

On trouve souvent

<external-graphic src="..\whitesml.bmp"/>

<fo:external-graphic src="file:images/catcode_logo.jpg"
                     width="99px" 
                     height="109px"/>

Mais on est sensé écrire les URLs ainsi :

<fo:external-graphic src="url('smile.gif')"
                     content-height="1em"
                     content-width="1em"
/>

Filets

(Pour ceux qui connaissent, c'est comme la commande \leaders de LaTeX.)

Une ligne horizontale

<block line-height="3px">
  <leader leader-pattern="rule" 
          leader-length.optimum="100%" 
          rule-thickness="1px"/>
</block>

Autre exemple.

<fo:block text-align="center">
<fo:leader leader-length="2in"
           leader-pattern="rule"
           alignment-baseline="middle"
           rule-thickness="0.5pt" color="black"/>
<fo:inline font="16pt ZapfDingbats"
           color="#E00000">&#x274B;</fo:inline>
<fo:leader leader-length="2in"
           leader-pattern="rule"
           alignment-baseline="middle"
           rule-thickness="0.5pt" color="black"/>
<fo:block>

On utilise aussi cela dans les tables des matières, pour faire les lignes de points de suspension.

Tableaux

Ca ressemble énormément au HTML, en plus lourd. On peut commencer par préciser la taille des colonnes, mais ce n'est pas obligatoire (du moins, d'après le standard, car certains processeurs XSL-FO peuvent exiger qu'on les spécifie).

<table>
  <table-column column-width="( 210mm - 2 * 15mm ) - 2in"/>
  <table-column column-width="1in"/>
  <table-column column-width="1in"/>

  <table-body>
    <table-row>
      <table-cell>
        <block text-align="start">
          <block font-size="19pt">
            Training material example
          </block>
          <block font-size="10pt" 
                 space-before.optimum="10pt">
            Module 1 - The context of XSLFO
          </block>
          <block font-size="10pt">
            Lesson 2 - Examples
          </block>
        </block>
      </table-cell>
      <table-cell>
        <block text-align="end">
          <external-graphic src="..\whitesml.bmp"/>
        </block>
      </table-cell>
      <table-cell>
        <block text-align="start">
          <external-graphic src="..\cranesml.bmp"/>
        </block>
      </table-cell>
    </table-row>
  </table-body>
</table>

On peut aussi avoir des cases qui s'étendent sur plusieures colonnes ou lignes.

<fo:table border="0.5pt solid black"
          text-align="center"
          border-spacing="3pt"[1]>
  <fo:table-column column-width="1in"/>
  <fo:table-column column-width="0.5in" number-columns-repeated="2"[2]/>
  <fo:table-header>[3]       
    <fo:table-row>
      <fo:table-cell padding="6pt"
                     border="1pt solid blue"
                     background-color="silver"
                     number-columns-spanned="3"[4]>
        <fo:block text-align="center" font-weight="bold">
          Header
        </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </fo:table-header>
  <fo:table-body>
    <fo:table-row>
      <fo:table-cell padding="6pt"
                     border="1pt solid blue"
                     background-color="silver"
                     number-rows-spanned="2"[5]>
        <fo:block text-align="end" font-weight="bold">
          Items:
        </fo:block>
      </fo:table-cell>
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> 1 : 1 </fo:block>
      </fo:table-cell>
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> 1 : 2 </fo:block>
      </fo:table-cell>
    </fo:table-row>
    <fo:table-row>[6]
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> 2 : 1 </fo:block>
      </fo:table-cell>
      <fo:table-cell padding="6pt" border="0.5pt solid black">
        <fo:block> 2 : 2 </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </fo:table-body>
</fo:table>

Listes

A peu près commen en HTML, mais on doit préciser le label (si ce doit être un nombre, il faut le mettre explicitement : XSL-FO ne sait pas compter). Schématiquement :

<list-block>

  <list-item>
    <list-item-label>...</>
    <list-item-body>...</>
  </list-item>

  ...
</list-block>

Exemple plus conséquent :

<list-block provisional-distance-between-starts=".43in" 
            provisional-label-separation=".1in" 
            space-before.optimum="6pt"
>
  <list-item relative-align="baseline">
    <list-item-label text-align="end" 
                     end-indent="label-end()">
      <block>-</block>
    </list-item-label>
    <list-item-body start-indent="body-start()">
      <block font-size="14pt">
        excerpts of formatting objects 
        created through the use of an XSLT stylesheet
      </block>
    </list-item-body>
  </list-item>
</list-block>

Structure de la page

Jusquà présent, nous avons simplement mis du texte dans la partie centrale de la page, mais on a aussi accès à ce qu'il y a au dessus, en dessous, à gauche et à droite.

Le vocabulaire utilisé est le suivant.

region-before = haut de la page
region-after = bas de la page
region-start = marge gauche
region-end = marge droite
region-body = haut de la page (là où on écrit)


block-progress-direction = sens dans lequel 
  on doit empiler les paragraphes (de haut en bas pour
  l'anglais, de droite à gauche pour le japonais).

inline-progress-direction = sens dans lequel 
  on doit mettre les caractères dans une ligne (de gauche
  à droite en anglais, de haut en bas en japonais).

Pour avoir des choses indépendantes de la direction de l'écriture, on n'utilisera pas left, right, top, bottom, mais

start-edge
end-edge
before-edge
after-edge

Layout-master (suite) avec hauts et bas de page

<fo:simple-page-master master-name="cover"
                       page-height="12cm"
                       page-width="12cm"
                       margin-top="0.5cm"
                       margin-bottom="0.5cm"
                       margin-left="1cm"
                       margin-right="0.5cm">
  <fo:region-body margin-top="3cm" />
</fo:simple-page-master> 

<fo:simple-page-master master-name="leftPage"
                       page-height="12cm"
                       page-width="12cm"
                       margin-left="0.5cm"
                       margin-right="1cm"
                       margin-top="0.5cm"
                       margin-bottom="0.5cm">
  <fo:region-before extent="1cm"/>
  <fo:region-after extent="1cm"/>
  <fo:region-body margin-top="1.1cm"
                  margin-bottom="1.1cm" />
</fo:simple-page-master>

<fo:simple-page-master master-name="rightPage"
                       page-height="12cm"
                       page-width="12cm"
                       margin-left="1cm"
                       margin-right="0.5cm"
                       margin-top="0.5cm"
                       margin-bottom="0.5cm">
  <fo:region-before extent="1cm"/>
  <fo:region-after extent="1cm"/>
  <fo:region-body margin-top="1.1cm"
                  margin-bottom="1.1cm" />
</fo:simple-page-master>

On peut lui dire que les pages impaires sont à droite et les paires à gauche (mais attention, il ne faut pas vouloir faire des choses plus compliquées !). (Question : le nom de l'attribut est-il master-reference ou master-name ???)

<fo:page-sequence-master master-reference="contents">
    <fo:repeatable-page-master-alternatives>
        <fo:conditional-page-master-reference
            master-name="leftPage"
            odd-or-even="even"/>
        <fo:conditional-page-master-reference
            master-name="rightPage"
            odd-or-even="odd"/>
    </fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>

Autre exemple, avec un nombre limité de pages.

<fo:page-sequence-master master-reference="example">
  <fo:repeatable-page-master-reference
  maximum-repeats="10" master-name="rightPage"/>
</fo:page-sequence-master>

Autres arguments possibles de conditional-page-master-reference

page-position 
blank-or-not-blank

Notes de bas de page

La structure est la suivante

... comme nous le savons tous
<footnote>
  <inline>(1)</inline>
  <footnote-body>
    (1) En effet...
  </footnote-body>
</footnote>

En particulier, on doit mettre le numéro de la note nous-même. Exemple plus conséquent, avec un tableau.

<fo:block>
  This text contains a footnote<fo:footnote>
    <fo:inline baseline-shift="super"
               font-size="smaller">(1)</fo:inline>
    <fo:footnote-body>
      <fo:list-block provisional-label-separation="0pt"
                     provisional-distance-between-starts="18pt"
                     space-after.optimum="6pt">
        <fo:list-item>
          <fo:list-item-label end-indent="label-end()">
            <fo:block>(1)</fo:block>
          </fo:list-item-label>
          <fo:list-item-body start-indent="body-start()">
            <fo:block>Footnote text</fo:block>
          </fo:list-item-body>
        </fo:list-item>
      </fo:list-block>
    <fo:footnote-body>
  </fo:footnote>
  after the word "footnote".
</fo:block>

Marques

On peut récupérer la première marque rencontr&e sur la page, ou la dernière (en TeX, on peut aussi récupérer la dernière rencontrée quand on arrive au début de la page).

Récupérer une marque :

<fo:static-content flow-name="xsl-region-before">
  <fo:block text-align="center">
    <fo:retrieve-marker retrieve-class-name="division"/>
  </fo:block>
</fo:static-content>

Déposer une marque :

<fo:block>
  <fo:marker marker-class-name="division">
    Introduction
  </fo:marker>
  <fo:block font-weight="bold" text-align="center">
    1. Introduction
  </fo:block>
  <fo:block text-indent="0.5in">
    Let me introduce you to something ?
    ? ? ?
  </fo:block>
</fo:block>

Exemple avec plusieures marques (par exemple pour un dictionnaire).

A FAIRE

Haut et bas de page

Une page avec un haut et un bas de page. On utilise <static-contents> pour le haut et le bas de page et <flow> pour les pages.

<fo:page-sequence master-name="contents" 
                  initial-page-number="2">
  <fo:static-content flow-name="xsl-region-before">
    <fo:block font-family="Helvetica" font-size="10pt"
        text-align="center">
        Spanish Review Handbook
    </fo:block>
  </fo:static-content>

  <fo:static-content flow-name="xsl-region-after">
    <fo:block font-family="Helvetica" font-size="10pt"
        text-align="center">
        P&#225;gina <fo:page-number />
    </fo:block>
  </fo:static-content>

  <fo:flow flow-name="xsl-region-body">
    <fo:block font-size="14pt">
        Watch this space!
    </fo:block>
  </fo:flow>
</fo:page-sequence>

XSLT

Exemple de fichier XSLT pour transformer du HTML en XSL-FO.

<xsl:template match="h3">
  <fo:block font-size="14pt" font-family="sans-serif"
      font-weight="bold" color="green"
      space-before="6pt" space-after="6pt">
  <xsl:apply-templates/>
  </fo:block>
</xsl:template>

<xsl:template match="p">
  <fo:block
      text-indent="1em"
      font-family="sans-serif" font-size="12pt"
      space-before.minimum="2pt"
      space-before.maximum="6pt"
      space-before.optimum="4pt"
      space-after.minimum="2pt"
      space-after.maximum="6pt"
      space-after.optimum="4pt">
  <xsl:apply-templates/>
  </fo:block>
</xsl:template>

Références

Si on veut faire référence à une section ou à un théorème, il faut mettre le numéro en dur.

On peut aussi faire référence à la page sur laquelle se trouve un objet (il suffit qu'on ait donné un nom à celui-ci, à l'aide de l'attribut id).

<fo:external-graphic id="smiley" src="url('smile.gif')"/>
...
As shown on the "Smiling Face" diagram
(see page <fo:page-number-citation ref-id="smiley"/>),
...

Le numéro de la page courrante est dans <fo:page-number/>. Cela s'utilise en particulier dans les hauts ou bas de page.

<fo:static-content flow-name="xsl-region-before">
  <fo:block text-align="end">Page <fo:page-number/></fo:block>
</fo:static-content>

Filet horizontal pour séparer les hauts de page

<fo:layout-master-set>
  <fo:simple-page-master master-name="my-page">
    <fo:region-body margin="1.5in 1in"/>
    <fo:region-before extent="1.5in"
                      padding="6pt 1in"
                      border-bottom="0.5pt silver solid"
                      display-align="after"/>
  </fo:simple-page-master>
</fo:layout-master-set>

Marges

Exactement comme on a tracé un filet horizontal pour séparer le haut ou le bas de page du texte (\headrule ou \footrule, en LaTeX), on peut tracer la marge gauche ou droite.

<fo:simple-page-master master-name="even-page">
  ...
  <fo:region-start extent="1.5in"
                   region-name="my-left-sidebar"
                   reference-orientation="90"   
                   padding="6pt 1in"
                   border-right="0.5pt silver solid"
                   display-align="after"/>
  ...
</fo:simple-page-master>

SVG

On peut inclure des images en SVG (c'est un format de dessin vectoriel, en XML), soit dans des fichiers séparés (on l'a déjà vu), soit directeent dans le corps du document.

<fo:block>
  <fo:instream-foreign-object>
    <svg:svg width="400pt" height="200pt">
      <svg:rect style="fill:none;stroke:blue" 
                x="20pt" y="20pt" 
                width="100pt" height="100pt"/>
      <svg:line x1="20pt" y1="20pt" x2="120pt" y2="120pt"/>
      <svg:line x1="120pt" y1="20pt" x2="20pt" y2="120pt"/>
      <svg:text x="20pt" y="150pt">Hello SVG!</svg:text>
    </svg:svg>
  </fo:instream-foreign-object></fo:block>
</fo:block>

Césure

Eh oui, même si c'est peu utilisé (d'après les exemples que l'on trouve sur Internet), on peut demander à XSL-FO de couper les mots.

<fo:block font-size="12pt" 
          font-family="sans-serif" 
          line-height="15pt"
           space-after.optimum="3pt"
          text-align="justify"
          language="en"
          country="US"
          hyphenate="true"
          hyphenation-push-character-count="2"
          hyphenation-remain-character-count="2"
>

Table des matières

On utilise des <leader>s pour les lignes de points de suspension.

<fo:table>
  <fo:table-column column-width="1cm"/>
  <fo:table-column column-width="14.2cm"/>
  <fo:table-column column-width="0.3cm"/>

  <fo:table-body font-size="12pt" font-family="sans-serif">

    <fo:table-row line-height="12pt">
      <fo:table-cell>
        <fo:block text-align="end">A) </fo:block>
      </fo:table-cell>

      <fo:table-cell>
        <fo:block text-align="start">
          This is some longer sample text
          <fo:leader leader-pattern="dots" 
                     leader-pattern-width="8pt"
                     leader-alignment="reference-area"
                     />
        </fo:block>
      </fo:table-cell>
      <fo:table-cell>
        <fo:block text-align="end">1</fo:block>
      </fo:table-cell>
    </fo:table-row>

  ...
  </fo:table-body>
</fo:table>

Liens

Liens externes.

<fo:inline font-style="italic" 
           font-family="serif">
  <fo:basic-link color="blue" 
                 external-destination="http://xml.apache.org/fop">
    http://xml.apache.org/fop
  </fo:basic-link>
</fo:inline>

Lien interne : on donne un nom à un endroit du document,

<fo:block ...
          id="block1">

et on y réfère ainsi

<fo:basic-link internal-destination="block1" 
               color="blue">
  formatting object
</fo:basic-link>

Colonnes

Si on veut du texte en plusieurs colonnes, il faut le définir dans les page-master (donc ce sera nécessairement pour des pages entières).

<fo:simple-page-master master-name="first"
                       page-height="11in" 
                       page-width="8.5in"
                       margin-top="1in" 
                       margin-bottom="1in" 
                       margin-left="0.75in" 
                       margin-right="0.75in">
  <fo:region-body margin-top="1in" 
                  margin-bottom="1in"
                  column-count="2" 
                  column-gap="0.25in"/>
  <fo:region-before extent="1in"/>
  <fo:region-after extent="1in"/>
</fo:simple-page-master>

Dans une page en plusieures colonnes, on peut demander à un bloc de s'étendre sur plusieures colonnes, avec l'attribut span (par exemple, pour mettre le titre et un résumé dans un article en deux colonnes).

<fo:block font-size="12pt" 
          font-family="sans-serif" 
          line-height="15pt"
          space-after.optimum="3pt"
          text-align="start"
          background-color="yellow"
          span="all">

Autres exemples

Voir les exemples qui viennent avec FOP.

locate .fo | grep '\.fo$'

Vincent Zoonekynd
<zoonek@math.jussieu.fr>
latest modification on jeu jui 11 16:13:57 CEST 2002