You are on page 1of 287

Publication web avec XML/XSLT

Bernd Amann et Philippe Rigaux

August 6, 2001
2
Contents

1 Introduction à XML et XSLT 13


1.1 L’application et ses besoins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.2 XML, format universel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.2.1 Qu’est-ce que XML ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.2.2 Structuration avec XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.2.3 Documents XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3 Publication de données avec XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.3.1 Site web (HTML) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.3.2 Site WAP (WML) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.3.3 Document papier (PDF) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.4 Échange et intégration de données en XML . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.4.1 Exemple : Le Site www.sallesenligne.com . . . . . . . . . . . . . . . . . . . . . . 42
1.4.2 Description de la structure d’un document XML . . . . . . . . . . . . . . . . . . 43
1.4.3 Transformation et échange de données . . . . . . . . . . . . . . . . . . . . . . . . 44
1.4.4 Un moteur de recherche XML/XSLT . . . . . . . . . . . . . . . . . . . . . . . . 45
1.4.5 Intégration dynamique de fragments XML . . . . . . . . . . . . . . . . . . . . . . 46
1.5 Comment lire la suite de ce livre ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

2 Documents XML : structure et navigation 55


2.1 La syntaxe XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.1.1 Déclaration XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
2.1.2 Déclaration du type de document et des entités . . . . . . . . . . . . . . . . . . . 57
2.1.3 Commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.1.4 Instructions de traitement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.1.5 Éléments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
2.1.6 Attributs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
2.1.7 Espaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.1.8 Sections CDATA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.1.9 Références d’entités . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.1.10 Balises, données caractères et valeur textuelle . . . . . . . . . . . . . . . . . . . . 62
2.2 Le modèle DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.2.1 Types de nœuds DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.2.2 Interface DOMString . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
2.2.3 Interfaces NodeList et NamedNodeMap . . . . . . . . . . . . . . . . . . . . . . 66
2.2.4 Interface Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
2.2.5 Interface Document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
2.2.6 Interfaces Element et Attr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
2.2.7 Interfaces DocumentType, Entity et EntityReference . . . . . . . . . . . . . . . 74
2.3 Du document sérialisé à l’arbre DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.3.1 Construction d’un arbre DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
2.3.2 Traitement des espaces pendant la construction . . . . . . . . . . . . . . . . . . . 78
2.3.3 Deux fonctions de navigation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

3
4 CONTENTS

2.4 Le langage XPath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81


2.4.1 Représentation XPath d’un document XML . . . . . . . . . . . . . . . . . . . . . 82
2.4.2 Expressions XPath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
2.4.3 Les axes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
2.4.4 Les filtres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
2.4.5 Prédicats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
2.4.6 Types et opérations XPath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
2.4.7 Exemples d’expressions XPath . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

3 XSLT 109
3.1 Programmes XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
3.1.1 Structure d’un programme XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . 111
3.1.2 Modularité : xsl:import et xsl:include . . . . . . . . . . . . . . . . . . . 115
3.1.3 Application d’un programme XSLT . . . . . . . . . . . . . . . . . . . . . . . . . 117
3.2 Les règles XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
3.2.1 Les patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
3.2.2 Règles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
3.2.3 Déclenchement de règles avec xsl:apply-templates . . . . . . . . . . . . . 124
3.2.4 Sélection des règles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
3.2.5 Appel de règle avec xsl:call-template . . . . . . . . . . . . . . . . . . . . 131
3.2.6 Paramètres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
3.3 Instructions de contrôle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
3.3.1 Tests : xsl:if et xsl:choose . . . . . . . . . . . . . . . . . . . . . . . . . . 134
3.3.2 Boucles : xsl:for-each . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
3.3.3 Variables : xsl:variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
3.3.4 Tri : xsl:sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
3.3.5 Itérations par récursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
3.4 Évaluation d’un programme XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

4 Production de documents XML 153


4.1 Définition de Types de Documents : DTD . . . . . . . . . . . . . . . . . . . . . . . . . . 154
4.1.1 Pourquoi définir une DTD ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
4.1.2 Entités . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
4.1.3 Éléments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
4.1.4 Attributs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
4.1.5 DTD et XML Schéma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
4.2 Site Web: HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
4.2.1 HTML et XHTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
4.2.2 DTD XHTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
4.2.3 Génération de pages HTML: xsl:output . . . . . . . . . . . . . . . . . . . . 170
4.2.4 Transformation d’une page XML . . . . . . . . . . . . . . . . . . . . . . . . . . 171
4.2.5 Création de liens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
4.2.6 XML/XSLT: une solution du problème des liens cassés . . . . . . . . . . . . . . . 175
4.2.7 Intégration de pages XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
4.3 Présentations multimédia: SMIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
4.3.1 SMIL par un exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
4.3.2 DTD SMIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
4.3.3 Génération de présentations SMIL . . . . . . . . . . . . . . . . . . . . . . . . . . 187
4.4 Traitement de texte dans XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
4.4.1 xsl:preserve-space et xsl:strip-space . . . . . . . . . . . . . . . . 195
4.4.2 Génération de texte : xsl:text . . . . . . . . . . . . . . . . . . . . . . . . . . 197
4.4.3 Sérialisation du résultat : xsl:output . . . . . . . . . . . . . . . . . . . . . . . 197
4.5 RSS et RDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
CONTENTS 5

5 Production de documents papier 199

6 Échange et intégration 201

7 Publication de bases de données 203


7.1 Bases de données et XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
7.1.1 Quelques rappels sur les BD relationnelles . . . . . . . . . . . . . . . . . . . . . 204
7.1.2 Documents orientés « texte » et documents orientés « données » . . . . . . . . . . 207
7.1.3 Transformation d’une base de données en XML . . . . . . . . . . . . . . . . . . . 209
7.1.4 Création de la DTD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
7.2 Architectures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
7.2.1 Une classe Java d’exportation XML . . . . . . . . . . . . . . . . . . . . . . . . . 218
7.2.2 Architecture Servlet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
7.2.3 Utilisation des Java Server Pages . . . . . . . . . . . . . . . . . . . . . . . . . . 225
7.3 XML dynamique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
7.3.1 XSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
7.3.2 XSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
7.4 Perspectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

8 Un serveur de publication XML 241

A L’environnement XML/Apache 243


A.1 Le projet XML/Apache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
A.2 Xalan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
A.2.1 Préliminaire : le Java Development Kit . . . . . . . . . . . . . . . . . . . . . . . 245
A.2.2 Installation de Xalan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
A.2.3 Test d’expressions XPath avec ApplyXPath . . . . . . . . . . . . . . . . . . . . . 245
A.2.4 Effectuer des transformations XSLT avec Xalan . . . . . . . . . . . . . . . . . . . 246
A.2.5 Utiliser Xalan en Applet ou en Servlet . . . . . . . . . . . . . . . . . . . . . . . . 247
A.3 Cocoon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
A.3.1 Tomcat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
A.3.2 Cocoon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
A.4 Intégration Apache/Tomcat/Cocoon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
A.4.1 Compilateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
A.4.2 Apache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
A.4.3 PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
A.4.4 Lien Apache/Tomcat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
A.4.5 Et Cocoon ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252

B Référence XPath/XSLT 253


B.1 Éléments XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
B.2 Fonctions XPath/XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
6 CONTENTS
Avant-propos

Ce livre traite de la publication de données, dans un environnement web, à partir de documents XML et
de programmes (ou « feuilles de styles ») XSLT. Le terme de publication employé ici doit être pris dans
un sens très général. Il recouvre toutes les transformations visant à mettre en forme un contenu afin de
le rendre accessible via un ou plusieurs médias de communication. Cette définition très souple s’applique
bien entendu à la publication web prise dans son acception la plus classique : rendre disponible un contenu
au format HTML sur une serveur connecté à l’Internet. Mais elle recouvre également de très nombreux
types de publications que nous aurons l’occasion d’aborder dans ce livre : publication WAP pour téléphones
mobiles, mise en forme pour une impression papier, présentations interactives multimédia, etc.
Il existe plusieurs approches pour la publication de données. Une première solution est de gérer les
données séparément dans un format adapté à chaque type de publication, avec des inconvénients évidents
dus à la duplication des informations. Un exemple très concret de ces limitations est donné par le Web, qui
est encore essentiellement constitué de pages HTML. Si un contenu est placé dans une telle page, il pourra
certes être affiché correctement dans un navigateur, mais il deviendra également impropre à être repris et
exploité dans un autre contexte (document papier, système de base de données, ...). Ce qui est vrai pour
HTML l’est également, à des degrés divers, pour toute autre représentation.
Il est donc très rapidement devenu évident qu’il était souhaitable de dissocier présentation et contenu.
Parmi les très nombreuses raisons justifiant ce principe, on peut citer :

la volonté de réutiliser un même contenu dans différents contextes ;

l’impossibilité de réaliser une application complexe et interactive avec HTML ;

la nécessité de baser la présentation sur une « maquette » définissant une mise en forme applicable à
de nombreuses occurrences de contenu (exemple typique des maquettes de quotidiens appliquées à
un contenu qui change tous les jours) ;

enfin, la lourdeur d’une gestion de sites web statiques : les webmestres doivent en effet être compé-
tents en graphisme, en HTML, en JavaScript, et savoir faire des choix relatifs au système d’information
de leur entreprise.

Une solution maintenant largement adoptée est de s’appuyer sur un serveur de données centralisant
l’information, et d’écrire pour chaque type de publication une application séparée qui utilise des outils
adaptés. Pour reprendre le domaine de la publication web, la plupart des sites s’appuient maintenant sur
un système de gestion de bases de données (SGBD), en extraient des informations avec SQL, et produisent
une page HTML intégrant ces informations avec un langage comme PHP, ASP ou les Java Server Pages
(JSP). La complexité des applications web peut varier du transfert simple de résultats de requêtes SQL
et la réservation de billets d’avion avec des mises à jour sur différentes bases de données. Cette solution
résout les principaux problèmes évoqués ci-dessus, et notamment rétablit une certaine indépendance entre
contenu et présentation. En revanche le simple énoncé des compétences nécessaires montre qu’elles sont
plutôt alourdies : ils faut maintenant non seulement maîtriser les langages propres au web, comme HTML
et JavaScript, mais également disposer de connaissances de graphiste, de programmeur, de concepteur et
administrateur de bases de données.
Un des arguments du présent livre est de montrer que l’utilisation de XML en lieu et place de HTML
permet de mettre en place des mécanismes beaucoup plus puissants, et notamment d’obtenir, à partir d’un

7
8 CONTENTS

même contenu, à peu près n’importe quel format de sortie (HTML, XML, PDF, WML, LaTeX, ...). Un
document XML est beaucoup plus souple, flexible et maniable qu’une base de données dont la mise en
œuvre suppose des compétences techniques assez avancées. De plus la mise en forme de l’information à
partir d’un document XML est grandement facilitée par l’existence d’un langage spécialisé : XSLT.

XSLT
XSLT (eXtensible Stylesheet Language Transformations) est un langage permettant d’extraire et de restruc-
turer des informations présentes dans un document XML. Cette restructuration peut être faite en HTML, si
on vise à produire un site au sens classique du terme, mais un programme XSLT peut également fournir,
pour tout ou partie des informations, une version imprimable en PDF, voire Word/RTF. On peut également,
dynamiquement, adapter la présentation au client qui accède au site, comme l’illustre le cas typique de
deux versions, WML et HTML, d’un site web.
La publication avec XSLT va au-delà de la seule mise en forme destinée à une consultation statique. On
peut utiliser XSLT dans une optique d’échange et d’intégration de données. Avec XML il est possible en
effet de rendre publiques sur le Web, en passant par une transformation XSLT appropriée, des informations
qui peuvent être reprises et traitées par d’autres. On peut envisager, par exemple, un système coopératif
où il n’y a plus besoin, pour créer un site web, de devoir gérer soi-même la base de données, le serveur, la
sécurité, la présentation. Le contenu est fourni à quelqu’un sous forme de documents XML, dans le format
qu’il attend, et ce quelqu’un se charge de l’intégration avec d’autres documents et la mise en forme, HTML
ou autre. Autre application possible de cette capacité d’échanges de données : l’indexation par un moteur
de recherche, dont le rôle est de collecter les informations sur un thème donné, et d’offrir des modes de
recherches sophistiqués pour ces informations.
XML rend possible la représentation de l’information dans un format universel, reconnu sur tous les
systèmes, et adapté à une répartition sur le Web. En utilisant des feuilles de style XSLT on peut extraire,
reformater, et définir la présentation adéquate pour ces informations XML. On résout, en d’autres termes,
un problème très courant : comment éviter de dupliquer des informations pour s’adapter soit à une applica-
tion donnée, soit au type particulier de publication/communication (papier, écran, transparent, email) que
l’on souhaite utiliser. Il devient possible d’imaginer un système d’information véritablement réparti sur un
réseau, dans lequel les nœuds peuvent s’échanger des informations et se spécialiser chacun dans un type
de service particulier.

Objectifs et contenu de ce livre


Le présent livre est principalement destiné à couvrir de manière complète, progressive et détaillée, le lan-
gage XSLT et ses applications à la transformation de documents XML. Cet axe principal est complété par
la recherche d’une mise en perspective du pourquoi et du comment de telles transformations. Autrement
dit nous avons cherché, autant que les limites fixées par la clarté de la présentation le permettaient, à définir
un contexte d’utilisation réaliste pour motiver le recours à XSLT et montrer ses apports.
Au cours des différents chapitres, nous envisageons donc différents « cas d’utilisation » de XML. Ce
choix nous amène, en pratique, à aller bien plus loin que la simple création de pages HTML, comme le
 etEn ,particulier
terme de « publication web » pourrait à tort le laisser croire. nous développons les aspects
relatifs aux échanges de données entre deux applications  avec des transformations XSLT prenant
en entrée un document XML reconnu par l’application , et produisant en sortie un autre document XML
reconnu par l’application  . Ces échanges constituent un aspect essentiel du rôle de XML dans des ap-
plications réparties, et XSLT, par sa capacité à transformer automatiquement les informations structurées
avec XML, y tient une place importante.
Un dernier thème abordé dans ce livre est l’intégration de données au format XML, préalable à une
transformation. Le langage XML peut en effet être vu comme un moyen pour unifier dans un format
cohérent des informations hétérogènes issues de sources diverses. Nous consacrons en particulier une
place importante à la création « à la volée » de documents XML à partir d’une base de données, suivie
d’une transformation XSLT. Une telle aproche offre une alternative intéressante à une solution basée sur
CONTENTS 9

un langage de script intégré aux pages HTML (PHP ou JSP) car elle permet une séparation des points
de vues et donc des compétences : celui qui intègre les informations en XML, en utilisant des langages
comme Java et SQL, peut être différent de celui qui publie ces informations à destination de différents
médias, en s’appuyant sur des connaissances XSLT et – par exemple – HTML. En incluant dans ce livre
des développements techniques sur une chaîne de publication complexe allant d’une base de données à un
document final au format PDF ou HTML, en passant par une intégration XML, nous pensons proposer un
panorama complet de ce que peut être un environnement de publication web construit sur XSLT.
Afin de donner des illustrations concrètes aux concepts évoqués ci-dessus, une partie importante des
exemples donnés dans ce livre est consacrée à des applications simplifiées, mais réalistes, de la manipula-
tion de documents XML avec XSLT. Nous invitons le lecteur à utiliser nos deux maquettes, disponibles sur
le site du livre, et à récuperer, puis modifier le code de ces exemples.

Les exemples
Sauf indication contraire, tous nos exemples sont conformes aux documents normatifs publiés par le World
Wide Web Consortium et disponibles sur le site http://www.w3c.org. Il devraient donc fonctionner avec
tous les serveurs d’application ou clients web dotés d’un processeur XSLT. Nous utilisons cependant, à
titre d’outil de référence, l’environnement Tomcat/Cocoon proposé par la fondation Apache et librement
disponible sur le site http://xml.apache.org. Nous proposons dans l’annexe A un guide d’installation et
de configuration de ces outils, sous Linux ou Windows, qui vous permettront de tester nos exemples ou
d’effectuer vos propres investigations sans investir dans un produit commercial.
Dans les cas où nous devons faire appel à des fonctionnalités non standardisées, nous avons choisi, par
souci de cohérence, de faire encore appel aux solutions proposées dans Cocoon, en essayant cependant
de mettre en valeur les aspects génériques qui se retrouvent dans la plupart des produits. C’est le cas
notamment pour la création dynamique de documents XML à partir d’une base de données pour laquelle
nos exemples sont basés sur XSP, une technique d’intégration de code java dans du XML que l’on retrouve
dans Cocoon, dans AxKit (www.axkit.org), et qui s’inspire fortement des Java Server Pages.
Vous pouvez récupérer tout le code de nos exemples sur le site du livre, afin de l’utiliser, le consulter
ou le modifier pour vos propres besoins.

http://cortes.cnam.fr:8080/XBOOK

Audience et pré-requis
Ce livre est destiné à tous ceux qui s’interrogent sur les applications liées à XML, et plus particulièrement
sur la validité d’une aproche basée sur XML pour la mise à disposition de données sur le Web. Nous
pensons que ce public recouvre plus spécifiquement les types de lecteur suivants :

1. les architectes d’applications envisageant d’utiliser XML comme format d’échange de données entre
différentes applications où comme support de base de leur système d’information ;

2. les chefs de projet qui doivent intégrer dans la conception de leurs produits un ou plusieurs modules
de communications de données via le Web ;

3. les développeurs d’application à qui ce livre donne les indications nécessaires pour produire une
présentation uniforme de leur site fondée sur l’utilisation de feuilles de style.

4. enfin toute personne cherchant une présentation pratique et complète des nouvelles méthodologies
de publications sur le web.

Nous supposons que le lecteur dispose par ailleurs d’une connaissance minimale des sujets suivants :

1. les bases des applications web, incluant HTML, la gestion de formulaires, quelques notions sur la
programmation CGI et les grandes lignes d’une architecture web ;
10 CONTENTS

2. les principes des bases de données relationnelles (notamment SQL) ;

3. un peu de programmation Java.

Il existe de très nombreux livres qui traitent des aspects ci-dessus. Nous recommandons par exemple
HTML : The Definitive Guide, Java in a Nutshell et (?) tous aux Éditions O’Reilly.

Organisation du livre
Le livre suit une double démarche de présentation des aspects les plus simples, puis, progressivement,
les plus complexes du langage XSLT, et d’illustration des mécanismes de ce langage à des cas concrets
d’utilisation. Nous avons choisi de commencer par un chapitre introductif en forme d’étude de cas qui pro-
pose, sur une application de type « Officiel des spectacles » adaptée au web, une déclinaison des différents
thèmes couverts. La lecture préalable de ce chapitre est probablement indispensable, au moins pour les
néophytes.
Les chapitres suivants traitent de manière plus systématique du couple XML/XSLT en reprenant de
manière approfondie les aspects présentés de manière délibérement intuitive dans le premier chapitre. Le
fil conducteur est cette fois une application publiant sous différentes formes les programmes d’organismes
de formation (universités, instituts techniques comme le Cnam, etc), mais nous utilisons également parfois
des exemples plus abstraits quand il faut privilégier l’explication des mécanismes XSLT.
Dans la quasi-totalité du livre nous essayons d’être indépendant d’un outil ou type d’outil particulier
afin de respecter le caractère normalisé de XML/XSLT. Le dernier chapitre propose cependant une étude de
cas détaillée montrant, pour un type d’environnement particulier, en l’occurrence la suite Apache/Tomcat/Coocon,
la réalisation d’un site web.

Plan détaillé
Une introduction à XML/XSLT. Ce premier chapitre fournit une présentation relativement courte de la
problématique d’ensemble abordée par le livre. Il peut se lire indépendamment du reste du livre, et
propose des arguments et des exemples simples, ainsi qu’une introduction intuitive des mécanismes
qui sont à la base des transformations XSLT.
Les apports de XML/XSLT sont successivement présentés, tous étant, dans les chapitres suivants,
repris et développés avec des descriptions techniques approfondies.

Documents XML. Présentation de la syntaxe XML (éléments, attributs, liens, entités..) ;

Bases de XSLT. Le cœur du sujet : à partir d’un ou plusieurs documents décrivant des formations, on
explore les principales possibilités de XSLT.

DTD. XSLT peut être vu comme un outil permettant de transformer un document XML représentant un
contenu indépendamment de toute application, vers un autre document XML, spécialisé, et dédié à
un application particulière (par exemple un navigateur web).
Plusieurs spécialisations sont présentées dans ce chapitre :

1. XHTML ;
2. RSS ;
3. WML ;
4. (?)
CONTENTS 11

Conventions
Nous utilisons les conventions typographiques suivantes :

La police à chasse constante s’applique à tous les exemples de code, de commande et de


programme.
La police à chasse constante en italiques est utilisée pour distinguer les paramètres
des mot-clé dans la syntaxe des commandes.
Le texte en italiques est utilisé pour les URL, les noms de fichiers, de programmes et de répertoires
cités dans le texte (autrement dit, quand ils ne sont pas inclus dans du code). L’italique est également
utilisé pour les termes étrangers et pour la mise en valeur de mots ou d’expressions importants.

Les commandes UNIX sont précédées de %. Par exemple :


% ls -l
De plus, nous adopterons également des conventions précises pour nommer les fichiers, les variables,
les fonctions, les noms de tables, etc. Ces conventions font partie d’une stratégie générale de qualité du
développement et seront présentées le moment venu.

Remerciements
Irini Fundulaki, Cédric Dumouza, Laurent Mignet, Michel Scholl, Luc Ségoufin, Dan Vodislav
12 CONTENTS
Chapter 1

Introduction à XML et XSLT

Sommaire
1.1 L’application et ses besoins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.2 XML, format universel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.2.1 Qu’est-ce que XML ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.2.2 Structuration avec XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.2.3 Documents XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3 Publication de données avec XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.3.1 Site web (HTML) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.3.2 Site WAP (WML) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.3.3 Document papier (PDF) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.4 Échange et intégration de données en XML . . . . . . . . . . . . . . . . . . . . . . 42
1.4.1 Exemple : Le Site www.sallesenligne.com . . . . . . . . . . . . . . . . . . . . 42
1.4.2 Description de la structure d’un document XML . . . . . . . . . . . . . . . . . 43
1.4.3 Transformation et échange de données . . . . . . . . . . . . . . . . . . . . . . 44
1.4.4 Un moteur de recherche XML/XSLT . . . . . . . . . . . . . . . . . . . . . . . 45
1.4.5 Intégration dynamique de fragments XML . . . . . . . . . . . . . . . . . . . . 46
1.5 Comment lire la suite de ce livre ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Ce chapitre a pour ambition de proposer au lecteur une présentation intuitive des principales caractéris-
tiques de XML, ainsi qu’un tour d’horizon de ses apports en terme d’intégration, d’échange et de publi-
cation de données. Nous évitons délibérément, à ce stade, toute discussion technique détaillée, l’objectif
étant plutôt de dresser un panorama des contextes d’utilisation de XML et de son association avec XSLT,
en vue de convaincre le lecteur de l’intérêt de recourir à ces langages.
Nous prenons comme fil conducteur, dans ce chapitre, une application simple qui nous permettra de
décliner des exemples d’utilisation de XML. Cette application consiste à fournir, sous les formes les plus
variées, les informations relatives aux films à l’affiche en France, comprenant un descriptif de chaque film,
et les cinémas, salles et séances où ces films sont projetés. Nous supposons de plus que ces informations
sont disponibles en différents points du réseau Internet. Nos exemples montreront comment XML permet
d’échanger ces informations, de les intégrer, et enfin de les publier sur les supports les plus divers.
L’accent est mis bien entendu sur l’association de XML avec le langage de transformation XSLT, mais
nous discutons également, plus brièvement, des interfaces de programmation, ainsi que des rapports entre
XML et les bases de données relationnelles. Nous souhaitons que ce premier chapitre permette, sans inve-
stir dans une étude technique approfondie, de dégager clairement la place de XML au sein des nombreux
outils, langages et techniques qui constituent un système d’information orienté vers la publication ou les
échanges de données sur le Web. Pour tous les aspects qui ne sont, techniquement parlant, qu’esquissés
dans cette introduction, nous indiquons finalement le chapitre ou la partie du livre où le lecteur trouvera un
développement complet.

13
14 CHAPTER 1. INTRODUCTION À XML ET XSLT

1.1 L’application et ses besoins


Décrivons tout d’abord l’application (simplifiée). L’objectif général consiste, pour un cinéma, à diffuser le
plus largement possible l’information relative à ses salles, avec les films qui y sont diffusés et les horaires
des séances. Nous prendrons comme exemple principal le cas du cinéma L’Épée de bois qui propose deux
films :

Le film Alien, de Ridley Scott, projeté dans la salle 1 avec trois séances dans la journée ;

le film Vertigo, d’Alfred Hitchcock, projeté dans la salle 2 avec une seule séance à 22 heures.

L’Épée de bois souhaite bien entendu rendre ces informations disponibles sur son site web. Mais il
envisage également le cas de cinéphiles munis d’un téléphone mobile, susceptibles de consulter les séances
via une application WAP. Enfin le programme des salles doit être affiché à l’entrée du cinéma, distribué dans
l’environnement proche (cafés, librairies) sous forme de tracts, et transmis à un magazine d’informations
sur les spectacles.
Pour tous ces modes de diffusion, la solution traditionnelle, basée sur des outils adaptés à chaque cas,
implique de resaisir l’information, avec des risques d’erreur multipliés et une perte de temps inutile. Par
exemple la plaquette serait stockée au format propriétaire d’un traitement de mise en page, chaque site web
placerait le contenu dans des fichiers HTML, le magazine conserverait ce même contenu dans une base de
données, et ainsi de suite.
Supposons de plus qu’un site, www.sallesenligne.com, propose de référencer toutes les séances de tous
les cinémas en France, et offre aux internautes un service de recherche et d’indexation. Bien entendu cela
suppose que chaque cinéma lui fournisse, dans un format donné, les informations sur ces propres séances,
ce qui implique pour l’Épée de bois un travail supplémentaire de saisie et mise à jour.
Enfin on supporsera qu’un dossier complet sur chaque film (acteurs, résumé) est disponible dans une
base de données interrogeable sur le web, et que chaque journal tenant une rubrique « cinéma » offre un
accès sur le Web aux critiques parues sur les films. Il serait souhaitable que cette information puisse être
intégrée au programme pour le rendre encore plus attrayant.
En résumé, la problématique est double : d’une part il faut être en mesure de fournir une même infor-
mation – le programme de cinéma – sous les formes les plus variées, d’autre part il faut « récupérer » tout
ce qui peut enrichir cette information, et intégrer le tout dans un format cohérent. Nous allons explorer
dans la suite de ce chapitre comment XML/XSLT répond à ce double besoin.

1.2 XML, format universel


XML constitue un moyen de rendre un même contenu accessible à plusieurs applications. Considérons le
cas des informations propres au cinéma, à savoir son nom, son adresse et la station de métro la plus proche :

L’Epée de bois, 100 rue Mouffetard, métro Censier-Daubenton

Ces quelques informations constituent un contenu susceptible d’apparaître sur de nombreux supports
différents : des affiches de film, un magazine des spectacles à Paris, de très nombreux sites web, des
plaquettes commerciales, un téléphone portable, etc. Dans un contexte cloisonné où ces différents supports
sont produits indépendamment les uns des autres, ce contenu est habituellement dupliqué autant de fois
que nécessaire, et associé à un format propre à chaque support.
Dans la mesure où les applications gérant ce contenu ne communiquent pas, cette duplication et cette
hétérogénéité des formats, adaptés à chaque type d’exploitation de ce contenu, sont légitimes. Si, en
revanche, on se place dans un environnement connecté au réseau et favorisant les échanges d’information,
duplication et hétérogénéité deviennent beaucoup moins justifiables. La duplication induit un coût, de
transformation ou de stockage, et l’hétérogénéité peut rendre inaccessible ou inexploitable une information
pourtant présente.
1.2. XML, FORMAT UNIVERSEL 15

1.2.1 Qu’est-ce que XML ?


XML est donc d’abord destiné à représenter des contenus indépendamment de toute application. Il s’appuie
pour cela sur la combinaison de plusieurs principes simples et généraux pour la représentation et l’échange
d’information. Voici une représentation XML de notre cinéma :

Exemple 1 Représentation XML d’un cinéma

<?xml version="1.0" encoding="ISO-8859-1"?><CINEMA><NOM>Epée de Bois


</NOM><ADRESSE>100, rue Mouffetard</ADRESSE><METRO>Censier-Daubenton
</METRO></CINEMA>

Une information codée en XML est donc simplement représentée sous forme d’une chaîne de carac-
tères. Cette chaîne débute obligatoirement par une déclaration XML :

<?xml version="1.0" encoding="ISO-8859-1"?>

qui indique que la chaîne contient des informations codées avec la version 1.0 de XML, et que le jeu de
caractères utilisé est conforme à la norme ISO-8859 définie par l’Organisation Internationale de Standard-
isation (ISO) pour les langues latines. Cette norme est adaptée à l’usage du français puisqu’elle permet les
lettres accentuées commme le ’é’ dans le mot Epée.

1.2.2 Structuration avec XML


La représentation sous forme de chaîne de caractères n’exclut pas la structuration de l’information. Par
exemple, la chaîne

« L’adresse du cinéma Épée de Bois est 100, rue Mouffetard


et se trouve près de la station de métro Censier-Daubenton »

contient la même information que la chaîne XML précédente, mais est difficilement exploitable par un
outil informatique car la structure de la phrase est cachée. Cette structure est marquée, en XML, par des
balises 1 encadrées par les symboles  et  . Les balises  CINEMA  ,  NOM  ,  /NOM  ,  ADRESSE  ,
 /ADRESSE  ,  METRO  ,  /METRO  et  /CINEMA  décomposent ainsi le contenu en trois parties
textuelles :

Epée de Bois ;

100, rue Mouffetard ;

Censier-Daubenton.

On peut constater que les balises forment des parenthèses autour de fragments de la chaîne XML.
On trouve dans notre exemple les « parenthèses »  CINEMA  . . .  /CINEMA  ,  NOM  . . .  /NOM  ,
 ADRESSE  . . .  /ADRESSE  ,  METRO  . . .  /METRO  . Dans ces paires de balises, la première est
appelé balise ouvrante et la deuxième la balise fermante. Voici la terminologie établie pour désigner les
constituants d’une chaîne XML :

une paire de balises ouvrante et fermante et le fragment qu’elles entourent constituent un élément
XML ;

le nom de la balise est le type de l’élément ;

le contenu d’un élément XML est obtenu en enlevant les balises qui l’entourent.
1 XML est un langage de balisage structurel.
16 CHAPTER 1. INTRODUCTION À XML ET XSLT

La structuration avec XML permet d’une part de désigner certaines parties du contenu avec des noms
d’éléments, et d’autre part de structurer ce contenu en définissant une hiérarchie entre les éléments. Une des
principales règles de structuration est en effet que le parenthésage défini par les balises doit être imbriqué :
si une balise  B  est ouverte entre deux balises  A  et  /A  définissant un élément, elle doit également
être fermée par  /B  entre ces deux balises. Cette contrainte introduit une hiérarchie entre les éléments
définis par les balises. Par exemple, l’élément  ADRESSE  100, rue Mouffetard  /ADRESSE 
est un sous-élément de l’élément défini par la balise  CINEMA  . Ce dernier englobe tout le document
(sauf la première ligne) et est appelé l’élément racine du document.
On peut noter que le nom des balises, ainsi que l’imbrication de ces balises, sont totalement libres : il
n’existe pas en XML de règles prédéfinies. Cela permet à chacun de définir son propre langage pour décrire
ses données. L’Épée de bois s’est défini un langage basé sur le vocabulaire CINEMA, NOM, ADRESSE et
METRO, et une règle de construction très simple consistant à imbriquer dans  CINEMA  les trois autres
éléments. Nous parlerons parfois de « dialecte » pour désigner un langage défini avec XML.
La structure hiérarchique d’un contenu XML devient plus explicite si on ajoute des changements de
ligne et des espaces dans le document :

Exemple 2 Représentation XML avec indentation


<?xml version="1.0" encoding="ISO-8859-1"?>
<CINEMA>
<NOM>Epée de Bois</NOM>
<ADRESSE>100, rue Mouffetard</ADRESSE>
<METRO>Censier-Daubenton</METRO>
</CINEMA>

Cette chaîne est considérée comme identique à la première car les caractères blancs et les sauts de ligne
entre deux balises ne sont pas pris en compte par un traitement. L’indentation est souvent utilisée pour clar-
ifier un contenu XML, sans avoir d’impact sur ce contenu lui-même. En fait, ce que cette pratique suggère,
c’est qu’une approche fructueuse pour faciliter la compréhension et le raisonnement sur une information
structurée avec XML est de considérer que cette information est un arbre, et pas une chaîne de caractères.
La figure 1.1 montre l’arbre correspondant au cinéma « L’Epée de bois ». Il a pour racine un élément
 CINEMA  donc le contenu est lui-même constitué des trois sous-éléments  NOM  ,  ADRESSE  et
 METRO  . Chacun de ces trois sous-éléments a un contenu qui est du texte simple.

CINEMA

NOM ADRESSE METRO

Épée de bois 100, rue Mouffetard Censier-Daubenton

Figure 1.1: Représentation arborescente d’un contenu XML

Cette représentation, plus abstraite, permet de mettre l’accent sur les deux aspects vraiment essentiels
d’un contenu structuré avec des balises XML. En premier lieu elle montre quels sont les noms d’éléments
qui décomposent et désignent les différentes parties du contenu. En second lieu elle permet de situer
précisément la place de chaque élément au sein de la hiérarchie globale. Il est très important de noter dès
maintenant que ces deux aspects sont indissociables : un élément est caractérisé à la fois par son nom
et par sa place dans l’arbre XML. Concrètement, cela implique que tout traitement de données XML –
par exemple en vue de les mettre en forme pour une publication web – se base sur des outils permettant de
1.2. XML, FORMAT UNIVERSEL 17

choisir des éléments par leur nom, ou par leur position, ou par les deux dimensions utilisées simultanément.
Le principal outil utilisé dans ce livre pour sélectionner des éléments XML est le langage XPath, mais nous
donnerons également un aperçu des interfaces de programmation Sax et DOM qui remplissent la même
fonction.
Voici un exemple plus général illustrant la structure d’un document. Il développe la description du
cinéma « L’Epée de bois ». Ce cinéma a deux salles, chacune représentée par un élément XML de type
 SALLE  . Pour chaque salle on connaît le titre du film projeté et les horaires des séances. La première
salle a également un sous-élément de type  REMARQUE  qui est absent pour les deux autres salles.
Exemple 3 ExXML1.xml : Un cinéma, avec salles et séances
<?xml version="1.0" encoding="ISO-8859-1"?>
<CINEMA>
<NOM>Epée de bois</NOM>
<ADRESSE>100, rue Mouffetard</ADRESSE>
<METRO>Censier-Daubenton</METRO>

<SALLE NO=’1’ PLACES=’320’>


<TITRE>Alien</TITRE>
<REMARQUE>Reservation conseillée</REMARQUE>
<SEANCES>
<SEANCE>15:00</SEANCE>
<SEANCE>18:00</SEANCE>
<SEANCE>21:00</SEANCE>
</SEANCES>
</SALLE>
<SALLE NO=’2’ PLACES=’120’>
<TITRE>Vertigo</TITRE>
<SEANCES>
<SEANCE>22:00</SEANCE>
</SEANCES>
</SALLE>
</CINEMA>

Cet exemple introduit un nouvel aspect de la représentation d’une information en XML : les attributs.
Dans les premiers exemples donnés précédemment, toute l’information concernant un type d’élément était
codée dans le contenu des éléments, ou, autrement dit, dans le texte entouré par les balises de l’élément. Ici
(exemple 3), le numéro et le nombre de places disponibles pour chaque salle ne font pas partie du contenu
de l’élément correspondant, mais sont indiqués au sein des balises même sous forme d’attributs NO et
PLACES. La même information aurait pu être codée avec des sous-éléments.

La figure 1.2 montre l’arbre XML. On peut en tirer quelques constatations générales :
cet arbre n’est pas équilibré (certaines branches sont plus longues que d’autres) ;
certains types d’éléments se répètent (cas des salles et des séances) et d’autres pas (cas du nom du
cinéma) ;
certains types d’éléments apparaîssent régulièrement comme sous-élément d’un autre type d’élément
(cas des salles qui sont des sous-éléments des cinémas et des titres qui sont des sous-éléments des
salles) ;
les éléments de certains types sont optionnels (cas des remarques).
Nous utiliserons abondamment la représentation arborescente pour soutenir nos explications sur les
mécanismes de transformation XSLT. Elle permet de s’affranchir de détails inutiles (comme, par exemple :
d’où vient cette chaîne ? comment est-elle indentée ?) et de travailler sur une représentation claire et
pertinente du contenu et de sa structuration.
18 CHAPTER 1. INTRODUCTION À XML ET XSLT

CINEMA

NOM ADRESSE METRO SALLE SALLE


NO=1, PLACES=320 NO=2, PLACES=120

100, rue Mouffetard

Épée de bois Censier Daubenton TITRE SEANCES

TITRE REMARQUE SEANCES Vertigo SEANCE

Réservation conseillée

Alien SEANCE SEANCE SEANCE 22:00

15:00 18:00 21:00

Figure 1.2: Arbre d’un document XML complété

1.2.3 Documents XML


Jusqu’à présent nous avons parlé de « chaîne de caractères » sans faire d’hypothèses sur l’origine ou le
stockage de cette chaîne : cette dernière peut être placée dans un fichier, mais il peut également s’agir
d’un flux (ou message) échangé entre deux applications, ou d’une information engendrée à partir d’une
application. Par exemple, la plupart des systèmes de bases de données actuels permettent de générer des
documents XML à partir des données stockées.
Dans le cas d’un stockage fichier, l’information codée en XML peut être affichée et modifiée par un
outil de traitement de texte standard. Il est ainsi possible de visualiser et modifier un document XML très
facilement et sans outil sophistiqué. Pour des raisons de simplicité, c’est la situation que nous envisagerons
prioritairement dans ce qui suit.
Le caractère persistant (cas d’un fichier) ou transitoire (cas d’un message) d’une information codée avec
XML sont cependant des aspects secondaires tant qu’on ne s’intéresse pas à des problèmes d’architecture
sur lesquels nous reviendrons plus tard. Nous utiliserons uniformément dans ce qui suit le terme de docu-
ment XML pour désigner un contenu structuré avec des balises XML, et ce quelle que soit la nature physique
et la durée d’existence de ce contenu.
La notion de document en XML est un peu plus complète que celle d’un arbre d’éléments. La déclara-
tion XML, ainsi que certaines autres informations qui apparaissent avant l’élément racine sont considérées
comme parties intégrantes du document. Nous distinguerons donc soigneusement, à partir de maintenant :

l’élément racine, défini par la première balise rencontrée ;


la racine du document qui comprend, outre l’élément racine, un ensemble de déclarations et d’instructions
utiles pour l’interprétation du contenu.

Cette distinction, ainsi que la différence entre document XML et fichier, sont illustrés par l’exemple
suivant. Imaginons que dans notre application, chaque salle est gérée par un responsable qui doit tenir à
1.2. XML, FORMAT UNIVERSEL 19

jour les informations. Il existe alors autant de fichiers XML qu’il y a de salles. Le document relatif à la
salle 2 est le suivant :
Exemple 4 Salle2.xml : La salle 2, représentée indépendamment
<?xml version="1.0" encoding="ISO-8859-1"?>

<SALLE NO=’2’ PLACES=’120’>


<FILM>
<TITRE>Vertigo</TITRE>
<AUTEUR>Alfred Hitchcock</AUTEUR>
<ANNEE>1958</ANNEE>
<GENRE>Drame</GENRE>
<PAYS>Etats Unis</PAYS>
<RESUME>Scottie Ferguson, ancien inspecteur de police, est sujet
au vertige depuis qu’il a vu mourir son collègue. Elster, son
ami, le charge de surveiller sa femme, Madeleine, ayant des
tendances suicidaires. Amoureux de la jeune femme Scottie ne
remarque pas le piège qui se trame autour de lui et dont il va
être la victime...
</RESUME>
</FILM>
<SEANCES>
<SEANCE>22:00</SEANCE>
</SEANCES>
</SALLE>

On retrouve les attributs et les éléments  SEANCE  , et l’élément  FILM  auquel on a ajouté des
informations complémentaires : année de production, metteur en scène, résumé, etc. Le contenu de
ce fichier correspond à un document représenté dans la figure 1.3, avec la racine du document notée
Salle2.xml:/, puis l’élément racine SALLE.

Salle2.xml:/

SALLE
<- - Salle 2 du cinéma Epée de Bois - -> NO=’2’ PLACES=’120’

FILM SEANCES

TITRE AUTEUR ANNEE GENRE PAYS RESUME SEANCE

Vertigo Hitchcock 1958 Drame USA Scotty... 22:00

Figure 1.3: Arbre d’un document XML complété


20 CHAPTER 1. INTRODUCTION À XML ET XSLT

À partir de l’ensemble des documents décrivant les salles, il est possible de reconstituer un document
global en assemblant dans un fichier les informations propres au cinéma, et en important les documents
relatifs aux salles. On utilise la notion XML d’entité externe qui permet de faire référence à une source
de données externe au fichier XML « principal » (appelé entité document), et d’inclure le contenu de cette
source.
Voici une nouvelle représentation du document XML pour le cinéma « L’Epée de bois » (figure 1.2). Il
s’agit bien du même document (avec un description plus détaillée des films), mais réparti dans trois fichiers
ou entités externes :

Exemple 5 Epee.xml : Fichier constituant par assemblage un document sur le cinéma

<?xml version="1.0" encoding="ISO-8859-1"?>

<?xml-stylesheet href="Cinema.xsl" type="text/xsl"?>


<?xml-stylesheet href="CinemaWML.xsl" type="text/xsl" media="wap"?>
<?cocoon-process type="xslt"?>

<!DOCTYPE CINEMA [
<!ENTITY salle1 SYSTEM "Salle1.xml">
<!ENTITY salle2 SYSTEM "Salle2.xml">
]>
<CINEMA>
<NOM>Epée de bois</NOM>
<ADRESSE>100, rue Mouffetard</ADRESSE>
<METRO>Censier-Daubenton</METRO>

<!-- Inclusion du fragment XML décrivant la salle 1 -->


&salle1;

<!-- Inclusion du fragment XML décrivant la salle 2 -->


&salle2;
</CINEMA>

L’entité document Epee.xml contient dans son entête deux définitions d’entité externes vers les fichiers
Salle1.xml et Salle2.xml :

<!ENTITY salle1 SYSTEM "Salle1.xml">\\


<!ENTITY salle2 SYSTEM "Salle2.xml">

Les références vers les entité externes dans l’entité document sont représentées par le nom de l’entité
correspondante entouré des symboles & et ; :

<!-- Inclusion du fragment XML décrivant la salle 1 -->


&salle1;

<!-- Inclusion du fragment XML décrivant la salle 2 -->


&salle2;

Dans la représentation arborescente du document XML (figure 1.2), toutes les références vers ces en-
tités seront remplacées par le contenu des entités Salle1.xml et Salle2.xml.
Nous serons amené dans la suite de ce livre à généraliser considérablement ce premier exemple où
un document XML est obtenu par assemblage de plusieurs sources. Ici nous sommes dans un cas simple
où les sources sont d’autres fichiers, mais il est possible d’intégrer des composants très divers, incluant
des parties « statiques » (par exemple un ou plusieurs fichiers, éventuellement répartis sur l’Internet) et
des parties « dynamiques », fragments créés à la volée, par exemple par extraction à partir d’une base de
données.
1.3. PUBLICATION DE DONNÉES AVEC XSLT 21

1.3 Publication de données avec XSLT


Nous allons maintenant montrer comment, à partir d’un document XML proposant un contenu structuré, on
obtient avec des transformations XSLT des publications de ce contenu destinées aux supports les plus var-
iés. L’idée de base d’un environnement XML/XSLT est de séparer le traitement des données du processus
de publication.

le traitement des données consiste à les mettre sous forme de document XML obéissant à une struc-
ture arborescente donnée (par exemple la structure cinéma-salle-film illustrée dans ce qui précède) ;
la publication des données consiste à extraire un contenu d’un document XML et à le mettre dans for-
mat reconnu par une application de publication particulière (par exemple au format HTML reconnu
par les navigateurs web).

Dans un tel environnement les responsabilités sont clairement partagées. On y distingue ceux qui gèrent
les contenus et doivent établir les documents XML, éventuellement à partir de plusieurs sources de données
– nous reviendrons sur cet aspect ultérieurement – de ceux qui doivent créer une mise en forme pour tel ou
tel support. Nous prenons comme exemple les documents XML de la section précédente, sans avoir besoin
de faire d’hypothèses sur l’origine de ces documents. Les transformations XSLT vont permettre d’obtenir
trois versions différentes de ce même contenu :
un (petit) site web, affichant les informations sur le cinéma, ses salles et ses séances ;
un site WAP permettant de consulter sur un téléphone mobile les mêmes informations ;
enfin un document PDF donnant l’ébauche de ce qui pourrait être un « Officiel des spectacles »
imprimé.

1.3.1 Site web (HTML)


HTML est un langage de balisage dédié à l’échange de documents sur le Web sous forme de document
hypertextes2 dans lesquels certains mots ou groupes mots (les ancres) servent d’accès à d’autres documents
HTML, parfois situés sur d’autres sites web. L’utilisation des ancres permet de « naviguer » sur le Web sans
même connaître ses notions de base (le protocole HTTP, le système d’adressage par des URL, etc).
Contrairement à XML, HTML fournit un ensemble fixe de balises auxquelles sont attachées des fonc-
tionnalités précises de présentation. L’utilisation des balises HTML est donc avant tout destinée à donner
des directives de mise en forme au navigateur qui se charge d’afficher le document. À l’opposé, l’auteur
d’un document XML définit son propre vocabulaire de balises, le choix étant guidé par le besoin de décrire
au mieux possible la structure et la signification des données.
Nous reviendrons en détail sur le langage HTML, ses différentes versions, et ses rapports avec XML. Ici
nous nous contenterons de montrer comment nous pouvons obtenir une version HTML de nos documents
XML par transformation XSLT, en commençant par prendre l’exemple très simple de la description d’un
film. Voici le document HTML que nous désirons obtenir.

Exemple 6 Vertigo.html : Document HTML pour le film Vertigo :


<html>
<head>
<title>Film: Vertigo</title>
</head>
<body bgcolor="white">
<img src="Vertigo.gif" height="220" align="left"></img>
<h1><i>Vertigo</i></h1> Drame, <i>Etats Unis</i>, 1958
<p> Mis en scène par <b>Alfred Hitchcock</b></p>
<h3>Résumé</h3>
Scottie Ferguson, ancien inspecteur de
2 « HTML » est l’abréviation de « HyperText Markup Language ».
22 CHAPTER 1. INTRODUCTION À XML ET XSLT

police, est sujet au vertige depuis qu’il a vu mourir son


collègue. Elster, son ami, le charge de surveiller sa femme,
Madeleine, ayant des tendances suicidaires. Amoureux de la jeune
femme Scottie ne remarque pas le piège qui se trame autour de
lui et dont il va être la victime...
</body>
</html>

Il s’agit, une nouvelle fois, d’un arbre dont la racine est l’élément  html  , avec deux fils :  head 
et  body  . Le reste du document est du texte libre, encadré par des balises de mise en forme. Sans entrer
pour l’instant dans le détail, on peut :

centrer une partie d’un document en utilisant la balise  center  ;


différencier différents niveaux de titre de sections (balises  h1  ,  h2  , . . . ,  h5  ) ;
mettre du texte en italique (balise  i ) ou en gras (balise  b );
créer des paragraphes (balise  p );
inclure des images (balise  img  ) qui sont stockées dans des fichiers externes.

Ce document HTML peut tout à fait être vu comme un document XML, avec une structure imposée
(notamment pour la racine de l’arbre et ses deux fils), et des noms de balise fixées par la norme HTML.
En fait HTML s’est développé indépendamment de XML et s’avère beaucoup moins rigoureux. Les navi-
gateurs acceptent par exemple des documents sans la racine  html  , et dans de nombreux cas la balise
fermante d’éléments vides est considérée comme optionnelle. Une norme récente, XHTML, reconsidère la
définition de HTML comme un « dialecte » XML.

Figure 1.4: Page HTML affiché avec Netscape

La figure 1.4 montre l’affichage de ce document dans le navigateur Netscape. On peut voir que le titre
du film apparaît en caractères gras italiques, le pays d’origine en caractères italiques et le nom du réalisateur
en caractères gras. De plus le texte entoure une image de l’affiche (version française) du film.

Transformations XSLT
Nous allons utiliser une feuille de style XSLT pour produire automatiquement le document HTML à partir
d’un document XML, appelé document source dans ce qui suit. Comme c’est la première fois que nous
1.3. PUBLICATION DE DONNÉES AVEC XSLT 23

rencontrons ce langage, nous commençons par une brève introduction permettant d’en comprendre les
principes de base.
L’application d’une feuille de style XSLT consiste à parcourir les nœuds du document XML, et à
appliquer des règles de transformation à ces nœuds. La notion de règle (nommées template) est centrale
dans XSLT, et la bonne compréhension des aspects suivants est essentielle.

une règle s’applique toujours dans le contexte de l’un des nœuds du document source ;
l’application de la règle consiste à produire un fragment de document, qui peut combiner du texte et
des données extraites du document XML.

Voici un premier exemple de règle de transformation XSLT. Elle consiste à produire une phrase simple
chaque fois qu’un élément  FILM  est rencontré dans le document source.

<xsl:template match="FILM">
Ceci est le texte produit par application de cette règle.
</xsl:template>

On constate qu’une règle est un élément XML défini par la balise xsl:template. L’attribut match="FILM"
est le motif de sélection de cette balise et indique à quel(s) type(s) d’éléments du document XML traité
s’applique la règle. La règle ci-dessus s’appliquera donc toujours dans le contexte d’un élément de type
FILM. Enfin le contenu de l’élément xsl:template est le corps de la règle et définit le texte produit à
chaque fois que la règle s’applique.
Un programme XSLT est en général constitué de plusieurs règles dont chacune peut s’appliquer à
différents parties d’un document XML. Chaque règle produit un sous-arbre spécifique quand elle rencontre
un élément déclencheur, et l’assemblage de ces sous-arbres constitue le résultat de la transformation. Dans
le cas le plus simple, on spécifie des règles différentes pour chaque type d’élément d’un document, comme
nous l’avons fait ci-dessus pour l’élément  FILM  du document XML à transformer. Parfois la distinction
par le type de l’élément peut être insuffisante et/ou trop imprécise pour choisir les règles et des motifs de
sélection plus complexes, que nous présenterons plus tard, s’avèrent nécessaires.
Le corps de la règle indique le texte produit quand un nœud du bon type est rencontré dans le document
XML. Dans notre premier exemple, le texte produit est toujours
Ceci est le texte produit par application de cette règle.

et ce quel que soit le contenu de l’élément  FILM  . En pratique ce genre de règle n’est évidemment pas
très intéressante, et on rencontre plus souvent des règles où le texte reprend et réorganise des parties du
document XML traité. Rappelons que la règle s’applique dans le contexte d’un nœud : le principe consiste
alors à sélectionner, à partir de ce nœud, les parties du document qui vont être produites par la règle.
Prenons l’exemple du document XML représentant le film Vertigo. Quand notre règle s’exécute, le
nœud contexte est l’élément racine de l’arbre. On a accès, depuis cette racine, à tous les fils du nœud
 FILM  , soit les éléments  TITRE  ,  AUTEUR  ,  ANNEE  , etc., mais aussi à d’autres nœuds
comme par exemple les nœuds descendants (les fils des fils, etc...) ou les nœuds parents et ancêtres.
Pour sélectionner le contenu d’un élément, on utilise l’élément XSLT xsl:value-of en indiquant
simplement le chemin d’accès à partir du nœud courant. Par exemple le titre du film est obtenu par :

<xsl:value-of select="TITRE"/>

Le fait de préfixer par xsl toutes les balises relevant du langage XSLT permet au processeur de dis-
tinguer les éléments qui doivent être simplement inclus dans le résultat, des éléments qui correspondent à
des instructions XSLT.
La figure 1.5 montre l’interprétation de xsl:value-of, avec ses deux paramètres déterminants :
le contexte d’exécution, qui est ici l’élément  FILM  , et le chemin d’accès, en l’occurrence l’élément
 TITRE  , fils de l’élément-contexte. Il s’agit ici de l’exemple le plus simple – mais aussi le plus courant
– où on accède aux descendants directs d’un élément, mais nous verrons que le mode de désignation des
éléments à partir d’un nœud contexte est beaucoup plus général.
24 CHAPTER 1. INTRODUCTION À XML ET XSLT
Contexte d’application de la règle XSLT
select="TITRE" FILM

TITRE AUTEUR ANNEE GENRE PAYS RESUME

Vertigo Hitchcock 1958 Drame USA Scotty...

Figure 1.5: Extraction des informations dans une règle XSLT

Nous sommes maintenant en mesure d’enrichir notre première règle pour produire un premier docu-
ment HTML sommaire, mais complet.

<xsl:template match="FILM">
<html>
<head>
<title>Film:
<xsl:value-of select="TITRE"/>
</title>
</head>
<body>
Ici je peux mettre d’autres informations sur le film
</body>
</html>
</xsl:template>

L’élément  xsl:value-of select="TITRE"/  est remplacé à l’exécution par la valeur de


l’élément  TITRE  , soit Vertigo. Appliquée à Vertigo.xml, cette règle produira donc le résultat suiv-
ant :

<html>
<head>
<title>Film: Vertigo
</title>
</head>
<body>
Ici je peux mettre d’autres informations sur le film
</body>
</html>

Bien entendu on peut appliquer la même règle à tout document XML ayant la même structure que
Vertigo.xml.

Transformation XML -  HTML


Notre objectif est donc d’obtenir le document HTML de l’exemple 6 par transformation XSLT du document
Vertigo.xml ci-dessous.

Exemple 7 Vertigo.xml : Le document XML pour le film Vertigo


1.3. PUBLICATION DE DONNÉES AVEC XSLT 25

<?xml version="1.0" encoding="ISO-8859-1"?>

<?xml-stylesheet href="Film.xsl" type="text/xsl"?>


<?xml-stylesheet href="FilmWML.xsl" type="text/xsl" media="wap"?>
<?cocoon-process type="xslt"?>

<FILM>
<TITRE>Vertigo</TITRE>
<AUTEUR>Alfred Hitchcock</AUTEUR>
<ANNEE>1958</ANNEE>
<GENRE>Drame</GENRE>
<PAYS>Etats Unis</PAYS>
<RESUME>Scottie Ferguson, ancien inspecteur de police, est sujet
au vertige depuis qu’il a vu mourir son collègue. Elster, son
ami, le charge de surveiller sa femme, Madeleine, ayant des
tendances suicidaires. Amoureux de la jeune femme Scottie ne
remarque pas le piège qui se trame autour de lui et dont il va
être la victime...
</RESUME>
</FILM>

De manière générale le résultat est obtenu en insérant dans des balises HTML des extraits du document
XML. Tous ces extraits sont facilement accessibles à partir de la racine  FILM  , et nous allons donc
pouvoir nous contenter d’une seule règle qui va « piocher », à partir de la racine, les différents constituants
décrivant le film, et produire les fragments HTML appropriés.
La figure 1.6 illustre ce principe par deux arbres superposés : l’arbre supérieur correspond au document
XML qui doit être transformé en HTML; l’arbre inférieur définit la structure de la page HTML à générer
(pour une meilleure représentation, la racine de l’arbre est en-bas). Tous les nœuds sauf sept feuilles sont
étiquetés par des balises HTML qui définissent la structure du document produit. Les autres noeuds sont de
type xsl:value-of et définissent, pour leur part, la partie dynamique du contenu, obtenue par extraction
de certains éléments du document XML. On peut noter que l’élément  TITRE  est référencé trois fois et
que l’ordre des instructions de substitution ne correspond pas à l’ordre des éléments insérés dans le résultat.

La règle de transformation, insérée dans une feuille de style complète, crée un document HTML pour
chaque film, autrement dit pour chaque document XML ayant la même structure que Vertigo.xml. Son
corps correspond à l’arbre inférieur dans la Figure 1.6.

Exemple 8 Film.xsl : Programme de transformation XSLT correpondant à la Figure 1.6.


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>

<xsl:template match="FILM">
<html>
<head>
<!-- Titre du film -->
<title>Film: <xsl:value-of select="TITRE"/>
</title>
</head>
<body bgcolor="white">
<p>
<!-- Insérer une image GIF avec le titre comme nom -->
<img SRC="{TITRE}.gif" align="left" height="220"/>
<h1>
26 CHAPTER 1. INTRODUCTION À XML ET XSLT

FILM

TITRE AUTEUR ANNEE GENRE PAYS RESUME

sele
ct="
AUT
EUR"
se
Vertigo Hitchcock 1958 Drame USA Scotty... lec
t=
"R
ES
UM
E"
selec

sel
select="PA
t="T

ect
select="
select="TITRE

="A

xsl:value-of
ITR

NN
E"

GENRE

YS"

EE
select="TIT

"

Résumé: xsl:value-of
"
"

xsl:value-of
RE"

i xsl:value-of Mise . . . b h3

Film: img h1 xsl:value-of i xsl:value-of

title xsl:value-of p p

head body

html

xsl:template
match="FILM"

Figure 1.6: Transformation XSLT


1.3. PUBLICATION DE DONNÉES AVEC XSLT 27

<i><xsl:value-of select="TITRE"/></i>
</h1>

<!-- Genre, pays, et année du film -->


<xsl:value-of select="GENRE"/>,
<i> <xsl:value-of select="PAYS"/></i>,
<xsl:value-of select="ANNEE"/>
</p>
<p>
<!-- Auteur du film -->
Mis en scène par <b><xsl:value-of select="AUTEUR"/></b>

<!-- Résumé du film -->


<h3>Résumé</h3>
<xsl:value-of select="RESUME"/>
</p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Un programme XSL comme celui présenté ci-dessus est un document XML interprété par un processeur
XSLT : on peut vérifier que c’est un arbre constitué d’une imbrication de balises ouvrantes et fermantes. Il
doit obéir à certaines règles de structuration et de nommage des balises. En particulier toutes les balises
propres à XSLT doivent être préfixées par xsl: avec que le processeur puisse les distinguer des balises à
insérer dans le résultat. Ce préfixe définit un espace de nom qui caractérise les balises XSLT.
L’élément racine du document XSLT Film.xsl est de type xsl:stylesheet et contient deux sous-
éléments de type xsl:output et xsl:template. L’élément xsl:output informe le processeur
XSLT que le document généré est un document HTML conforme à la version 4.0 et utilisant le codage
“iso-8859-1”.

Chemins complexes
Nous prenons maintenant l’exemple de la production du document HTML décrivant une salle de cinéma
pour illustrer la capacité de XSLT à spécifier des chemins d’accès complexes pour extraire des informations
d’un document XML.
Dans le document HTML montrant un film, tous les nœuds  TITRE  ,  AUTEUR  et autres auxquels
on accédait était les fils (au sens de : descendants directs) de l’élément  FILM  tenant lieu de contexte
de la règle. Le cas d’un document décrivant une salle de cinéma présente une structure plus riche. La
figure 1.7 montre la salle 1 de notre cinéma. Si on prend comme contexte d’une règle de transformation le
nœud  SALLE  , on constate que :

certaines informations (le numéro de la salle, le nombre de places) sont représentées comme des
attributs ;
le nœud a trois fils :  FILM  ,  REMARQUE  et  SEANCES  ;
les informations décrivant le film sont des petits-fils de  SALLE  :  TITRE  et  AUTEUR  en
sont séparés par  FILM  ;
l’élément  SEANCE  est petit-fils de  SALLE  , et peut de plus être répété un nombre quelconque
de fois ;
enfin l’élément  REMARQUE  est optionnel : il apparaît pour la salle 1, mais pas pour la salle 2
(voir figure 1.3, page 19).

Ces nouvelles particularités rendent plus complexe l’accès aux informations permettant de créer un
document HTML à partir d’un nœud de type SALLE. Gardons pour l’instant le principe de n’utiliser qu’une
28 CHAPTER 1. INTRODUCTION À XML ET XSLT

Contexte d’application de la règle chemin "@NO"


NO=2
SALLE PLACES=320
chemin "FILM/TITRE"
chemin
SEANCES/SEANCE

FILM
chemin
"REMARQUE"

TITRE AUTEUR ANNEE GENRE PAYS RESUME REMARQUE SEANCES

Alien Scott Science-Fiction 1979 USA Près d’un Réservation boucle


vaisseau spatial... conseillée for-each

SEANCE SEANCE SEANCE

15:00 18:00 21:00

Figure 1.7: Le document XML pour la première salle

seule règle faisant appel à des xsl:value-of . Les parties du document Salle1.xml sont alors désignées
par des chemins qui prennent tous leur origine du nœud  Salle  . Voici quelques exemples, illustrés
dans la figure 1.7.

l’attribut d’un élément est désigné par la concaténation du symbole ’@’ et du nom de l’attribut ; donc
le numéro de la salle est désigné par select="@NO" ;
le descendant d’un élément est désigné en donnant les nœuds successifs rencontrés à chaque niveau
de la branche menant à l’élément ; donc le titre du film est désigné par select="FILM/TITRE" ;
pour parcourir toutes les occurrences d’un même type d’élément, on peut effectuer une boucle
xsl:for-each sur l’ensemble des séances désignées par select="SEANCES/SEANCE" ;
enfin l’élément contexte lui-même est désigné par le symbole ’.’, comme dans select=".".

Voici la règle produisant une présentation HTML et récupérant les informations en exprimant les
chemins présentés ci-dessus.

<xsl:template match="SALLE">
<!-- Extraction d’attribut : no de salle et places -->
<h2>Salle No <xsl:value-of select="@NO"/></h2>
<h3>Capacité: <xsl:value-of select="@PLACES"/> places</h3>

<!-- Description du film: tous les chemins commencent par FILM/ -->
<h3>Film: <a href="{FILM/TITRE}XML.html">
<b> <xsl:value-of select="FILM/TITRE"/>
</b></a></h3>
de <b> <xsl:value-of select="FILM/AUTEUR"/>
</b><br/><i> <xsl:value-of select="FILM/PAYS"/></i>,
<xsl:value-of select="FILM/ANNEE"/>

<!-- Boucles sur toutes les séances -->


<h3>Séances</h3>
<ol>
<xsl:for-each select="SEANCES/SEANCE">
1.3. PUBLICATION DE DONNÉES AVEC XSLT 29

<li> <xsl:value-of select="."/></li>


</xsl:for-each>
</ol>
<xsl:for-each select="REMARQUE">
<font color="red"><xsl:value-of select="."/></font>
</xsl:for-each>
</xsl:template>
L’instruction xsl:for-each permet de créer une boucle pour ajouter toutes les séances et remar-
ques dans le résultat. La transformation définie par le contenu d’un élément  xsl:for-each  ne
s’applique pas à l’élément qui est en cours de transformation (la salle), mais aux éléments sélectionnés
par l’attribut select (les séances). Ainsi, l’instruction  xsl:value-of select="."/  dans la
première boucle sera remplacé par le contenu de chaque séance retrouvée.

Appel de règle
Il reste à ajouter les balises  html  ,  head  et  body  pour obtenir un document HTML complet.
Jusqu’à présent nous nous sommes volontairement limités à des exemples de productions basés sur une
seule règle. En pratique on est le plus souvent amené à définir plusieurs règles dans un programme XSLT,
et à déclencher des appels de règles à partir d’autres règles.
La règle initiale s’applique en général à la racine du document XML, désignée par ’/’. Elle génère un
document HTML complet avec un élément racine  html  et deux sous-éléments  head  et  title  .
Cette règle est la première règle appliquée par le processeur XSLT pendant la transformation d’un docu-
ment XML.
<xsl:template match="/">
<html>
<head><title>Salle: <xsl:value-of select="SALLE/@NO"/></title></head>
<body bgcolor="white">
<xsl:apply-templates select="SALLE"/>
</body>
</html>
</xsl:template>
L’élément  body  ne contient qu’un seul sous-élément qui est une instruction XSLT de type xsl:apply-
templates. Le processeur XSLT remplace cet élément par le résultat de la transformation qu’il dé-
clenche. Autrement dit on va appliquer aux éléments  SALLE  fils de la racine ’/’ du document la règle
spécifique à ce type d’élément, et insérer entre les balises  body  et  /body  le fragment HTML
produit.
L’intérprétation du mécanisme d’appel de règles est donné dans la figure 1.8. La partie supérieure
montre l’arbre XML, et la partie inférieure les deux règles du programme XSLT.
La première règle (en bas à gauche) s’applique à l’élément racine, ’/’. Elle produit successivement
un élément  html  , racine de l’arbre résultat, puis deux fils,  head  et  body  .
Au sein de l’élément  body  se trouve une instruction d’application d’une règle aux éléments fils
de l’élément courant qui sont de type SALLE. Le processeur XSLT cherche donc si un tel élément
existe : c’est le cas et la deuxième règle (en bas à droite) est donc déclenchée. Elle produit des
fragments HTML qui viennent s’insérer dans l’élément  body  .
La figure 1.9 montre le résultat obtenu alors, tel qu’il s’affiche avec Netscape.

Réutilisation de règles
Passons maintenant à un dernier stade pour compléter cette introduction à XSLT. Nous voulons produire la
page HTML récapitulant tout le programme proposé par L’Épée de bois. La figure 1.10 montre le résultat
obtenu3. Il apparaît clairement que la présentation de chaque salle est identique à celle qui était obtenue
3 Il va sans dire que nous privilégions ici la simplicité du code, au détriment de la qualité de présentation.
30 CHAPTER 1. INTRODUCTION À XML ET XSLT

NO="2"
PLACES="120"
SALLE
Transfroamtion du document (racine)

FILM SEANCES

Transfromation de <SALLE>
TITRE AUTEUR ANNEE GENRE PAYS RESUME SEANCE
select="SALLE"

Vertigo Hitchcock 1958 1958 USA Scotty... 22:00

... xsl:apply-templates
"Salle No" xsl:value-of "Capacité:" xsl:value-of "places"

head body

html h2 h3

...

<xsl:template match="/"> <xsl:template match="SALLE">

Figure 1.8: Appel de règles à partir d’autres règles

par application de la règle destinée à présenter une salle individuelle.


Pour créer la présentation d’un cinéma, nous allons donc reprendre la règle existante de traitement
des éléments SALLE, et déclencher son application. On utilise pour cela un élément xsl:apply-
template. Voici tout d’abord la règle s’appliquant à l’élément racine du document XML.
<xsl:template match="/">
<html>
<head><title>Programme de <xsl:value-of select="CINEMA/NOM"/>
</title>
</head>
<body bgcolor="white">
<xsl:apply-templates select="CINEMA"/>
</body>
</html>
</xsl:template>

La seconde règle d’applique dans le contexte d’un élément  CINEMA  . Elle extrait des informa-
tions relatives au cinéma, et propage la production de code HTML par un nouvel appel à xsl:apply-
templates.
<xsl:template match="CINEMA">
<h1><i> <xsl:value-of select="NOM"/> </i>
</h1><hr/> <xsl:value-of select="ADRESSE"/>,
<i>Métro: </i> <xsl:value-of select="METRO"/>
<hr/>
1.3. PUBLICATION DE DONNÉES AVEC XSLT 31

Figure 1.9: Copie écran du résultat de la transformation de Salle1.xml

<xsl:apply-templates select="SALLE"/>

</xsl:template>
Ce dernier appel déclenche la règle relative aux salles, pour tous les éléments  SALLE  qui sont fils
de l’élement  CINEMA  . Nous ne redonnons pas cette dernière règle.
L’application de chaque règle engendre un fragment d’arbre HTML, et tout appel xsl:apply-
templates insère dans ce fragment un ou plusieurs sous-arbres. La figure 1.11 montre (partiellement)
l’arbre final HTML obtenu, en distinguant les parties issues de chacune des trois règles impliquées dans la
transformation.

1. la première règle, appliquée à la racine du document XML, produit un « squelette » de document


HTML, avec les trois balises  html  ,  head  et  body  indispensables, puis elle passe la
main à la règle s’appliquant aux éléments de type CINEMA ;
2. la seconde règle produit les informations globales sur un cinéma, puis déclenche l’application de la
règle aux éléments  SALLE  ;
3. enfin la troisième règle s’applique aux deux éléments  SALLE  présents dans la description du
cinéma L’Épée de bois, et produit les deux sous-arbres HTML décrivant ces deux salles.

Un programme XSLT peut donc être vu comme l’application successive d’un ensemble de règles,
chacune concourant à la création du résultat final par « assemblage » de fragments qui viennent s’associer
pour former une hiérarchie. Dans la copie d’écran du résultat de la transformation (figure 1.10) on peut
clairement distinguer la partie créée par la règle de transformation pour les salles, reproduisant un motif de
présentation identique pour chaque élément  SALLE  rencontré.

1.3.2 Site WAP (WML)


Passons maintenant à la création d’une représentation permettant de consulter les séances à partir d’un
téléphone mobile, en partant du même document XML décrivant les séances à « L’Epée de bois ».

Publication WAP (WML)


Le langage utilisé pour spécifier l’affichage sur un mobile est WML. Il s’agit d’un « dialecte », ou spécial-
isation de XML, qui se base sur un ensemble de noms d’éléments et définit leur signification.
32 CHAPTER 1. INTRODUCTION À XML ET XSLT

Figure 1.10: La page d’accueil de L’Épée de bois

Un document WML est un arbre avec pour racine un élément  wml  (de même qu’un document
HTML est un arbre avec pour racine l’élément  html  ), mais il est divisé en sous-éléments, les « cartes »,
définisant l’unité d’affichage sur l’écran du mobile. Les cartes d’un même document peuvent être liées entre
elles par des liens, ce qui permet à l’utilisateur de naviguer grâce aux boutons de son téléphone.
Un exemple de document WML comprenant une seule carte est donné ci-dessous, avec les informations
sur le film Alien. Toutes les balises WML sont en minuscules, et toutes sont très concises afin de limiter le
coût des transferts de documents.

Exemple 9 Alien.wml : Un document WML


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card>
<p><b>Alien</b>, 1979, Ridley Scott<br/>
Près d&apos;un vaisseau spatial échoué sur une lointaine
planète, des Terriens en mission découvrent de bien étranges
&quot;oeufs&quot;. Ils en ramènent un à bord, ignorant
qu&apos;ils viennent d&apos;introduire parmi eux un huitième
passager particulièrement féroce et meurtrier. </p>
</card>
</wml>

Une carte est organisée en paragraphes grâce à la balise  p  , avec au moins un paragraphe par carte, ce
qui est le cas dans l’exemple ci-dessus. Quelques autres balises, reprises de HTML, peuvent être utilisées
1.3. PUBLICATION DE DONNÉES AVEC XSLT 33

html

head body

title h1 hr adresse p p

Règle "/" i
h2 h3 h2 h3
Epée de bois
Salle No 1 Film: Alien Salle No 2 Film : Vertigo
Règle "CINEMA"
Règle "SALLE"

Figure 1.11: L’arbre HTML, résultat de la transformation XSLT

pour définir une mise en page (limitée) du texte sur l’écran du mobile : la balise  b  affiche le contenu de
l’élément en gras, et la balise  br  permet de passer à la ligne. La figure 1.12 montre l’affichage obtenu
dans un téléphone Nokia 6150.
Voyons maintenant comment obtenir cette représentation WML à partir du document Alien.xml, donné
ci-dessous.

Exemple 10 Alien.xml : Document XML pour le film Alien

<?xml version="1.0" encoding="ISO-8859-1"?>

<?xml-stylesheet href="FilmWML.xsl" type="text/xsl" media="wap"?>


<?cocoon-process type="xslt"?>

<FILM>
<TITRE>Alien</TITRE>
<AUTEUR>Ridley Scott</AUTEUR>
<ANNEE>1979</ANNEE>
<GENRE>Science-fiction</GENRE>
<PAYS>Etats Unis</PAYS>
<RESUME>Près d’un vaisseau spatial échoué sur une lointaine
planète, des Terriens en mission découvrent de bien étranges
"oeufs". Ils en ramènent un à bord, ignorant qu’ils viennent
d’introduire parmi eux un huitième passager particulièrement
féroce et meurtrier.
</RESUME>
</FILM>

Nous allons simplement utiliser deux règles. Une première règle, d’initialisation, crée le « squelette »
du document résultat, soit l’équivalent pour WML de la structure  html  ,  head  ,  body  que nous
avons utilisée pour HTML. Cela consiste :

à ouvrir, puis refermer la balise principale  wml  ;

à déclencher, dans la balise principale, un appel aux autres règles.

Voici cette première règle.


34 CHAPTER 1. INTRODUCTION À XML ET XSLT

Figure 1.12: L’affichage de la carte de l’exemple 9

<xsl:template match="/">
<wml>
<xsl:apply-templates/>
</wml>
</xsl:template>

La seconde règle s’applique à un élément de type  FILM  . Cette règle produit une carte WML, et
place dans cette carte un extrait des éléments constituant la description du film, à savoir le titre, l’année,
l’auteur et le résumé. Notons que l’ordre dans lequel on utilise ces éléments peut être totalement reconsid-
éré par rapport à celui du document XML initial.

<xsl:template match="FILM">
<card>
<p>
<b> <xsl:value-of select="TITRE"/></b>,
<xsl:value-of select="ANNEE"/>,
<xsl:value-of select="AUTEUR"/><br/>
<xsl:value-of select="RESUME"/><br/>
</p>
</card>
</xsl:template>

Voici finalement la feuille de style complète. Il va sans dire qu’elle s’applique à tout document XML
dont la structure est identifique à celle de Alien.xml, par exemple Vertigo.xml (voir page 24).

Exemple 11 FilmWML.xsl : La feuille XSLT créant une version WML


1.3. PUBLICATION DE DONNÉES AVEC XSLT 35

<?xml version="1.0" encoding="ISO-8859-1"?>


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output encoding="ISO-8859-1"/>

<xsl:template match="/">
<xsl:processing-instruction name="cocoon-format">
type="text/wml"
</xsl:processing-instruction>

<wml>
<xsl:apply-templates/>
</wml>
</xsl:template>

<xsl:template match="FILM">
<card>
<p>
<b> <xsl:value-of select="TITRE"/></b>,
<xsl:value-of select="ANNEE"/>,
<xsl:value-of select="AUTEUR"/><br/>
<xsl:value-of select="RESUME"/><br/>
</p>
</card>
</xsl:template>

</xsl:stylesheet>

L’application de cette feuille de style permet d’obtenir le document de l’exemple 9, et donc l’affichage
de la figure 1.12.

Création d’un site WAP


Nous pouvons maintenant, à partir de notre document XML décrivant L’Epée de bois, créer un ensemble de
cartes permettant de choisir la salle et le film, de consulter les séances pour cette salle, et enfin d’afficher les
informations détaillées sur le film. La structure du document WML résultat est donnée dans la figure 1.13.
Il contient cinq éléments  card  : un pour le menu d’accueil, montrant les salles de L’Epée de bois et le
film qui y est projeté, deux cartes pour les deux salles, enfin deux cartes donnant des détails sur les films.
Pour permettre la navigation dans ce document, chaque carte doit être identifiée par la valeur – unique
au sein du document WML – de l’attribut id dans la balise  card  . La figure 1.13 montre les id de
chaque carte : index, S1, S2, Alien et Vertigo. Pour créer un lien vers une carte, on utilise en WML,
comme en HTML, la balise  a  . Voici par exemple l’élément WML permettant de référencer la carte
décrivant Alien :

<a href="#Alien">lien vers le film Alien</a>

En se positionnant sur le texte tenant lieu de lien, l’utilisateur peut afficher la carte correspondante.
Les flèches en tiretés sur la figure indiquent la navigation entre les cartes : de l’index (affichage dans la
figure 1.14, à gauche), on peut se rendre sur une salle (affichage dans la figure 1.14, au centre), puis d’une
salle sur le film projeté dans la salle (figure 1.14, à droite).
Voici maintenant quelques détails sur la feuille XSLT permettant de produire le document WML. La
règle d’initialisation procède comme précédemment, en produisant un élément  wml  , puis elle déclenche
trois autres règles, correspondant respectivement aux trois types de cartes : liste des salles, liste des séances,
affichage du film. Voici cette première règle.

<xsl:template match="/">
36 CHAPTER 1. INTRODUCTION À XML ET XSLT

wml

id=index id=S1 id=S2 id=Alien id=Vertigo


card card card card card

p p p p p

href=Alien href=Vertigo
href=S1
a a a

href=S2
a

Figure 1.13: L’arbre XML du site WAP

<wml>
<!-- création de la carte d’accueil -->
<xsl:apply-templates select="CINEMA"/>

<!-- création des cartes pour les salles et séances -->


<xsl:apply-templates select="CINEMA/SALLE"/>

<!-- création des cartes pour les films -->


<xsl:apply-templates select=".//FILM"/>
</wml>

Rappelons comment on désigne le chemin d’accès aux éléments auxquels on applique des règles. Le
principe tient en deux points :

1. prendre en compte la position courante dans l’arbre ;


2. indiquer le chemin à suivre dans l’arbre, à partir de la position courante, pour atteindre l’élément à
traiter.

Ici la position courante (autrement dit à laquelle la règle courante s’applique) est la racine du docu-
ment, dénotée « / ». On veut traiter trois types d’éléments,  CINEMA  , pour produire la carte d’index,
 SALLE  , pour produire la carte donnant les séances, et  FILM  pour produire la carte donnant la
description de chaque film.
Étant donnée la position courante située à la racine, et la position de ces éléments dans l’arbre XML, la
désignation de ces éléments se fait de trois manières différentes :
1. l’élément  CINEMA  est un fils de la position courante : on le désigne simplement par CINEMA ;
2. les éléments de type SALLE sont petit-fils de la position courante, avec comme niveau intermédiaire
 CINEMA  : on les désigne par CINEMA/SALLE qui indique le chemin à parcourir ;
3. enfin les éléments de type FILM sont arrière-petit-fils de la position courante ; on pourrait les
désigner par CINEMA/SALLE/FILM, mais on utilise ici un moyen plus général : .//FILM désigne
tous les éléments descendant de la position courante, quel que soit leur niveau, nommés  FILM  .
Un part importante de la programmation XSLT consiste à savoir désigner, à partir d’un nœud courant
dans l’arbre XML, les éléments auxquels on veut appliquer des règles de transformation. Les quelques
exemples donnés ci-dessus correspondent à des cas restreint, et font notamment l’hypothèse que le chemin
1.3. PUBLICATION DE DONNÉES AVEC XSLT 37

Figure 1.14: Un téléphone mobile avec carte WML

d’accès à un élément se fait en descendant dans l’arbre. Nous verrons que le langage est beaucoup plus
général.
Il reste à créer une règle pour chacun des types de carte. Voici la règle, déclenchée sur les éléments de
type CINEMA, qui produit la carte affichant la liste des salles.
<xsl:template match="CINEMA">
<card id="index" title="Programme">
<p align="center">
<xsl:value-of select="NOM"/>
</p>
<xsl:for-each select="SALLE">
<p> <a href="#S{@NO}">
Salle <xsl:value-of select="@NO"/>:
</a>
<xsl:value-of select="FILM/TITRE"/>
</p>
</xsl:for-each>
</card>
</xsl:template>
Rappelons que tout ce qui ne commence pas par xsl:, indiquant les types d’éléments propres à XSLT,
est considéré comme du texte et inclus dans le résultat. Pour un cinéma, on va afficher avec une boucle
xsl:for-each un paragraphe (élement de type p) pour chaque salle. Ce paragraphe contient l’intitulé
de la salle, et sert également d’ancre (élément  a  ) vers la carte détaillant les séances de la salle. La carte
d’une salle est référencée par #S où  est le numéro de la salle, présent dans l’attribut NO. Avec XSLT,
on crée cet identifiant avec l’expression #S{@NO}.
38 CHAPTER 1. INTRODUCTION À XML ET XSLT

Voici maintenant la règle servant à produire les cartes des salles. Notez que chaque carte comprend un
attribut id ayant pour valeur S où  est le numéro de la salle. On insère une ancre vers la carte détaillant
le film diffusé dans la salle.

<xsl:template match="SALLE">
<card id="S{@NO}">
<p>Séances salle <xsl:value-of select="@NO"/></p>
<p>
<a href="#{FILM/TITRE}">
Film : <xsl:value-of select="FILM/TITRE"/>
</a>
</p>
<xsl:apply-templates select="SEANCES"/>
</card>
</xsl:template>

Enfin la règle produisant la carte des films est identique à celle que nous avons déjà étudiée (exem-
ple 11).

1.3.3 Document papier (PDF)


Chaque type de document a des contraintes spécifiques – affichage, mode d’utilisation – définies par son
interface utilisateur. L’auteur doit prendre en compte la taille de la fenêtre d’affichage, la couleur des pages,
la couleur et la taille des caractères, la possibilité – ou non – d’effectuer un défilement, etc. Ces critères sont
très stricts par exemple pour un téléphone portable dont l’écran est très petit et les manipulations limitées
par un clavier réduit à une quinzaine de touches.
La création d’un document destiné à l’impression est essentiellement différente de ceux destinés au
Web et constitue un changement radical de support. Une page HTML est affichée sur un écran informa-
tique et doit avoir une taille limitée, approximativement égale à la taille de l’écran. De plus la lecture de
documents HTML n’est pas fondée sur un parcours linéaire, de bas en haut et de gauche à droite, mais
sur une « navigation » définie par le hyper-liens. Par contraste, un document papier est organisé en une
séquence de pages, avec un ordre de lecture séquentielle. En conséquence, quand on imprime un document
HTML, le résultat est souvent insatisfaisant. Nous complétons cette présentation de l’utilisation de XSLT
pour la transformation de documents XML avec la production de documents papier grâce aux formatting
objects.

Les formatting objects


Le processus de publication permettant de contrôler le résultat et la qualité de l’impression d’un document
XML s’effectue en deux étapes (figure 1.15) :
1. L’étape de transformation permet de revoir complétement la structure du document XML en ap-
pliquant des règles de transformation. Les éléments d’origine peuvent être remplacés par d’autres
éléments, déplacés, effacés, et de nouveaux éléments peuvent être insérés. On obtient un nouveau
document.
2. L’étape de mise en forme (formatting en anglais) est appliquée après la transformation pour obtenir
un document final adapté au support de publication. Dans le cas d’un document papier, la mise en
forme prend en compte la taille des pages, les marges à respecter, la taille et le poids des caractères,
l’alignement du texte, l’espace entre les paragraphes, l’en-tête et le pied de page, etc.
La recommendation XSL propose un vocabulaire de balises XML, connu sous le nom XSL-FO (FO
est un acronyme pour formatting objects), qui permet la spécification précise des caractéristiques ty-
pographiques d’un document. Un document XSL-FO est un document XML qui peut être utilisé par
différentes applications pour générer un document dans un format d’impression comme Postscript ou PDF.
Voici un premier document XSL-FO :
1.3. PUBLICATION DE DONNÉES AVEC XSLT 39

Document XML Document XSL-FO Document PDF



      

             

 
        
       



                  



             
  
          
       

Transformation Mise en Forme

Figure 1.15: Transformation et Mise en Forme

Exemple 12 SimpleFO.xml : Un document XSL-FO simple


<?xml version="1.0" encoding="iso-8859-1"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="29.7cm" page-width="21cm">
<fo:region-body
margin-top="2cm" margin-bottom="2.5cm"
margin-left="2.5cm" margin-right="2.5cm"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="simple" >
<fo:single-page-master-reference master-name="page" />
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-name=’simple’>
<fo:flow flow-name=’xsl-region-body’ font-size="20pt">
<fo:block>
Ceci est le premier paragraphe,
</fo:block>
<fo:block space-before="20pt" font-size="10pt">
et ceci est le deuxième.
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

Ce document débute par quelques éléments qui indiquent les propriétés globales de la mise en page
souhaitée. Sans entrer dans le détail de chaque balise utilisée, on trouve :
! l’élément " fo:simple-page-master # qui définit la dimension (page-height="29.7cm",
page-width="21cm") des pages ;
! l’élément " fo:region-body # qui fixe l’espace entre la « région » du contenu et les bords de
chaque page (margin-top="2cm", margin-bottom="2.5cm", . . . ) ;
! l’élément " fo:page-sequence-master # qui est utilisé pour définir la structure du document
(par exemple : une table des matières, des chapitres, un index, etc) ;
! enfin l’élément " fo:block # qui défini des paragraphes avec l’espace de séparation (space-
before=”20pt” et la taille des caractères (font-size=”10pt”).
40 CHAPTER 1. INTRODUCTION À XML ET XSLT

Les éléments qui suivent correspondent au contenu du document. Ce dernier contient deux paragraphes
(éléments de type fo:block) dont le deuxième est séparé du premier par un espace de 20 points (space-
before="20pt"). La taille des caractères est aussi 20 points par défaut (font-size="20pt" dans
" fo:flow # ) sauf pour le deuxième paragraphe, où la taille des caractères est limité à 10 points.
Le document obtenu peut maintenant être transmis à un processeur XSL qui va se charger de produire
une réalisation concrète. Nous utilisons le processeur FOP qui produit des documents PDF : il va nous
permettre d’engendrer une version imprimable du programme de L’Épée de bois.

Le programme de L’Épée de bois


On peut maintenant insérer les informations concernant notre cinéma Epée de bois. Pour cela on va définir
deux règles de transformation. La première met en forme le nom et l’adresse du cinéma.

<xsl:template match="CINEMA">
<fo:block text-align="center">
<fo:block font-size="40pt" font-weight="bold" space-after="20pt">
<!-- Sélection du nom du cinema -->
<xsl:value-of select="NOM"/>
</fo:block>
<!-- Sélection de l’adresse du cinema -->
<xsl:value-of select="ADRESSE"/>
<!-- Sélection du métro près du cinema -->
(<xsl:value-of select="METRO"/>)
</fo:block>
<fo:block space-before="20pt">
<!-- Transformer chaque salle -->
<xsl:apply-templates select="SALLE"/>
</fo:block>
</xsl:template>

Le nom du cinéma et son adresse sont des sous-blocs d’un bloc spécifiant que le texte sera centré
(attribut text-align="center"). Le nom du cinéma est écrit en caractères gras de 40 points, suivi
de l’adresse et de la station de métro. Pour afficher les séances, la règle suivante est appelée (élément
" xsl:apply-templates select="SALLE"/ # ) :
<xsl:template match="SALLE">
<fo:block text-align="center" space-before="40pt">
<fo:inline font-weight="bold" font-size="26pt">
<!-- Sélection du titre du film -->
<xsl:value-of select="FILM/TITRE"/>
</fo:inline> de
<fo:inline font-style="italic">
<!-- Sélection de l’auteur du film -->
<xsl:value-of select="FILM/AUTEUR"/>
</fo:inline>
<fo:block space-before="5pt">
<!-- Sélection de l’année et du pays du film -->
(<xsl:value-of select="FILM/PAYS"/>,
<xsl:value-of select="FILM/ANNEE"/>)
</fo:block>
</fo:block>
<fo:block space-before="10pt">
<!-- Sélection du résumé du film -->
<xsl:value-of select="FILM/RESUME"/>
</fo:block>
<fo:block space-before="10pt">
<fo:inline font-weight="bold">
<!-- Sélection du numéro de salle -->
1.3. PUBLICATION DE DONNÉES AVEC XSLT 41

40pt, gras 2cm

26pt, gras 20pt, italique

20pt

29.7cm
2.5cm
2.5cm

2.5cm

21cm

Figure 1.16: Mise en Forme avec XSL-FO

Salle <xsl:value-of select="@NO"/>


</fo:inline>
(<xsl:value-of select="@PLACES"/> places) :
<!-- Sélection des séances -->
<xsl:for-each select="SEANCES/SEANCE">
<xsl:value-of select="."/> -
</xsl:for-each>
<!-- Sélection de la remarque -->
<xsl:value-of select="REMARQUE"/>
</fo:block>
</xsl:template>

Ces deux règles effectuent simultanément la transformation de la structure du document XML et la


mise en forme du résultat sous forme d’un document XSL-FO. Le document XSL-FO peut ensuite être
transformé par un transformateur adapté XSL-FO $ PDF, avec le résultat de la figure 1.16.
En résumé, à partir d’un même document XML, nous sommes en mesure de produire avec un seul
langage des représentations très diverses.
42 CHAPTER 1. INTRODUCTION À XML ET XSLT

1.4 Échange et intégration de données en XML


La technologie XML n’est pas limitée à la génération de pages web (HTML, WAP) ou d’autres documents
plus traditionels. Par sa capacité de représenter des données très diverses, XML a rapidement été promu
comme format universel pour l’échange de données entre différéntes applications informatiques.
Dans cette section nous décrivons l’utilisation de XML comme interface entre plusieurs applications
souhaitant échanger des données. Notre exemple va montrer l’intérêt de XML comme format d’échange
entre serveurs web, mais il s’extrapole facilement à l’utilisation de XML pour échanger des informations
sous forme de messages entre des applications réparties.
Nous mettons plus l’accent sur le processus de transformation impliqué dans ces échanges que sur la
transmission des données qui est liée à l’infrastructure client-serveur et aux protocoles de communication 4.

1.4.1 Exemple : Le Site www.sallesenligne.com


L’utilisation de XML comme format d’échange est illustrée par un site web qui récupère des informations
sur les programmes de cinéma disponibles sur différents sites locaux, les intègre et fournit un moteur de
recherche. La Figure 1.17 montre le site www.sallesenligne.com, relié à de nombreux sites locaux dont
deux, www.cine-marseille et www.epee-de-bois.fr, sont représentés.

réponse

www.cine-marseille.fr requête

www.sallesenligne.fr

www.epée-de-bois.fr

Figure 1.17: Échanges de données du site www.sallesenligne.com

Le moteur de recherche sur les séances de cinéma se base sur le titre du film, le début de la séance
et la ville. L’utilisateur remplit un formulaire avec les critères désirés et obtient une liste des séances
correspondantes avec des liens vers les sites locaux (Figure 1.18).
Le site www.sallesenligne.com offre donc une valeur ajoutée aux informations déjà existantes au niveau
de chaque site élémentaire. En contrepartie, il demande que les informations nécessaires à la recherche lui
soient fournies sous un format XML imposé dont voici un exemple :
<FILM>
<TITRE>Vertigo</TITRE>
<CINEMA>Epée de Bois</CINEMA>
<VILLE>Paris</VILLE>
<URL>www.epée-de-bois.fr/ExCinema1.xml</URL>
<HEURE>22:00</HEURE>
</FILM>

À part le titre, le cinéma, la ville et les heures de projection, l’élément " FILM # contient un sous-
élément de type URL avec l’adresse de la page web du cinéma. Ces informations forment un résumé de
toutes celles disponibles au niveau du site d’un cinéma, et elles sont de plus représentées différemment,
aussi bien au niveau de la structure des documents que du nom des balises utilisées. Le but est donc de
4 Différents choix techniques possibles pour les aspects d’échange et de communication seront étudiés à la fin de ce livre.
1.4. ÉCHANGE ET INTÉGRATION DE DONNÉES EN XML 43

Figure 1.18: Formulaire de saisie et page résultat fourni par le moteur de recherche

convertir le document XML pour chaque cinéma vers la structure définie pour le moteur de recherche, de
transférer cette conversion vers www.sallesenligne.com et enfin d’assembler tous ces fragments dans un
seul document sur lequel s’effectueront les opérations de recherche.

1.4.2 Description de la structure d’un document XML


Pour écrire un programme de transformation, il faut connaître la structure du document à transformer,
mais également la structure du document à engendrer. Comme dans les exemples sur la publication, où la
structure du résultat d’une transformation devait être conforme aux « formats » HTML, WML ou XSL-FO,
l’information exploitée par le moteur de recherche doit « ressembler » à la structure de l’élément " FILM #
précédent.
En l’occurrence, le serveur central veut acquérir des éléments de type FILM, avec des sous-éléments
de type TITRE, CINEMA, VILLE, URL et HEURE. Chaque sous-élément n’apparaît qu’une seule fois sauf
les sous-éléments de type HEURE.
Cette description informelle de la structure des documents XML échangés peut être utilisé pour écrire
un programme XSLT qui génère des « résumés » à partir des documents stockées sur les sites locaux. Pour
éviter les malentendus et ambiguités qui sont possibles dans un langage naturel, il existe des langages plus
formels pour décrire la structure d’un document XML. Nous introduisons ci-dessous la méthode la plus
répandue à l’heure actuelle pour définir des types de documents : les document type definition ou DTD.
Dans une DTD, la structure d’un document XML est spécifiée par la description structurelle des types
d’éléments. Ainsi, à travers une DTD, un élément n’est plus seulement caractérisé par le nom de la balise,
mais également par la structure de son contenu. Par exemple, l’expression
<!ELEMENT TITRE ( #PCDATA ) >
indique que le contenu (aussi appelé modèle de contenu) d’un élément de type TITRE est une chaîne de
caractères (#PCDATA), comme les éléments de type TITRE, CINEMA, VILLE, URL et HEURE.
Le contenu des éléments de type FILM est défini par une expression plus complexe :

<!ELEMENT FILM (TITRE, CINEMA, VILLE, URL?, HEURE+)

Cette expression indique que le contenu d’un élément " FILM # est constitué d’une succession d’éléments
dont les types respectifs sont TITRE, CINEMA, VILLE, URL et HEURE. La séparation des noms d’éléments
par des virgules signifie que l’ordre des éléments est fixé et doit correspondre à la séquence indiquée. Tous
les types d’éléments ne peuvent apparaître qu’une seule fois comme fils d’un élément " FILM # , sauf
l’élément de type URL qui est optionel (ce qui est indiqué par le symbol ?) et les éléments de type HEURE
qui peuvent apparaître plusieurs fois (indiqué par le symbole + après HEURE). Voici la DTD complète,
spécifiant les informations acceptées par le moteur de recherche :
44 CHAPTER 1. INTRODUCTION À XML ET XSLT

Exemple 13 Echange.dtd : DTD des documents acceptés par le moteur de recherche.


<!ELEMENT FILM ( TITRE, CINEMA, VILLE,
URL?, HEURE+ ) >
<!ELEMENT TITRE ( #PCDATA ) >
<!ELEMENT CINEMA ( #PCDATA ) >
<!ELEMENT VILLE ( #PCDATA ) >
<!ELEMENT URL ( #PCDATA ) >
<!ELEMENT HEURE ( #PCDATA ) >

Il est possible d’indiquer, dans l’en-tête d’un document XML, à quelle DTD se conforme le contenu
du document. Cette information, quoique non obligatoire, est très importante car elle définit la classe
des applications qui vont pouvoir interpréter et traiter le document. Réciproquement, une application (par
exemple : un navigateur) est conçue pour traiter la classe de tous les documents XML conformes à une
DTD donnée (par exemple la DTD HTML).
Une feuille de style peut également être considérée comme un programme dédié à une DTD. C’est ce
que nous avons exprimé – de manière peu précise – en signalant qu’un programme de transformation du
document Alien.xml s’applique également à Vertigo.xml. De plus, si le résultat est toujours un document
XML conforme à une autre DTD, un programme XSLT peut être vu comme une conversion de documents
XML entre deux structures bien définies.
Les exemples de publications que nous avons décrits (HTML, WML, XSL-FO) étaient conformes à
ce cadre, puisque pour chacun de ces langages il existe une DTD. Maintenant, XML étant un langage
eXtensible, chacun peut définir sa propre DTD, et la publication XSLT s’étend à la mise en forme de nos
données afin qu’elles soient reconnues et traitées par quelqu’un d’autre. Le cas que nous traitons n’est
donc qu’une généralisation naturelle d’une problématique de publication qui se limiterait à HTML, ou aux
quelques langages largement diffusés.

1.4.3 Transformation et échange de données


L’application – le site central – traite des documents conformes à la DTD Echange.dtd, et les intègre dans
une liste formant un index de toutes les séances de cinémas. La structure de ce document est très simple :
l’élément racine de type MOTEUR contient un sous-élément " FILM # pour chaque film projeté dans un
cinéma. Notez dans l’en-tête la référence à la DTD Moteur.dtd qui décrit la structure du document.

Exemple 14 Moteur.xml : Document XML interrogé par le moteur de recherche


<?xml version="1.0" encoding="ISO-8859-1"?>

<?xml-stylesheet href="MoteurCherche.xsl" type="text/xsl"?>


<?cocoon-process type="xslt"?>

<MOTEUR>
<FILM>
<TITRE>Alien</TITRE>
<CINEMA>Epée de bois</CINEMA>
<VILLE>Paris</VILLE>
<URL>www.epée-de-bois.fr/ExCinema1.xml</URL>
<HEURE>15:00</HEURE>
<HEURE>18:00</HEURE>
<HEURE>21:00</HEURE>
</FILM>
<FILM>
<TITRE>Vertigo</TITRE>
<CINEMA>Epée de bois</CINEMA>
<VILLE>Paris</VILLE>
<URL>www.epée-de-bois.fr/ExCinema1.xml</URL>
<HEURE>22:00</HEURE>
1.4. ÉCHANGE ET INTÉGRATION DE DONNÉES EN XML 45

</FILM>
</MOTEUR>

Afin d’obtenir un résumé du document EpeeDeBois.xml qui puisse être intégré dans le moteur de
recherche, il reste à lui appliquer une transformation à l’aide de la feuille de style suivante.

Exemple 15 Echange.xsl : Transformation XSLT pour échange de données.


<?xml version="1.0" encoding="iso-8859-1" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:output encoding="iso-8859-1"/>

<xsl:template match="/">
<xsl:for-each select=’CINEMA/SALLE’>
<FILM>
<TITRE><xsl:value-of select=’FILM/TITRE’/></TITRE>
<CINEMA><xsl:value-of select=’../NOM’/></CINEMA>
<VILLE>Paris</VILLE>
<URL>www.epée-de-bois.fr/ExCinema1.xml</URL>
<xsl:for-each select=’SEANCES/SEANCE’>
<HEURE><xsl:value-of select=’.’/></HEURE>
</xsl:for-each>
</FILM>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Le mécanisme de transformation devrait maintenant être clair pour le lecteur. Notons que cette trans-
formation peut intervenir soit au niveau de chaque cinéma, qui fait alors l’effort de fournir un programme
de transformation de ses données en escomptant en tirer profit, soit au niveau du moteur de recherche
lui-même.

1.4.4 Un moteur de recherche XML/XSLT


Pour conclure cet exemple, nous allons décrire l’implantation d’un petit moteur de recherche pour trouver
des séances de cinéma dans un document XML. Nous supposons que toutes les informations sont stockées
dans Moteur.xml.

Exemple 16 MoteurHTML.xsl : Programme XSLT pour publier toutes les séances dans Moteur.xml.
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<head> <title>Résultat de la recherche</title> </head>
<body bgcolor="white">
<h1>Résultat de la recherche</h1>
<xsl:apply-templates select=’MOTEUR’/>
</body>
</html>
</xsl:template>

<xsl:template match="MOTEUR">
<xsl:for-each select="FILM">
<xsl:apply-templates select="." /><p/>
46 CHAPTER 1. INTRODUCTION À XML ET XSLT

</xsl:for-each>
</xsl:template>

<xsl:template match="FILM">
Ville: <i> <xsl:value-of select="VILLE"/> </i><br/>
Cinéma: <A HREF=’http://{URL}’>
<xsl:value-of select="CINEMA"/> </A> <br/>
Film: <xsl:value-of select="TITRE"/> <br/>
Séances:
<xsl:for-each select="HEURE">
<xsl:value-of select="."/> -
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Ce programme publie toutes les séances sous forme d’un document HTML. Il peut facilement être
adapté pour sélectionner un sous-ensemble des films à publier en utilisant des paramètres. En occurrence,
pour sélectionner les films à publier, on peut introduire trois paramètres de sélection $titre, $seance
et $ville dans la feuille de style, comme suit :

<xsl:param name="titre"/>
<xsl:param name="seance"/>
<xsl:param name="ville"/>

Ces déclarations globales sont ajoutées après l’élément " xsl:output method="html"/ # et
avant la première règle de transformation. Il suffit ensuite de modifier la règle de transormation pour les
éléments de type MOTEUR en ajoutant une condition de sélection avant la transformation d’un film :
<xsl:template match="MOTEUR">
<xsl:for-each select="FILM">
<xsl:if test=" ($titre = ’’ or TITRE = $titre)
and ($seance = ’’ or HEURE &gt;= $seance)
and ($ville = ’’ or VILLE = $ville)">
<xsl:apply-templates select="." /><p/>
</xsl:if>
</xsl:for-each>
</xsl:template>
L’instruction xsl:if compare le contenu des éléments de type TITRE, HEURE et VILLE avec les
paramètres correspondants. Si la condition est satisfaite, l’élément de type FILM est transformé. Dans le
cas opposé, la boucle xsl:for-each passe au film suivant.
Les valeurs des paramètres formels $titre, $seance et $ville peuvent être obtenues de dif-
férentes manières. Dans le cas d’une application web, on utilise naturellement un formulaire HTML (fig-
ure 1.17) qui passe les paramètres dans l’URL de la feuille de style (méthode GET du protocole HTTP).
On obtient par exemple :
http://wwww.sallesenligne.fr/Moteur.xsl?titre=Vertigo&ville=Paris
En résumé, les programmes XSLT interviennent ici à deux niveaux : pour la transformation des docu-
ments issus de chaque site, en vue d’une uniformisation de la stucture des données telle qu’elle est définie
par la DTD du moteur de recherche, et pour l’extraction sélective de parties du document intégrateur à
l’aide de paramètres.

1.4.5 Intégration dynamique de fragments XML


Dans tous les exemples que nous avons étudiés jusqu’à présent les informations étaient issues de sources
XML, éventuellement transformées au passage par XSLT. Nous allons conclure ce tour d’horizon – partiel
1.4. ÉCHANGE ET INTÉGRATION DE DONNÉES EN XML 47

– des possibilités de publication à partir de XML/XSLT en étudiant la situation où la représentation XML


est produite dynamiquement à partir d’une autre source de données.
Cette notion de dynamicité est maintenant bien établie dans le domaine des sites web. Les sites con-
stitués de pages HTML au contenu figés sont en effet extrêmement difficiles à maintenir, et tout à fait
inappropriés pour interagir avec un internaute qui vient visiter le site, y rechercher des informations, voire
déposer ses propres données. La plupart des sites professionnels sont donc associés à une base de données
qui gère l’information indépendamment de toute représentation, les données étant extraites et mises en
forme « à la volée » par des techniques de programmation spécialisées basées sur l’interface CGI (Common
Gateway Interface). Les principaux langages dédiés à ce type d’application sont Perl, PHP et Java, ce
dernier sous la forme de servlets ou de leur dérivé, les Java Server Pages (JSP).
Dans le cas de PHP ou des JSP, le principe consiste à intégrer dans un document HTML des parties
programmées qui vont se connecter à la base de données (ou à toute autre source d’information), effectuer
des requêtes SQL et formater le résultat de ces requêtes avec des balises HTML. Il est tout à fait souhaitable
de pouvoir faire de même avec XML, dans la mesure où on admet qu’un système d’information ne gére pas
toutes ses données sous forme XML, mais fait appel à des applications spécialisées : traitement de texte,
tableur, annuaire, et bien sûr SGBD.
Notons que PHP ou les JSP sont – du moins à l’heure actuelle – conçus pour être utilisés uniquement
avec HTML. Le scénario que nous considérons ici est plus général, et se déroule en deux étapes. Dans
un premier temps l’organisme ou la société qui souhaite publier une partie du contenu de son système
d’information intégre ce contenu sous une forme homogène XML. Puis, à partir de cette intégration les
différents types de présentation étudiés précédemment (HTML, WML, PDF, etc) sont générés par des
feuilles de styles XSLT.
Nous prenons dans ce qui suit l’exemple d’une intégration dynamique (autrement dit au moment où le
document est utilisé) à partir d’une base de données relationnelle. Cette base contient une table Film dont
nous allons extraire une ou plusieurs lignes.

titre auteur année genre pays résumé


Alien Ridley Scott 1979 USA Science-Fiction Près d’un vaisseau spatial
échoué sur une lointaine
planète, des Terriens en
mission découvrent de bien
étranges "oeufs"...
Vertigo Alfred Hitchcock 1958 Drame USA Scottie Ferguson, ancien in-
specteur de police, est sujet
au vertige depuis qu’il a vu
mourir son collègue...
... ... ... ... ... ...

XML n’est pas un langage de programmation et ne permet donc pas directement d’exécuter des requêtes
SQL pour extraire les données de cette table. Il n’existe pas – pas encore ? – de norme pour définir comment
des parties programmées peuvent être intégrées dans du XML, mais le schéma généralement suivi est celui
illustré dans la figure 1.19.

1. des balises « dynamiques », interprétées par l’application comme correspondant à l’exécution de code
d’accès à une base de données, sont insérées dans le document initial ;

2. avant la transformation par une feuille XSLT, ces balises déclenchent le code qui va extraire des
informations et en faire un fragment XML ;

3. finalement ce fragment vient remplacer les balises « dynamiques » : un document intermédiaire est
obtenu, qui peut être publié avec XSLT.

Nous utilisons en l’occurrence les outils suivants : MySQL pour le SGBD, Java pour le code de con-
nexion et d’interrogation de la base, enfin XSP, un langage qui reprend le principe des JSP et permet
48 CHAPTER 1. INTRODUCTION À XML ET XSLT

Partie Partie
statique statique
Publication
Balises Code <fragment
"dynamiques" XML> XSLT
Partie SQL Partie
statique statique
Base
de données
Document initial Document intermédiaire

Figure 1.19: Architecture d’une intégration XML/Base de données

d’exécuter du code Java inclus dans un document XML. Le mécanisme peut être transposé, mutatis mu-
tandis, à d’autres environnement, par exemple l’environnement XML proposé par Oracle qui propose sen-
siblement le même schéma.
L’exemple développé ci-dessous va extraire la description XML d’un film et l’intégrer dans le document
XML correspondant aux séances de L’Épée de bois.

D’une base relationnelle à XML


Voici pour commencer le code Java qui permet d’accéder à la base MySQL, d’effectuer la requête SQL
recherchant un film (ici c’est Alien) et de le mettre au format XML. Le petit programme ci-dessous utilise
l’interface JDBC (Java Database Connectivity) pour se connecter à MySQL.

Exemple 17 ExJDBC.java : Code Java pour extraire un film au format XML


// D’abord on importe le package JDBC
import java.sql.*;

class ExJDBC
{
public static void main (String args []) throws SQLException
{
// Enregistrement du driver JDBC pour se connecter à
// MySQL
DriverManager.registerDriver(new org.gjt.mm.mysql.Driver());

// Connection à la base
try
{
Connection conn = DriverManager.getConnection
("jdbc:mysql://localhost/Films",
"visiteurFilms", "mdpVisiteur");

// Exécution de la requête qui ramène le film Alien


Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery
("select * from Film where titre=’Alien’");

// Sortie du résultat avec balises XML


while (rset.next ())
{
System.out.println ("<FILM>");
System.out.println ("<TITRE>" + rset.getString (1) + "</TITRE>");
1.4. ÉCHANGE ET INTÉGRATION DE DONNÉES EN XML 49

System.out.println ("<ANNEE>" + rset.getString (2) + "</ANNEE>");


System.out.println ("<AUTEUR>" + rset.getString (3) + "</AUTEUR>");
System.out.println ("<GENRE>" + rset.getString (4) + "</GENRE");
System.out.println ("<RESUME>" + rset.getString (5) + "</RESUME>");
System.out.println ("<PAYS>" + rset.getString (6) + "</PAYS>");
System.out.println ("</FILM>");
}
}
catch (SQLException e)
{
System.out.println ("Problème quelque part !!!");
System.out.println (e.getMessage());
}
}
}

Les commentaires de ce programme devraient suffire à donner une compréhension, ne serait-ce qu’intuitive,
de son fonctionnement. Une requête (au sens large : interrogation ou mise à jour) correspond à un objet
de la classe Statement. Cet objet doit avoir été créé par un objet Connection, ce qui le rattache
automatiquement à l’une des transactions en cours.
La méthode executeQuery, comme son nom l’indique, exécute une requête (d’interrogation) placée
dans une chaîne de caractères. Le résultat est placé dans un objet ResultSet qui, comme son nom
l’indique encore une fois, contient l’ensemble des lignes du résultat.
Un objet ResultSet correspond à la notion de curseur employée systématiquement dans les inter-
faces entre un langage de programmation et SQL. La classe ResultSet propose un ensemble de méth-
odes get*** qui prennent un numéro d’attribut en entrée et renvoient la valeur de cet attribut. L’exécution
de ce programme donne le résultat suivant :

Exemple 18 ExJDBC.xml : Résultat de l’exécution du programme java


<FILM>
<TITRE>Alien</TITRE>
<ANNEE>1979</ANNEE>
<AUTEUR>Ridley Scott</AUTEUR>
<GENRE>Science-fiction</GENRE
<RESUME>Près d’un vaisseau spatial échoué sur une lointaine planète,
des Terriens en mission découvrent de bien étranges "oeufs". Ils
en ramènent un à bord, ignorant qu’ils viennent d’introduire parmi
eux un huitième passager particulièrement féroce et meurtrier.
</RESUME>
<PAYS>USA</PAYS>
</FILM>

On est donc en présence d’une information transitoire, qu’il est possible d’intégrer à un document
statique avant d’effectuer la transformation XSLT.

Intégration Java/XML/XSLT
Maintenant que les films sont dans une base de données, il devient inutile de placer la description d’Alien
ou Vertigo dans des fichiers XML : il est bien préférable de créer à la demande la version transitoire XML,
puis d’appliquer la feuille de style existante.
Voici le nouveau document décrivant Alien, les éléments statiques étant remplacés par du code Java qui
les engendre dynamiquement.

Exemple 19 AlienXSP.xml : La version XML/XSP incluant du code java


<?xml version="1.0" encoding="ISO-8859-1"?>
50 CHAPTER 1. INTRODUCTION À XML ET XSLT

<?cocoon-process type="xsp"?>
<?cocoon-process type="xslt"?>
<?xml-stylesheet href="Film.xsl" type="text/xsl"?>

<xsp:page
language="java"
xmlns:xsp="http://www.apache.org/1999/XSP/Core"
>
<xsp:structure>
<xsp:include>java.sql.*</xsp:include>
<xsp:include>java.util.Date</xsp:include>
</xsp:structure>

<FILM>
<xsp:logic>
DriverManager.registerDriver(new org.gjt.mm.mysql.Driver());
// Connection à la base
Connection conn = DriverManager.getConnection
("jdbc:mysql://localhost/Films",
"visiteurFilms", "mdpVisiteur");
Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery (
"select * from Film where titre=’Alien’");
// Affichage du résultat
while (rset.next ())
{
<TITRE><xsp:expr>rset.getString (1)</xsp:expr></TITRE>
<ANNEE><xsp:expr>rset.getString (2)</xsp:expr></ANNEE>
<AUTEUR><xsp:expr>rset.getString (3)</xsp:expr></AUTEUR>
<GENRE><xsp:expr>rset.getString (4)</xsp:expr></GENRE>
<RESUME><xsp:expr>rset.getString (5)</xsp:expr></RESUME>
<PAYS><xsp:expr>rset.getString (6)</xsp:expr></PAYS>
}
</xsp:logic>
</FILM>
</xsp:page>

Il s’agit d’un document XML, avec un élément racine de type xsp:page et une nouvelle classe
d’éléments XSP dont toutes les balises étant préfixées par xsp:. On retrouve à peu de chose près la
structure du programme Java de l’exemple 17, avec, successivement :

1. l’appel aux packages nécessaires, obtenu avec le type d’élément xsp:include ;

2. l’inclusion directe de code Java dans les éléments de type xsp:logic ;

3. enfin la production avec le éléments de type xsp:expr de chaînes de caractères qui viennent
s’intégrer au document XML.

Le document est traité en deux phases. Dans une première, le code Java est évalué et remplacé par les
chaînes de caractères produites, ce qui revient en l’occurrence à obtenir un fichier – temporaire – décrivant
le film Alien. Dans la seconde phase la feuille de style est apppliquée et on obtient la page HTML.
Le lecteur familier avec les Java Server Pages (JSP) notera que XSP s’en inspire largement : dans les
deux cas on inclut du code dans un langage de balisage, en limitant les parties programmées aux endroits
où des informations dynamiques doivent être insérées. La grande différence est qu’une page JSP mélange
HTML, Java, et même SQL. Ici on a séparé le contenu (en XML) de la présentation (obtenue par un
programme XSLT).
1.5. COMMENT LIRE LA SUITE DE CE LIVRE ? 51

Séparation des points de vue


Il reste cependant un aspect insatisfaisant dans cette séparation des rôles : en incluant directement du code
Java dans du XML, on mélange toujours la gestion du contenu et la « logique » de l’application. Autrement
dit la personne qui est en charge de définir les informations à publier et leur structure, est également
confrontée au code qui permet de produire ces informations. Idéalement ces deux points de vues devraient
également être séparés. C’est ce que permet l’utilisation de balises « dynamiques ». En voici un exemple :

Exemple 20 AlienXSPLib.xml : Le document pour Alien avec balise dynamique


<?xml version="1.0" encoding="ISO-8859-1"?>

<?cocoon-process type="xslt"?>
<?xml-stylesheet href="FilmXSP.xsl" type="text/xsl"?>

<FILM xmlns:BDFilm="http://cortes.cnam.fr/XBOOK">
<TITRE>Alien</TITRE>
<BDFilm:film titre=’Alien’/>
</FILM>

Cette fois plus aucun code n’apparaît dans le document qui est réduit à une extrême simplicité. Une
nouvelle classe de balises, BDFilm, a été définie pour servir d’interface avec la base de données. La balise

<BDFilm:film titre=’Alien’/>

exprime de la manière la plus simple qui soit une demande d’insertion de la représentation XML d’Alien.
Par un mécanisme propre au serveur d’application, et que nous ne décrirons pas ici, le processeur va
associer cette balise au code Java/JDBC présenté précédemment, constituer la représentation XML tempo-
raire du film, puis appliquer la transformation XSLT.
On obtient, avec cette architecture, une séparation complète des rôles :

1. la logique de l’application est codée en Java (ou tout autre langage reconnu par le serveur), ce qui
autorise tous les calculs, accès aux bases de données, échanges réseaux et appels de services divers
et variés ; l’information obtenue est rendue disponible par l’intermédiaire d’une librairie de balises
(taglib) ;

2. le contenu est intégré sous forme XML, à partir de sources d’informations qui peuvent être des
fichiers, des sites, ou les balises des librairies ;

3. enfin la présentation est obtenue par un ensemble de programme XSLT.

1.5 Comment lire la suite de ce livre ?


Le moment est venu de récapituler ce premier chapitre, et de voir comment il fournit la clé pour appréhender
le contenu de ce livre, et donc en guider la lecture.

Récapitulatif
En utilisant XML, nous rendons notre contenu indépendant du format propre à une application donnée.
Du même coup, nous dissocions ce contenu de toute signification intrinsèque. Un document XML n’a pas
d’autre interprétation que celle qu’un traitement particulier va lui associer à un moment donné. Prenons
deux exemples pour bien clarifier cette notion :

1. quand un traitement de texte sauvegarde un document dans son format propriétaire, ce format a une
signification, définie par le rendu qu’en fait le traitement de texte lors d’un affichage à l’écran ; il n’y
a rien de tel avec XML puisqu’un document est indépendant de toute application ;
52 CHAPTER 1. INTRODUCTION À XML ET XSLT

2. dans une page HTML, on trouve également des balises, mais la différence essentielle est que la
signification de ces balises est fixée, dans un contexte donné à l’avance qui est l’affichage dans la
fenêtre d’un navigateur : une balise " BR # correspond à un saut de ligne, et ne s’interprète pas
librement.
Ce qui compte en XML c’est la structure, à savoir l’arbre correspondant à un document, et l’utilisation
de noms d’éléments comme moyen pour différencier ou au contraire grouper de nœuds. En revanche le
choix des noms lui-même est sans importance et on aurait tout aussi bien pu utiliser pour décrire notre
cinéma les balises " A # , " B # , " C # et " D # ou les balises " MOVIE # , " NAME # , " ADDRESS # et
" SUBWAY # sans modifier la structure.
Chacun est donc libre de définir, en fonction de ses besoins, son propre langage basé sur XML (XML est
parfois présenté comme un méta-langage – un langage pour définir des langages). C’est ce que nous avons
fait pour décrire nos séances de cinéma, c’est ce que font également les navigateurs web avec (X)HTML,
les mobiles avec WML, etc. Tous ces langages partagent des règles de structuration communes, ce qui
permet de leur appliquer des outils standards (édition, analyse) et de passer de l’un à l’autre sans difficulté
majeure.

Échange et intégration avec XML


Le rôle de XML comme langage d’échange et d’intégration de données découle des caractéristiques qui
précèdent. Dans beaucoup de cas, un système d’information confie ses données à des logiciels spécialisés
dans une tâche donnée (serveur web, base de données, fichiers de configuration, etc) et les rend du même
coup impropres à une utilisation autre que celle à laquelle elles ont été initialement affectées.
Transformer ses données au format XML, temporairement ou définitivement, revient à les rendre
disponibles pour d’autres applications et d’autres utilisateurs. Intégrer ces informations, issues de sources
diverses, dans un format commun, permet à la fois de donner une vision uniforme des informations, et
d’éviter de confronter le responsable de la publication à des logiciels et langages divers et complexes. De
fait la connaissance de XSLT suffit.

Publication XML/XSLT
Il existe des applications qui sont conçues pour travailler sur des documents XML ayant une structure
particulière, et utilisant une terminologie (un nommage des nœuds) spécifique. De telles applications
définissent la signification de tels documents, en fournissant un mise en forme (sur écran ou sur papier) ou
un mode de traitement (insertion dans une base de données, envoi de messages) de leur contenu.
L’exemple typique est fourni par un document HTML – ou, pour être plus précis, XHTML – qui obéit à
des règles de structuration et de nommage particuliers. Un document XHTML est un document XML, mais
doit impérativement avoir pour racine " HTML # , cette racine ayant elle-même des sous-éléments " HEAD #
et " BODY # (dans cet ordre), etc. Tout document conforme aux règles de structuration XHTML peut être
affiché dans un navigateur web qui interprète les balises du documents comme des commandes de mise en
forme à l’écran.
XHTML n’est qu’un des exemples possibles de « dialecte » XML, et la présentation de XML comme
un « super-HTML » ou comme un HTML « extensible » est selon nous une source de confusion. XHTML
ne constitue qu’un des nombreux exemples de format de données décrit par un langage plus général et
universel, XML. En d’autres termes, XML peut être considéré comme un outil pour définir des formats
de données qui sont liés à des applications spécifiques. Nous verrons dans ce livre plusieurs exemples de
dialectes XML, dont WML pour l’affichage sur des téléphones mobiles, RSS, une norme de description de
documents utiles pour les annuaires de liens, SMIL, un format dédié aux présentation multimédia, etc. Ces
dialectes de XML sont définis par des Document Type Definition (DTD).
À partir d’un document XML donné, il est possible d’effectuer des transformations du contenu afin
d’obtenir des représentations spécialisées qui peuvent alors être traitées par les applications. Il existe de
nombreuses techniques et outils pour effectuer de telles transformations. La perspective adoptée par ce
livre est celle d’une transformation avec des feuilles de style XSLT. Une feuille de style applique une
conversion à un document XML. Il est bien entendu possible de définir plusieurs feuilles de style pour un
même document, ce qui aboutit à un mécanisme de publication de contenu illustré dans la figure 1.20.
1.5. COMMENT LIRE LA SUITE DE CE LIVRE ? 53

Base de Message
Fichiers
données XML

Transformation
XSLT
XSLT Document XML

XSLT XSLT
XSLT XSLT

Contenu
Page XHTML Page WML Document XML
formaté

application web application édition application WAP application XML

Figure 1.20: Intégration XML, et transformations XSLT

Cette figure décline quelques-unes des situations qui seront explorées dans les prochains chapitres.
Pour un même document XML, on obtient par des transformations XSLT :

1. une ou plusieurs pages XHTML constituant un site web ;


2. un formatage adapté à un traitement de texte, en vue de faire de l’édition ;
3. des « cartes » WML pour communiquer par le WAP avec des téléphones mobiles ;
4. enfin on peut imaginer toute conversion d’un dialecte XML vers un autre, l’objectif dans ce cas étant
de faire communiquer des applications en vue de réutiliser des informations existantes.

En résumé, XML est un langage de description de données qui vise à l’universalité en se basant sur
un principe simple : le contenu est séparé de la présentation, et la manière dont ce contenu est constitué
est elle-même indépendante de la production d’une présentation. On obtient un processus de publication
en plusieurs étapes, chacune relevant d’une compétence particulière, ce qui constraste avec les techniques
courantes de productions de site qui impliquent la maîtrise et l’emploi simultané d’un grand nombre de
techniques et d’outils.

Organisation des chapitres qui suivent


La suite de ce livre reprend de manière systématique tous les thèmes abordés dans ce qui précède. Le
chapitre 3 donne une description complète de la syntaxe XML, et introduit les opérations applicables à un
document XML. Le chapitre 4 reprend de manière rigoureuse le langage XSLT, tandis que les chapitres 5 et
6 développent l’utilisation de XSLT pour effectuer des transformations vers des DTD courantes : HTML,
WML, SMIL, RSS, XSL-FO... Les chapitres suivants continuent l’exploration des transformations XSLT,
en y ajoutant des processus d’intégration et d’échanges de données.
Nous espérons que la lecture de ce premier chapitre aura permis de clarifier les choix d’organisation qui
ont été faits, et donneront l’opportunité au lecteur, en fonction de ses compétences, de choisir éventuelle-
ment un ordre de lecture différent.
54 CHAPTER 1. INTRODUCTION À XML ET XSLT
Chapter 2

Documents XML : structure et


navigation

Sommaire
2.1 La syntaxe XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.1.1 Déclaration XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
2.1.2 Déclaration du type de document et des entités . . . . . . . . . . . . . . . . . . 57
2.1.3 Commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.1.4 Instructions de traitement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.1.5 Éléments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
2.1.6 Attributs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
2.1.7 Espaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.1.8 Sections CDATA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.1.9 Références d’entités . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.1.10 Balises, données caractères et valeur textuelle . . . . . . . . . . . . . . . . . . 62
2.2 Le modèle DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.2.1 Types de nœuds DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.2.2 Interface DOMString . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
2.2.3 Interfaces NodeList et NamedNodeMap . . . . . . . . . . . . . . . . . . . . . 66
2.2.4 Interface Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
2.2.5 Interface Document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
2.2.6 Interfaces Element et Attr . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
2.2.7 Interfaces DocumentType, Entity et EntityReference . . . . . . . . . . . . . 74
2.3 Du document sérialisé à l’arbre DOM . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.3.1 Construction d’un arbre DOM . . . . . . . . . . . . . . . . . . . . . . . . . . 76
2.3.2 Traitement des espaces pendant la construction . . . . . . . . . . . . . . . . . . 78
2.3.3 Deux fonctions de navigation . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
2.4 Le langage XPath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
2.4.1 Représentation XPath d’un document XML . . . . . . . . . . . . . . . . . . . 82
2.4.2 Expressions XPath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
2.4.3 Les axes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
2.4.4 Les filtres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
2.4.5 Prédicats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
2.4.6 Types et opérations XPath . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
2.4.7 Exemples d’expressions XPath . . . . . . . . . . . . . . . . . . . . . . . . . . 107

55
56 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Nous approfondissons dans ce chapitre la notion de document XML, en mettant l’accent sur la structure
d’un document et sur la navigation dans cette structure. Ces deux aspects sont en effet à la base de la
programmation XSLT.
Nous suivons la démarche adoptée dès l’introduction, consistant à considérer un document XML
comme un arbre. Ce point de vue a le grand avantage d’être indépendant de l’origine du document et de
faire abstraction de sa représentation physique ou textuelle : la représentation arborescente est conceptuelle
et a pour but de décrire sans ambiguïté la structure et le contenu d’un document. Ce n’est pas le cas d’une
représentation textuelle ou « sérialisée » où un même contenu peut être représenté avec des constructions
syntaxiques différentes. Par exemple un élément vide a une seule représentation dans l’arborescence (un
nœud sans fils) mais possède deux représentations textuelles équivalentes : " a #%" /a # et " a/ # . Un
autre exemple d’une tel ambiguïté est le caractère ’>’ qui peut-être représenté par ’&#62;’ et ’&gt;’ dans
un document XML.
Nous décrirons la structure arborescente d’un document XML en nous appuyant sur un modèle normal-
isé de représentation et de manipulation de données XML, le modèle DOM. Dans la suite, et quand il est
nécessaire de distinguer explicitement les deux types de représentation, nous utiliserons le terme document
sérialisé pour désigner la représentation textuelle d’un document XML et le terme arbre DOM pour sa
représentation arborescente.
Avant d’être transmis à un traitement, quel qu’il soit, un document XML (sérialisé) est traité par un
processeur XML ou parseur qui va analyser son contenu et déterminer sa structure. Dans le cas d’un
parseur DOM le résultat de cet analyse est un arbre DOM. Dans tous les cas, cette phase d’analyse peut
échouer si le document n’est pas bien formé, autrement dit s’il ne respecte pas la syntaxe du langage XML.
Bien que cette syntaxe ne soit pas nécessaire pour expliquer le fonctionnement de XSLT proprement dit,
il est important de bien comprendre comment un document XML est transformé en arborescence DOM et
inversement.
Nous utiliserons également le modèle DOM (Document Object Model) pour compléter notre descrip-
tion de la structure d’un document par les opérations de navigation dans ce document. DOM fournit une
spécification orientée-objet basée sur des méthodes d’investigation et d’extraction de données. Bien que
cette spécification définisse de manière précise les opérations sur un arbre XML, sa mise en œuvre en pra-
tique nécessite le recours à un environnement de programmation comme Java. Le langage XPath, étudié
dans la seconde partie de ce chapitre, offre un outil plus simple pour déclarer des chemins complexes
d’accès à des éléments. C’est XPath qui est utilisé dans XSLT, et pas les opérations DOM, mais il est
important de signaler dès maintenant que l’évaluation d’un programme XSLT peut être décrite en DOM
(même si le système lui-même n’utilise pas nécessairement cette API), et que la compréhension de ce
modèle donne donc la clé d’une bonne interprétation des règles XSLT.

2.1 La syntaxe XML


Les documents XML sont la plupart du temps créés, stockés ou échangés sous une représentation textuelle
ou sérialisée qui « marque » la structure par des formes syntaxiques (essentiellement des balises) mêlées au
contenu textuel. Nous donnons maintenant les règles syntaxiques de base pour représenter des documents
XML sérialisés. Nous verrons dans la section suivante comment on passe de cette représentation à une
représentation arborescente sous forme d’un arbre DOM.
Commençons par l’exemple d’un document XML dont le contenu – sommaire – résume les principaux
aspects syntaxiques du langage.

Exemple 21 ExXML4.xml : Illustration de la syntaxe XML


<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!DOCTYPE A SYSTEM "minimal.dtd" [
<!ENTITY monTexte "texte simple">
<!ENTITY maSignature SYSTEM "signature.xml">
]>
<!-- Instruction de traitement -->
<?xml-stylesheet href="prog.xslt" type="text/xslt"?>
2.1. LA SYNTAXE XML 57

<A>
Du &monTexte;, sans caractères réservés:
ni &lt; ni &gt; ni &amp; ni &apos; ni &quot;
<B> contenu texte </B>
<!-- Un élément vide -->
<C/>
<D attr1="1" attr2="azerty">
<B>Encore &monTexte;,</B>
</D>
<![CDATA[Du texte <non interprété> &monTexte;]]>
&maSignature;
</A>

Cet exemple va nous servir de support à la présentation des différents composants d’un document XML.

2.1.1 Déclaration XML


La déclaration XML est une balise spéciale qui doit apparaître au début du document. Sa forme minimale
indique la version de la norme XML à laquelle se conforme le document :

<?xml version="1.0"?>

Cette information est principalement destinée au traitement qui va analyser le document, afin qu’il
puisse tenir compte des éventuelles variantes de syntaxe entre les différentes versions XML. On peut aussi
lui associer des attributs (voir plus loin) caractérisant le document. Nous utilisons par exemple systéma-
tiquement l’attribut encoding avec la valeur ISO-8859-1 qui indique un codage de caractères « latin »
incluant les caractères accentués.
L’attribut (optionnel) standalone indique si le document XML contient des références vers d’autres
fichiers ou « entités externes » (voir plus loin) qui doivent être chargées pendant l’analyse du document. La
valeur yes permet au processeur XML de savoir qu’il n’est pas nécessaire d’accéder à d’autres sources
pour analyser et restituer le document XML en entier. Dans notre exemple nous avons défini stan-
dalone=’no’ (qui est aussi la valeur par défaut) car, comme nous allons le voir maintenant, il contient
une référence vers une entité externe.

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>

La déclaration de document est uniquement destinée au parseur, et n’est plus « visible » dans l’arborescence
DOM d’un document XML. On ne peut donc y avoir accès dans un traitement XSLT.

Contrainte : La déclaration XML est optionnelle, mais sa présence est cependant recommandée. Si elle
est présente, elle doit être la première ligne du document.

2.1.2 Déclaration du type de document et des entités


La balise spéciale " !DOCTYPE # définit la DTD (Définition du Type de Document) qui est une description
générale de la structure du document. Cette description peut être entièrement incluse dans la balise sous
forme de déclarations locales, mais le plus souvent on fait appel à une source externe (ce peut être un nom
de fichier local, ou une URL). La forme générale de la déclaration est alors :
" !DOCTYPE nomDocument SYSTEM "sourceExt" [decLoc] #
Cette déclaration indique tout d’abord que le document est de type nomDocument. Après le mot-clé
SYSTEM on trouve l’URL sourceExt qui correspond à un fichier avec des déclarations externes sur la
structure du document. Les déclarations locales decLoc sont entourées des symboles [ et ].
Un problème bien connu des URL pour identifier des unités d’informations comme une page HTML ou
un fichier DTD est l’utilisation d’un mécanisme d’adressage physique. Ce type d’adressage est risqué dans
un environnement évolutif où les serveurs Web changent d’adresse et où les fichiers sont déplacés d’un
58 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

répertoire à l’autre. Pour remédier à ce problème, XML propose également l’utilisation « d’identificateurs
publics », qui seront décrits dans le chapitre 4.
Les entités fournissent un moyen de factoriser des fragments XML et des réutiliser en plusieurs en-
droits. Dans notre exemple, les déclarations d’entités sont locales (comprises entre les crochets [ ]) mais
il peuvent également faire partie du fichier externe sourceDTD. Notre document ExXML4.xml, page 56,
contient la déclaration d’une entité interne (une simple chaîne de caractères) et d’une entité externe (un
fichier) :

<!ENTITY monTexte "texte simple">


<!ENTITY maSignature SYSTEM "signature.xml">

Le nom de la première entité est monTexte et sa valeur texte simple. La deuxième entité a le
nom maSignature et sa valeur est définie par le contenu du fichier signature.xml. Les deux entités
peuvent ensuite être référencées dans le document par leur nom.

Contrainte : La déclaration du type de document est optionnelle. Si elle est présente, elle doit apparaître
avant le premier élément du document.

2.1.3 Commentaires
Un commentaire est une zone de texte libre encadrée par " !-- et -- # . Il peut contenir n’importe quel
texte, à l’exception de --, selon n’importe quelle disposition (sauts de lignes par exemple). Le commen-
taire suivant est syntaxiquement correct (bien formé) :

<!-- Instruction de traitement <?xml-stylesheet ...> -->

Les deux commentaires suivants ne sont pas corrects :

<!-- erreur: -- n’est pas permis -->


<!-- erreur: --->

Le deuxième commentaire n’est pas bien formé, car un commentaire ne doit pas terminer par « ---> ».

Contrainte : Les commentaires peuvent être placés n’importe où dans le document, sauf dans une balise.

2.1.4 Instructions de traitement


Les instructions de traitement (processing instructions) sont conçues pour intégrer des instructions propres
à un processeur particulier dans un document XML. Toute instruction apparaît dans une balise de la forme
" ?nomInstruction attributs # . Nous utiliserons par exemple très souvent l’instruction suivante
qui indique à un processeur XSLT l’adresse du fichier qui contient le programme pour la transformation du
document :

<?xml-stylesheet href="prog.xslt" type="text/xslt">

Le mot qui suit le « ? » est la cible (target), le reste constituant le contenu de l’instruction de traitement.
Il faut noter que la déclaration de document XML, bien que conforme à la définition syntaxique, n’est pas
une instruction de traitement. De plus, le nom de cible ’xml’ (en minuscule, majuscule ou mélangé) est
réservé pour des versions futures du standard XML.

Contrainte : Les instructions de traitement peuvent être placés n’importe où dans le document, sauf dans
une balise.
2.1. LA SYNTAXE XML 59

2.1.5 Éléments
Les éléments constituent le principal composant d’un document XML. La représentation sérialisée de
tout élément se compose d’une balise ouvrante " balise # , de son contenu et d’une balise fermante
" /balise # . La présence des balises ouvrantes et fermantes est obligatoire. En revanche le contenu
d’un élément peut être vide. Il existe alors une convention qui permet d’abréger la notation. L’élément vide
<C></C>

peut être noté


<C/>

Le contenu d’un élément peut aussi – et surtout – être constitué d’une combinaison arbitrairement
complexe de commentaires, d’autres éléments, de références entités et de sections de texte (voir plus loin).
Par exemple, le contenu de l’élément de type A dans le fichier ExXML4.xml est une telle combinaison de
catégories syntaxiques.

Contrainte : Tout document comprend un et un seul élément racine qui définit le contenu même du doc-
ument.

Notre exemple ExXML4.xml contient un élément racine de type A. Le document suivant n’est pas bien
formé car il a deux éléments racine.

<?xml version="1.0"?>
<A>Un premier contenu</A>
<B>Un deuxième contenu</B>

Contrainte : Le nom du type de l’élément racine doit être identique au nom du type de document (si
celui-i est présent).

Le document suivant n’est pas bien formé car le type de l’élément ne correspond pas au type du docu-
ment :
<?xml version="1.0"?>
<!DOCTYPE A SYSTEM "fichier.dtd">
<B>contenu</B>

Le nom d’une balise, qui correspond au type de l’élément (voir plus loin), peut comprendre des lettres
de l’alphabet, des chiffres, les caractères « - », « _ », mais pas de blanc ni de lettres accentuées. De plus
le nom ne doit pas commencer par un chiffre. Enfin XML distingue les majuscules des minuscules, et la
balise " NOM # sera donc considérée comme distincte de la balise " nom # (ces deux balises définissent
deux éléments de types différents). Sous réserve de ces quelques restrictions, les noms d’élément sont
libres en XML : il n’existe pas de nom réservé.

2.1.6 Attributs
Un élément peut avoir des attributs. Les attributs apparaissent toujours dans la balise ouvrante, sous la
forme nom="valeur" ou nom=’valeur’, séparés par un espace blanc (voir plus loin). Les noms
d’attributs suivent les mêmes règles que les noms d’éléments.

Contrainte : La balise ouvrante d’un élément ne doit pas contenir deux attributs avec le même nom.

Par exemple le fragment XML suivant n’est pas bien formé :


<A at1=’1’ at1=’2’/>
60 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Pour ceux qui auraient l’habitude des pratiques assez laxistes de HTML, il est bon de noter que
! un attribut doit toujours avoir une valeur, donc la balise HTML " OPTION SELECTED # n’est pas
du XML bien formé ;
! la valeur doit toujours être comprise entre des apostrophes simples (’10’) ou des guillemets ("10") ;
la valeur elle-même peut contenir des apostrophes simples si elle est encadrée par des guillemets, et
réciproquement ;

Une caractéristique essentielle de XML est que l’ordre des attributs d’un élément n’est pas significatif.
L’élément :

<A at1=’1’ at2=’2’/>

est donc identique à :

<A at2=’2’ at1=’1’/>

Autrement dit tout traitement doit donner le même résultat, indépendamment de l’ordre des attributs.
En pratique il faudra toujours accéder à un attribut par son nom, et pas par sa position.
Il existe plusieurs noms d’attribut réservés dans XML (tous commencent par le préfixe xml:) :
! xml:lang : cet attribut permet d’indiquer la langue utilisée dans le contenu d’un élément. Les
codes utilisés pour les langues sont définis par le standard IETF RFC 1766. Par exemple, les codes
en, fr et de indiquent respectivement des contenus en Anglais, Français et Allemand.
! xml:space : cet attribut précise le traitement des espaces dans le contenu d’un élément. Il a deux
valeurs possibles, default ou preserved. Dans le premier cas, c’est l’application qui détermine le
traitement des espaces. Dans le second cas, tous les espaces doivent être préservés par l’application.
! le nom d’attribut xmlns et tous les noms qui commencent par xmlns: sont également réservés
pour la spécification d’espaces de nom.

Remarque : Les espaces de nom (namespace) constituent un aspect important de XML : ils seront décrits
de manière approfondie dans le chapitre 6.

2.1.7 Espaces
Les espaces jouent un rôle spécial dans la représentation syntaxique d’un document XML. Un « espace » est
une chaîne de caractères composée uniquement de caractères espace blanc (Unicode #x20), retour chariot
(Unicode #x9), line feed (Unicode #xD) et tabulation (Unicode #xA) (voir page 64 pour plus de détails sur
le standard Unicode).
Généralement les espaces blancs servent comme séparateurs entre les différents composants syntax-
iques d’un document sérialisé. Par exemple, le fichier ExXML4.xml contient 18 lignes, c’est à dire 18
retours chariot. On voit également que, pour augmenter la lisibilité, le même document contient des es-
paces (#x20) pour souligner la structure hiérarchique du document.
À priori un parseur XML doit transmettre tous les espaces à l’application exploitant le document (par
exemple au processeur XSLT). Néanmoins, un programme XSLT permet de spécifier une prise en compte
spécifique des nombreux espaces apparaissant dans un document XML. Il est courant par exemple d’ignorer
tous les espaces en dehors de l’élément racine d’un document ou des éléments qui contiennent uniquement
un espace blanc. Il est surprenant de constater que la gestion des espaces constitue un point très délicat
dans la manipulation de documents XML. Nous aurons donc souvent l’occasion de revenir sur le traitement
des espaces et la la distinction entre espaces significatifs et non-significatifs.
2.1. LA SYNTAXE XML 61

2.1.8 Sections CDATA


Il peut arriver que l’on souhaite placer dans un document du texte qui ne doit pas être analysé par le parseur.
C’est le cas par exemple :

1. quand on veut inclure de code de programmation qui contient des caractères réservés dans XML : les
’ " ’ et ’&’ abondent dans du code C ou C++ ;

2. quand le document XML est consacré lui-même à XML, avec des exemples de balises que l’on
souhaite reproduire littéralement.

Les sections littérales CDATA définissent une zone qui n’est pas analysée par le parseur, et est donc
transmise telle quelle au programme traitant le document XML (par exemple un programme XSLT). Notre
petit exemple contient une section CDATA :

<![CDATA[Du texte <non interprété> &monTexte;]]>

Cette section est transmise littéralement, et correspond donc à


Du texte <non interprété> &monTexte;

Il est clair que le traitement de ce contenu mènerait à résoudre les références à l’entité monTexte, et à
tenter d’interpréter " non interprété # comme une balise, ce qui d’ailleurs échouerait car il ne s’agit
pas d’un nom d’élément valide.

2.1.9 Références d’entités


Chaque référence à une entité doit se faire sous la forme &nom; où nom est le nom de l’entité. En pratique,
dans un programme XSLT on considère que le parseur du document a remplacé toutes les références aux
entités par leur valeur. Par exemple, la référence
&monTexte;

dans le document ExXML4.xml est remplacée par sa valeur, et on obtient :


texte simple

Cela signifie que nous n’avons pas à nous soucier des entités dans nos programmes XSLT puisque
ceux-ci travaillent sur la représentation du document obtenue à l’issue de la phase de parsing, et donc après
résolution des références aux entités.

Remarque : Le remplacement des références vers les entités par leur valeur n’est pas une obligation im-
posée par la recommandation XML. L’avantage d’un tel remplacement est une programmation plus facile
qui n’est pas obligée de se préoccuper de la composition physique d’un document XML.

La syntaxe XML permet de spécifier des caractères par leur code Unicode. Ainsi, au lieu d’écrire C
en majuscule, on peut également utiliser la référence &#67; où l’entier 67 correspond à l’Unicode de ce
caractère. Ce mécanisme de référencement est utile& pour inclure des caractères qui ne se trouvent pas sur
le clavier qu’on utilise. Par exemple, le caractère « c » dont le code est soit 169, soit xA9 en hexadécimal
( ')(+*'-,+.0/213'),4/ , le symbole « x » après ’#’ indiquant que le code est en hexadécimal) peut être inclus
dans un document XML par des références vers des entités caractères #169; ou #xA9;.
Mais les références vers les entités caractères sont surtout utiles pour inclure des caractères avec une
signification spécifique dans la syntaxe XML : « < », « > », « & », « ’ » et « " ». Par exemple, pour inclure
le symbole « < » dans le texte sans qu’il soit interprété par le processeur XML comme le début d’une balise
on peut utiliser la référence &#60;.
À priori, toutes les entités référencés dans un document XML doivent être déclarées dans sa DTD. Il
existe deux exceptions : les entités caractères et les entités du tableau 2.1 si le document n’a pas de DTD :
Notre exemple contient le fragment suivant :
62 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Déclaration entité (prédéfinie) Référence Caractère


<!ENTITY lt "&#60;"> &lt; <
<!ENTITY gt "&#62;"> &gt; >
<!ENTITY amp "&#38;"> &amp; &
<!ENTITY apos "&#39;"> &apos; ’
<!ENTITY quot "&#34;"> &quot "

Table 2.1: Entités caractères prédéfinies dans un document XML sans DTD

Du &monTexte; , sans caractères réservés:


ni &lt; ni &gt; ni &amp; ni &apos; ni &quot;

Ce qui donnera, après résolution des références aux entités le texte suivant :
Du texte simple, sans caractères réservés:
ni < ni > ni & ni ’ ni "

Les entités externes permettent quant à elles d’inclure le contenu d’un fichier.
<!ENTITY maSignature SYSTEM "signature.xml">

On peut donc insérer le contenu de signature.xml par une simple référence &maSignature;. Ce mé-
canisme permet de constituer un document par assemblage de plusieurs autres, éventuellement accessibles
sur le réseau. Par défaut, on suppose que le fichier inclus se trouve au « même endroit » que le document
principal, mais il est également possible de définir un chemin d’accès différent à travers une URL absolue.
XML distingue entre deux types d’entités externes : les entités XML (parsed entities) et les entités
non-XML (unparsed entities) :
! Une entité XML doit être conforme à la définition du contenu d’un élément. Ainsi une entité externe
peut être un document XML bien-formé mais aussi un fragment XML avec plusieurs (ou sans) élé-
ments racines mélangés avec des sections de texte et des commentaires. Ce fragment doit néanmoins
être bien-formé et « complet » dans le sens où toutes les balises ouvrantes sont fermées dans la même
entité.
! Une entité non-XML peut être un fichier avec n’importe quel contenu comme par exemple une image
ou un fichier audio. Ce contenu ne respecte évidemment pas la syntaxe XML ce qui a comme con-
séquence, qu’il ne peut pas faire partie du contenu d’un élément. XSLT ne prévoit pas un traitement
spécifique pour les références vers les entités non-XML dans un document XML.
Une entité externe peut contenir des références vers d’autres entités et, pour chaque document XML,
on peut créer une arborescence d’entités (plus précisément un graphe acyclique) qui se réfèrent. La racine
de cette arborescence est le document XML, également appelé entité document.

2.1.10 Balises, données caractères et valeur textuelle


La représentation sérialisée d’un document XML est un texte composé de balises (markup) et de données
caractères (character data). Les balises permettent de séparer et d’identifier les différentes catégories
syntaxiques qui précèdent et définissent les instructions et déclarations utiles pour constituer, structurer,
valider et interpréter le contenu « textuel » d’un document XML. Dans XML, tout ce qui ne relève pas
l’une des catégories syntaxiques suivantes constitue donc les données caractères d’un document :
! la déclaration du document <?xml ....> ;
! la déclaration de type (si présente) <?DOCTYPE ...> ;
! les commentaires <!--... --> ;
! les instructions de traitement ;
2.1. LA SYNTAXE XML 63

! les références d’entités (interne et externe) ;


! les balises d’éléments (ouvrantes, fermantes et vides) ;
! les séparateurs des sections CDATA (sans leur contenu) : <![CDATA[ et ]]> : le texte entre ces
séparateurs contient des données caractères !

Les données caractères représentent toute la partie textuelle d’un document XML qui n’est pas inter-
prétée par un parseur. Par exemple, les données caractères du document ExXML4.xml sont les suivantes
(les espaces sont représentés par « _ » et les retours chariots par « | ») :
|
|
__|
__|
|
|
|
|
__Du_,_sans_caractères_réservés:|
__ni__ni__ni__ni__ni_|
___contenu_texte_|
___Un_élément_vide_|
__|
__|
___Encore_,|
__|
__Du_texte_<non_interprété>_&monTexte;|
__|
On voit que les retours chariots et les espaces font partie des données caractères d’un document et que les
références vers les entités ont disparu. Ainsi, les données caractères ne correspondent pas exactement au
contenu « textuel » d’un document s’il contient des références vers des entités. Pour faire cette distinction,
nous allons utiliser le terme valeur textuelle pour désigner les données caractères d’un document (ou d’un
élément) une fois remplacées toutes les références aux entités par leur valeur. Par exemple, la valeur
textuelle de l’élément A dans le document ExXML4.xml est :

|
__Du_texte_simple,_sans_caractères_réservés:|
__ni_<_ni_>_ni_&_ni_’_ni_"|
___contenu_texte_|
__|
__|
__|
___Encore_texte_simple,|
__|
__Du_texte_<non_interprété>_&monTexte;|
__signature|

Dans la valeur textuelle de l’élément toutes les références ont été remplacées par leur valeur (nous avons
supposé que le fichier signature.xml contient uniquement la chaîne de caractères « signature »). On
peut remarquer que le contenu d’une section CDATA correspond à sa valeur textuelle.
Un autre exemple de la différence entre les données caractères dans un document ou d’un élément et
sa valeur textuelle concerne les espaces. À priori un parseur XML doit transmettre tous les espaces qui ne
font pas partie de sections de balisage à l’application exploitant le document (par exemple au processeur
XSLT). Néanmoins, les espaces peuvent interprétés différemment selon l’endroit où ils apparaissent.
64 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Par exemple, les espaces qui se trouvent avant l’élément racine et ne font pas partie du contenu du
document ont « moins » de signification que ceux qui se trouvent dans le contenu d’un élément. Nous
reviendrons plusieurs fois sur le traitement des espaces blancs dans XML et XSLT (pages 74 et chapitre 3).

Remarque : La notion de valeur textuelle ne fait pas partie de la recommandation XML, mais a été intro-
duite dans XSLT.

2.2 Le modèle DOM


Un document XML, quelle que soit sa représentation de départ, correspond à une structure arborescente,
et c’est sur cette structure que s’applique le traitement XSLT. Dans la mesure en effet où l’exécution d’un
programme XSLT consiste – en simplifiant beaucoup – à se positionner sur des éléments et à produire
du texte en « piochant », à partir de l’élément courant, des parties du contenu du document XML, le pro-
cesseur XSLT doit se baser sur une représentation d’ensemble du document qui supporte les opérations de
navigation et d’extraction. Ce serait très difficile sur une représentation sérialisée, c’est plus facile, nous le
verrons, sur une représentation arborescente.
Comme nous l’avons mentionné au début de ce chapitre, une des normes de description d’une structure
XML est le Document Object Model, DOM1 . La modélisation DOM d’un document XML consiste à
décrire ce document comme un graphe composé d’objets appartenant à un ensemble déterminé de types de
nœuds, la composition des objets étant régie par des règles qui définissent la grammaire de XML.
DOM est une spécification de haut niveau, indépendante d’un langage particulier. Une connaissance des
concepts orientés-objet de base est donc suffisante. Nous donnons une première présentation des aspects
essentiels de cette spécification, avant de la compléter par des exemples.

2.2.1 Types de nœuds DOM


Dans sa représentation DOM, un document XML est essentiellement un arbre constitué de nœuds de dif-
férents types. Les types de nœuds sont définis sous forme d’interfaces. Ainsi, un document XML devient
un objet qui contient d’autres objets avec des propriétés et méthodes qui peuvent être utilisées pour écrire
des applications XML2 . Le tableau 2.2 résume tous les types de nœuds fournis par DOM.

Type de Nœuds Catégorie syntaxique XML


Document document XML (racine)
DocumentType type du document (DTD)
ProcessingInstruction instruction de traitement
Element élément XML
Attribute attribut XML
Entity déclaration d’entité
EntityReference référence vers entité
Comment commentaire
CharacterData commentaire et section de texte
Text section de texte
CDataSection section CDATA
DocumentFragment fragment de document XML
Notation notation (fait partie de la DTD)

Table 2.2: Types de nœuds DOM

1 La
présentation qui suit correspond au DOM (Core) Level 1.
2 Comme Java, DOM utilise la notion d’interface pour souligner l’indépendance d’un langage de programmation et d’une implan-
tation spécifique. Nous allons utiliser dans la suite le terme type DOM pour souligner les aspects structuraux et interface DOM pour
les aspects liés à la programmation.
2.2. LE MODÈLE DOM 65

La plupart de ces interfaces (onze sur treize) correspondent aux différents catégories syntaxiques XML
que nous avons décrites page 56. Les seules exceptions sont DocumentFragment et Notation :
! L’interface DocumentFragment est essentiellement destinée à faciliter la programmation et corre-
spond à une version allégée de l’interface Document. Elle peut être ignorée sans dommage dans le
contexte XSLT.
! L’interface Notation correspond à une notion faisant partie de la DTD du document et elle permet
à une application XML de choisir les actions pour traiter des données non-XML dans le contenu du
document.
Tous ces interfaces sont considérées par DOM comme des spécialisations d’une interface Node dont ils
héritent toutes les propriétés et méthodes. La figure 2.1 montre cette hiérarchie de spécialisation (l’interface
DocumentFragment n’apparaît pas dans la figure). Les interfaces TreeNode, Leaf et Container montrées

Node

Attribute TreeNode

Leaf Container

Character Processing Entity Document


Notation Entity Document Element
Data Instruction Reference Type

Comment Text

CData
Section

Figure 2.1: Hiérarchie de spécialisation des interfaces DOM

dans la figure 2.1 ne font pas partie du modèle DOM, mais nous les avons ajoutées pour clarifier le rôle des
différents interfaces dans une arborescence DOM :
! l’interface TreeNode permet de différentier les attributs XML qui correspondent à des nœuds de type
Attr des autres nœuds d’une arborescence DOM : nous revenons sur cette question ci-dessous ;
! parmi les nœuds de type TreeNode nous distinguons ceux qui acceptent des fils (type Container), et
ceux qui sont forcément des feuilles de l’arbre (type Leaf ).
Le modèle DOM spécifie une interface de programmation qui permet soit de modifier un document,
soit de l’inspecter en vue d’en extraire des informations, point de vue que nous privilégions. Toutes ces
opérations sont disponibles sous forme de propriétés3 , et de méthodes propres à chaque type de nœud.
3 Nous utilisons le mot propriété au lieu de celui, plus couramment employé, d’attribut afin de ne pas introduire de confusion avec

les attributs XML.


66 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Avant d’y revenir en détail, nous introduisons trois interfaces supplémentaires qui définissent quelques
structures de données nécessaires à représentation complète d’une arborescence DOM. Ces interfaces ne
sont pas représentées dans la hiérarchie de la figure 2.1.

2.2.2 Interface DOMString


Dans le modèle DOM, comme dans la syntaxe XML, une chaîne est une séquence de caractères Unicode.
Ce système d’encodage est largement répandu dans les applications informatiques et aussi utilisé, par
exemple, dans le langage Java pour la représentation des chaînes de caractères (le type DOMString peut
être directement implanté par le type String de Java). Le standard Unicode définit chaque caractère par un
entier sur deux (16-bit Unicode) ou quatre octets (16-bit Unicode étendu). Plus précisément, DOM (et la
recommandation XML) distingue entre
5 les caractères blancs : #x9 (tabulation), #xA (saut à la ligne), #xD (retour chariot) et #x20. Générale-
ment, on utilise une représentation héxadécimale qui permet de représenter une valeur par deux sym-
boles dans l’ensemble 6-798;:;:):<8>=98;?48;:;:):@8>ACB . Ainsi, les entiers #x9, #xA, #xD et #x20 correspondent
aux entiers 9, 10, 13 et 32 dans le système décimal pour la représentation des entiers ;
5 les caractères 16-bit Unicode dont les valeurs héxadécimales sont comprises entre #x21 et #xD7FF,
et entre #xE000 et #xFFFD ;
5 les caractères 16-bit Unicode étendu, dont les valeurs héxadécimales sont comprises entre #x10000 et
#x10FFFF et entre #xE000 et #xFFFD. Bien que la représentation interne des caractères « étendus »
soit deux fois plus longue (4 octets) que la représentation des autres caractères (2 octets), tous sont
considérés comme des caractères simples (une position) dans les fonctions qui calculent la taille
d’une chaîne de caractères ou la position d’un caractère.

Dans DOM, la comparaison de deux chaînes de caractères s’effectue sur la représentation Unicode de
leurs caractères et prend donc en compte ainsi la casse des chaînes comparées.

2.2.3 Interfaces NodeList et NamedNodeMap


DOM définit deux interfaces supplémentaires permettant de constituer des groupes de nœuds. Ces deux
interfaces sont utilisées pour décrire les résultats de certaines méthodes.
Le type NodeList correspond à la notion de tableau indicé. Il représente une liste (ordonnée) de nœuds.
Ces nœuds ne sont pas tous forcément de même type. NodeList peut permettre par exemple la manipulation
de l’ensemble des fils d’un nœud de l’arbre, parmi lesquels on peut trouver des nœuds de type Text,
Element, CDataSection, etc.
Le type NamedNodeMap correspond à la notion de tableau associatif (ou table de hachage). Il sert
à représenter un ensemble (donc sans ordre) de nœuds identifiés par un nom. Ce type est essentiellement
destiné à gérer une liste d’attributs XML.

2.2.4 Interface Node


Le type Node est la racine de toutes les autres interfaces proposées par DOM. Il définit les propriétés
essentielles et fournit la plus grande part des opérations importantes dans DOM.
Les propriétés spécifiées par l’interface Node sont récapitulées dans le tableau 2.3. Les trois premières
permettent de déterminer les informations « locales » concernant un nœud, c’est-à-dire son type, son nom
et sa valeur sous forme d’un objet de type DOMString. Le nom et la valeur ne constituent pas des notions
pertinentes pour tous les types de nœuds : un nœud de type Text par exemple n’a pas de nom, et un nœud
de type Element n’a pas de valeur.
On peut remarquer que dans une spécification objet plus rigoureuse l’information sur le nom ou la
valeur ne devrait pas apparaître à un niveau global Node mais au niveau d’une interface spécialisée spé-
cifique aux sous-types de Node ayant soit un nom, soit une valeur, soit les deux. DOM n’adopte pas
une telle approche, d’une part parce que XML s’y prête assez difficilement, d’autre part pour des raisons
2.2. LE MODÈLE DOM 67

Propriété Type
nodeType unsigned short
nodeName DOMString
nodeValue DOMString
parentNode Node
firstChild Node
lastChild Node
childNodes NodeList
previousSibling Node
nextSibling Node
attributes NamedNodeMap

Table 2.3: Propriétés du type Node

d’efficacité de l’implantation. On peut donc accéder à toutes les opérations nécessaires au niveau du type
Node, à charge pour le programmeur de tester le type d’un objet appartenant à l’interface générique Node
pour savoir quelles sont les opérations appropriées (technique dite de casting, à éviter en principe dans une
approche objet). La propriété NodeType est justement destinée à effectuer ce test.
Cette conception constitue une limite de DOM, modèle qui se trouve à mi-chemin entre une mod-
élisation conceptuelle rigoureuse et indépendante de l’implantation, et des compromis techniques im-
posées par des critères d’efficacité ou de facilité de développement. L’inconvénient est qu’il faut connaître
l’interprétation des propriétés en fonction du type de nœud, ce que présente le tableau 2.4.

Type de nœud nodeName nodeValue


CDATASection #cdata-section contenu de la section CDATA
Comment #comment contenu du commentaire
Document #document NULL
DocumentType nom de la DTD NULL
Element nom de l’élément NULL
ProcessingInstruction nom de la cible le contenu (moins la cible)
Text #text contenu du nœud Text
Notation nom de notation (voir page 154) NULL
Entity nom de l’entité NULL
EntityReference nom de l’entité référencée NULL
Attr nom de l’attribut valeur de l’attribut

Table 2.4: Interprétation des propriétés nodeName et nodeValue

La figure 2.2 montre une instance d’un document DOM, avec des choix de représentation que nous
adopterons dans toute la suite de ce livre et qu’il est bon de souligner dès maintenant.

Dans chaque nœud figurent trois informations : le type DOM (première ligne en gras), son nom (deuxième
ligne) et la valeur (troisième ligne). Comme souligné précédemment, le nom et la valeur ne sont pertinents
que pour certains types de nœuds. Par exemple les nœuds DOM de type Text ont une valeur mais pas
de nom, ce que nous représentons par un symbole « – » dans la deuxième ligne, et, à l’inverse, les nœuds
DOM de type Element ont un nom, mais pas de valeur. Dans ce cas la troisième ligne est absente.
L’arbre DOM de la figure 2.2 contient neuf nœuds dont deux sont des attributs. Pour simplifier la
description de cet arbre, nous identifions chaque nœud par un entier ou un caractère (s’il s’agit d’un attribut)
écrit entre parenthèses à côté du type du nœud. La racine (nœud 1) du document est de type Document
et contient un fils unique (2) de type Element. L’élément racine a deux attributs (notés a et b) et deux
sous-éléments (3 et 5) de type Element. Le premier élément, de type B (il ne faut pas confondre le type
68 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Document (1)
-

Element (2)
A

Attr (a) Attr (b) Element (3) Element (5)


at1 att2
val1 val2
B B

Texte (4) Comment (6) Texte (7)


- - -
texte 1 comment texte 2

Figure 2.2: Instance d’un arbre DOM

d’un nœud DOM avec le type d’un élément) et contient un seul nœud de type Text ; le deuxième élément
contient un commentaire et du texte. Si on parcourt cet arbre à partir de la racine, en allant de gauche
à droite et en profondeur d’abord, on obtient la séquence de nœuds 1 2 3 4 5 6 7 (on remarque que les
attributs n’apparaissent pas dans ce parcours).

Propriétés structurelles de Node


La structure arborescente et les liens qui permettent de se déplacer dans cette structure sont représentés par
les autres propriétés (sauf attributs) de l’interface Node (tableau 2.3, page 67).
Parmi les propriétés structurelles, la plus importante est childNodes qui est de type NodeList et donne
la liste des fils d’un nœud de type Container. La structure générale d’un arbre DOM est montrée dans
la figure 2.3. Pour chaque type de nœud on indique les enfants possibles par un arc. Tous les arcs sont
étiquetés par childNodes[], le symbole [] indiquant que les fils sont stockés sous forme d’une liste ordonnée.

childNodes[]
childNodes[]
Leaf Container

Figure 2.3: Structure générale d’un arbre DOM

Voici les autres propriétés :

1. parentNode référence le père d’un nœud ;

2. firstChild et lastChild référencent respectivement le premier et le dernier fils ;

3. previousSibling et nextSibling référencent respectivement le frère gauche et le frère droit 4 . Deux


nœuds sont sibling s’ils ont le même père, mais pas s’ils sont au même niveau dans l’arbre mais avec
des pères différents.

Le tableau 2.5 montre la « valeur » de ces propriétés pour quelques nœuds de l’arbre DOM présenté dans
la figure 2.2 : pour les propriétés parentNode, firstChild, lastChild previousSibling et nextSibling la valeur
correspond à une référence vers un nœud représenté par son identificateur. La propriété childNodes retourne
une liste de nœuds (NodeList) qui est représentée par une séquence d’entiers entre crochets. Finalement,
4 Le mot sibling en anglais désigne indifféremment le frère ou la sœur, et n’a malheureusement pas d’équivalent en français. Nous

utiliserions volontiers le mot « sœur » si « nœud » était du genre féminin...


2.2. LE MODÈLE DOM 69

la propriétés attributes retourne un ensemble d’attributs (NamedNodeMap) que nous représentons sous
forme d’un ensemble d’identificateurs d’attributs (un ensemble est noté {} pour le différentier d’une liste).
Bien entendu, tout ou partie de ces valeurs peuvent être à NULL (non définies) : il ne peut pas y avoir
de père pour un nœud de type Document, pas de fils, de frère précédent ou suivant pour tous les nœuds de
type Leaf.
Toutes les propriétés structurelles précédentes s’appliquent à tous les nœuds DOM (même les attributs)
et contiennent comme valeur pour les nœuds qui ne sont pas de type Container des listes vides (par exemple
pour childNodes) ou la valeur NULL. Il faut noter que la propriété parentNode n’est pas définie pour les
nœuds de type Attribute.

Propriété Nœud Valeur


parentNode 1 NULL
2 1
firstChild 5 6
6 NULL
lastChild 5 7
6 NULL
childNodes 2 [3, 5]
4 NULL
previousSibling 3 NULL
5 3
nextSibling 2 NULL
3 5
attributes 2 {a, b}
4 NULL

Table 2.5: Propriétés structurelles pour l’arbre DOM de la figure 2.2

Des propriétés comme firstChild ou lastChild ne font jamais référence à des attributs. Le dernière
propriété de l’interface Node que nous n’avons pas détaillé est attributes. Cette propriété, seulement définie
pour les éléments, est de type NamedNodeMap qui fournit un ensemble d’opérations pour inspecter et
mettre à jour les attributs d’un élément.

Remarque : Bien que l’interface NamedNodeMap permette de choisir un attribut par son nom (méthode
getNamedItem()) et par sa position (méthode item()), rappelons que les attributs d’un élément ne
sont pas ordonnés. En d’autres termes, si deux éléments se distinguent seulement par l’ordre des attributs
dans la propriété attributes, ils sont considérés comme identiques.

Opérations du type Node

Passons maintenant aux opérations du type Node, données dans le tableau 2.6. Elles permettent de modifier
un document en ajoutant, remplaçant et supprimant les fils d’un nœud. Les méthodes hasChildNodes()
et hasAttributes() permettent de vérifier l’existence de fils ou d’attributs et la méthode cloneN-
ode() permet de créer une copie d’un nœud (ainsi que de tous ses descendants si la valeur du paramètre
booléen prof est true).
Certaines de ces opérations ne sont pas autorisées sur certains types de nœuds, comme par exemple
l’insertion d’un fils pour un nœud de type Text. Il est donc de la responsabilité de celui/celle qui programme
un traitement de s’assurer qu’aucune opération interdite ne pourra être déclenchée par le traitement, ce qui
là encore montre que DOM ne s’appuie que partiellement sur les concepts orientés-objet.
70 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Résultat Méthode Paramètres Explication


Node insertBefore() Node nouv, Insertion du nœud nouv avant le fils
Node fils fils; retourne nouv
Node replaceChild() Node nouv, Remplacement du fils anc par le nœud
Node anc nouv; retourne anc
Node removeChild() Node fils Suppression de fils dans la liste des fils;
retourne fils
Node appendChild() Node nouv Ajout du nœud nouv à la fin de la liste des
fils; retourne nouv
boolean hasChildNodes() Retourne vrai si le nœud à des fils et
faux sinon
Node cloneNode() boolean prof Retourne une copie du nœud

Table 2.6: Opérations du type Node

Exemple: parcours d’un arbre DOM


Les propriétés et les méthodes de l’interface Node peuvent être utilisées pour créer des programmes. Par
exemple, la fonction suivante réalise un parcours d’un arbre DOM en pré-ordre, c’est-à-dire en profondeur
à gauche :

fonction parcours_préordre(Node nœud) {


print nœud D id;
print ’ ’;
si nœud D hasChildNodes()
pour tous les nœuds fils dans nœud D childNodes
parcours_préordre(fils);
}

La fonction parcours_préordre() prend un nœud DOM comme argument et utilise les propriétés
nodeName et childNodes et la méthode booléenne hasChildNodes() de l’interface Node. La propriété
id ne fait pas partie de l’interface Node et elle donne les identificateurs des nœuds que nous avons introduit
plus haut.
L’application de cette fonction à un nœud imprime d’abord l’identificateur du nœud suivi d’un espace,
vérifie ensuite si le nœud a des fils et, si c’est le cas, effectue un parcours pour chacun des fils dans l’ordre
de la liste childNodes. Le résultat affiché par la fonction parcours_préordre() pour tous les nœuds
dans l’arbre de la figure 2.2 est donné dans le tableau 2.7.

Appel de fonction Paramètre Résultat affiché


parcours_préordre() 1 1234567
2 234567
3 34
4 4
5 567
6 6
7 7

Table 2.7: Parcours en pré-ordre de l’arbre DOM de la figure 2.2

Pour les feuilles (4, 6 et 7), la fonction affiche uniquement leurs identificateurs. Pour les nœuds 3
et 5, elle affiche l’identificateur du nœud suivi de ses enfants (qui sont des feuilles). En remontant dans
2.2. LE MODÈLE DOM 71

l’arborescence on arrive à la racine qui produit l’affichage de tous les nœuds du documents (sauf les at-
tributs) dans l’ordre.
Comme nous l’avons déjà remarqué, l’ordre des nœuds est significatif (toujours en excluant les attributs
XML). Deux documents ayant les mêmes nœuds mais pas dans le même ordre seront donc considérés
comme différents. Cette notion d’ordre est reflétée par le type de la propriété childNodes qui est une
liste de nœuds et permet de distinguer les fils d’un élément par leur position (le premier fils, le deuxième,
etc. . . ). Ceci signifie, en pratique, qu’un traitement qui parcourt la liste des fils d’un élément ne donnera
pas forcément le même résultat si l’ordre vien à changer.
Reprenons, par exemple, l’arbre de la figure 2.2, mais en changeant l’ordre des fils de la racine et de
ceux du nœud 5 (la figure 2.4).

Document (1)
-

Element (2)
A

Attr (a) Attr (b) Element (5) Element (3)


at1 att2
val1 val2
B B

Texte (7) Comment (6) Texte (4)


- - -
texte 2 comment texte 1

Figure 2.4: Instance d’un arbre DOM avec un ordre différent

Maintenant, si on applique la fonction parcours_préordre() aux nœuds de l’arbre de la fig-


ure 2.4, on constate que le résultat dans le tableau 2.8 est différent du résultat du parcours de l’arbre
d’origine.

Appel de fonction Paramètre Résultat affiché


parcours_préordre() 1 1257634
2 257634
3 34
4 4
5 576
6 6
7 7

Table 2.8: Parcours en pré-ordre de l’arbre DOM de la figure 2.4

2.2.5 Interface Document


La structure d’un document XML bien formé doit respecter des contraintes précises. Ainsi, chaque arbre
DOM qui correspond à un document XML a une seule racine de type Document qui représente la racine
d’un document XML (à distinguer de l’élément racine du document). Dans un arbre DOM, tout accès au
contenu d’un document passe donc initialement par ce nœud.
Le nœud Document doit obéir aux règles suivantes :
72 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

5 il a une liste de fils comprenant un nombre quelconque de nœuds de type ProcessingInstruction,


Comment et un – un seul – nœud de type Element. Ce nœud est l’élément racine du document ;
5 il peut avoir (ce n’est pas obligatoire) un fils de type DocumentType qui doit apparaître avant
l’élément racine et qui correspond à la définition du type du document (voir page 154).

Les nœuds qui précèdent l’élément racine constituent le prologue du document XML, et les nœuds qui
suivent l’épilogue.

Nom Type
doctype DocumentType
implementation DocumentImpl
documentElement Element

Table 2.9: Propriétés du type Document

Le tableau 2.9 donne les propriétés du type Document. La propriété doctype est de type Document-
Type et contient la DTD du document XML. Elle est à NULL si la DTD est absente. La propriété imple-
mentation est utilisée pour référencer l’objet « créateur » du document de type DocumentImpl. Souvent,
mais pas obligatoirement, cet objet correspond au parseur qui génère une représentation DOM à partir d’un
document XML. Finalement, la propriété documentElement référence l’élément racine du document.
Un nœud de type Document fournit des opérations permettant de créer tous les autres nœuds d’un arbre
DOM. Ce type d’objet agit donc comme une « fabrique » des différents types de nœuds d’une arborescence
DOM. Le tableau 2.10 donne quelques-unes de ces opérations :

Résultat Méthode Paramètres


Element createElement() DOMString nom
Text createTextNode() DOMString texte
Comment createComment() DOMString texte
CDATASection createCDATASection() DOMString texte
ProcessingInstruction createProcessingInstruction() DOMString cible, texte
Attr createAttribute() DOMString nom
EntityReference createEntityReference() DOMString nom

Table 2.10: Opérations du type Document

Chaque méthode createX() crée un objet de type X à partir des paramètres qui sont fournis sous
forme de chaînes de caractères de type DOMString (voir section 2.2.2). Nous avons vu dans la section 2.1
que ces chaînes de caractères doivent respecter quelques contraintes quand il s’agit d’un nom d’élément,
d’un nom d’attribut ou d’une cible dans une instruction de traitement (ProcessingInstruction). En partic-
ulier, ils ne doivent pas contenir d’espaces.

2.2.6 Interfaces Element et Attr


Un élément XML est un arbre et peut contenir des commentaires, du texte, des références vers les entités
et d’autres éléments. De plus, un élément peut avoir zéro, un ou plusieurs attributs. Nous avons déjà
souligné qu’un attribut est de type Node mais n’est pas traité de la même façon que les autres nœuds d’un
arborescence DOM. Il existe plusieurs raisons à cette distinction :
5 les attributs ne peuvent apparaître que comme fils d’un élément ;
5 les attributs d’un élément ne sont pas ordonnés ;
5 un élément ne peut pas avoir plusieurs attributs de même nom.
2.2. LE MODÈLE DOM 73

Pour toutes ces raisons, on peut considérer chaque élément à la foi comme un nœud dans un arbre
DOM, et comme la racine d’un arbre non-ordonné dont les fils sont des attributs. Ces deux rôles d’un
élément sont indépendants : on ne mélange jamais les fils « DOM » d’un élément et ses fils de type Attr.
Cette distinction est illustrée dans la figure 2.5 par la représentation de deux compositions différentes.

attributes{}
Element Attribute

childNodes[]

TreeNode

Figure 2.5: Structure d’un élément

Les opérations définies pour les éléments sont données dans le tableau 2.11.

Résultat Méthode Paramètres Explication


DOMString getAttribute() DOMString Retourne la valeur de l’attribut
name name
DOMString setAttribute() DOMString Affecte la valeur value à l’attribut
name, name ; retourne value
DOMString
value
void removeAttribute() DOMString Supprime l’attribut avec le nom
name name de la liste d’attributs
Attr removeAttributeNode() Attr oldAttr Supprime l’attribut oldAttr et re-
tourne l’attribut supprimé
Attr getAttributeNode() DOMString Retourne la valeur de l’attribut
name name
Attr setAttributeNode() Attr newAttr Insère l’attribut newAttr dans la
liste des attributs (si un attribut du
même nom existe déjà il est rem-
placé); retourne l’attribut remplacé
ou NULL
NodeList getElementsByTagName() DOMString Retourne la liste des éléments de-
name scendants dont le type est égal
à name; le résultat est trié dans
l’ordre d’un parcours en pré-ordre
void normalise() normalise le contenu textuel d’un
élément : un élément normalisé ne
contient pas de nœuds de type Text
adjacent (tous sont fusionnés en un
seul nœud).

Table 2.11: Opérations du type Element

L’opération de normalisation est utile si on a ajoute plusieurs nœuds de type Text consécutifs comme
fils d’un élément : dans la version sérialisée du même élément, ces fils consécutifs ne peuvent plus être
distingués l’un de l’autre. Ainsi, l’application de la méthode normalise() à tous les éléments d’un
arbre DOM donne un nouvel arbre qui correspond exactement à l’arbre qu’on obtient par une sérialisation
suivie d’une analyse par un parseur DOM. Cela peut être important dans le cas où on utilise des opérations
qui dépendent du nombre ou de la position des fils d’un élément.
74 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

2.2.7 Interfaces DocumentType, Entity et EntityReference


La Document Type Definition (DTD) d’un document XML est représentée par un nœud de type Docu-
mentType. Il est optionnel et ne peut apparaître qu’une seule fois dans un arbre DOM, comme propriété
du nœud Document. Dans DOM, la seule information qui est accessible à partir de cette interface est la
liste d’entités et de notations déclarés dans la DTD.
La notion d’entité permet de décomposer un document en plusieurs entités physique qui sont référencées
dans le un document. Les interfaces Entity et EntityReference sont surtout importantes pour le passage
d’une représentation sérialisée à une représentation DOM. Elles permettent de rassembler des informa-
tions distribuées pour créer un nouveau document et représentent précisément la structure physique d’un
document XML.
Une fois la représentation DOM créée, la structure physique initiale devient peu importante et on peut
se concentrer sur la vision logique du document. Nous n’allons pas nous appesantir sur ces notions plus
que nécessaire, et considérerons que les références aux entités sont résolues (autrement dit la référence est
remplacée par la valeur) au moment de l’application d’un programme XSLT. Ainsi, avec la disparition des
entités, la DTD d’un document devient une boîte noire qui ne peut plus être examinée par un programme
XSLT.

2.3 Du document sérialisé à l’arbre DOM


Nous allons maintenant comparer la version « sérialisée » d’un document XML avec sa représentation
sous forme d’un arbre DOM. Cette comparaison permet de comprendre le passage d’une représentation à
l’autre : dans le sens XML – E DOM, ce passage correspond à l’analyse d’un document texte par un parseur
(processeur XML) qui construit une arborescence DOM pour le traitement du document par un programme.
Le sens DOM – E XML correspond à la sérialisation d’un arbre DOM, sous forme de document texte.
Voici un document XML contenant des éléments avec attributs.
Exemple 22 ExXML2DOM1.xml : Fichier XML avec attributs
<?xml version=’1.0’ encoding="ISO-8859-1"?>
<A at1="val1">
<B>du texte</B>
<C>
<D at2="0">autre texte</D>
<D at2="1">texte</D>
</C>
</A>

Le premier attribut est défini dans l’élément F A E . Son nom est at1 est sa valeur est val1. Cet
élément a deux fils F B E et F C E dont le premier contient un texte et le deuxième contient de nouveau
deux fils avec un attribut at2 chacun. L’arbre DOM correspondant est montré dans la figure 2.6.

Les attributs sont également représentés sous forme de nœuds dans l’arbre DOM (figure 2.6). Nous
leur affectons une représentation différente à cause de leurs caractéristiques spécifiques.
Voici un autre exemple avec une instruction de traitement et un commentaire :
Exemple 23 ExXML2DOM2.xml : Document XML avec instructions de traitement et commentaires
<?xml version=’1.0’ encoding="ISO-8859-1"?>
<?xml-stylesheet href="feuille.xsl" type="text/xsl"?>
<A>
<C>
<!-- un commentaire -->
<D at1="1">un &lt; et un &gt;</D>
</C>
</A>
2.3. DU DOCUMENT SÉRIALISÉ À L’ARBRE DOM 75

Document
-

Element
A

Element Attr Element


at1
B val1
C

Texte Element Element


- D D
du texte

Texte Attr Attr Texte


- at2 at2 -
autre texte 0 1 texte

Figure 2.6: Représentation DOM du fichier XML

Ce document contient une instruction de traitement dans la deuxième ligne – bien que syntaxiquement
conforme à la définition, la première ligne du document n’est pas une instruction de traitement. La cible
de cette instruction est xml-stylesheet et elle indique au processeur XSLT l’URL du programme et
le type du transformation à appliquer. Enfin le commentaire dans la cinquième ligne est une description
courte de l’élément qui suit. Les instructions de traitement et les commentaires sont également représentés
sous forme de nœuds dans l’arbre DOM (figure 2.7). On peut également constater que les références &lt;
et &gt; on été remplacées par leurs valeurs respectives dans le fils de type Texte de l’élément D.

Document
-

Instruction
xml-stylesheet Element
A
href="feuille.xsl" type="text/xsl"

Element
C

Comment Element
- D
un commentaire

Attr Text
G H
at1 -
1 un et un

Figure 2.7: Représentation DOM avec commentaires et instructions de traitement

Au moment de l’analyse, le processeur se base sur des caractères réservés comme F , E et & pour
structurer le document. En contrepartie le contenu textuel ne peut pas contenir de balises, ni même de
caractères comme F ou E puisque ceux-ci vont être interprétés comme faisant partie du marquage. Les
sections CDATA permettent de prévenir cette interprétation.

Exemple 24 ExXML2DOM3.xml : Document XML avec une section CDATA


<?xml version=’1.0’ ?>
<A>
&lt;B&gt;
<![CDATA[
76 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

<?xml version=’1.0’ ?>


<A>
&lt;B&gt;
&lt;/B&gt;
</A>
]]>
&lt;/B&gt;
</A>

Dans l’exemple ci-dessus, le contenu textuel du document XML comprend le contenu d’un nœud de
type Text (« Voici l’exemple d’un document XML ») et le contenu d’une section CDATA. La figure 2.8
montre l’arbre DOM correspondant.

Document
-

Element
A

CDATASection
-
G ?xml version=’1.0? H
Text
- G H A Text
-
G H
B &lt;B&gt; G/B H
&lt;/B&gt;
G /AH
Figure 2.8: Représentation DOM avec un nœud de type CDATASection

2.3.1 Construction d’un arbre DOM


Nous allons maintenant étudier plus en détail le schéma de construction d’un arbre DOM à partir d’un
document XML sérialisé. Voici un fichier XML simple avec quatre éléments :

Exemple 25 ExXML2DOMa.xml : Fichier XML


<?xml version=’1.0’ encoding="ISO-8859-1"?>
<A>
<B>texte simple</B>
<C>
<D> </D>
</C>
</A>

Le document XML est représentée linéairement sous la forme d’une chaîne de caractères, et structuré
à l’aide de balises qui peuvent être distinguées des informations textuelles par les symboles F et E qui les
entourent. La construction de l’arbre DOM consiste à parcourir cette chaîne séquentiellement en appliquant
l’algorithme ci-dessous, décrit à l’aide des opérations DOM qui ont été présentées dans la section 2.2.

Document fonction parseDoc(Stream fic){


Document document = new Document;
appeler parse(fic, document, document);
retourner document; }
2.3. DU DOCUMENT SÉRIALISÉ À L’ARBRE DOM 77

fonction parse(Stream fic, Document document, Node père) {


Node fils;
DOMString fragmentXML;
DOMString filsType;
boolean finNode = false;
tant que le flux fic n’est pas vide et not finNode {
fragmentXML = lireToken(fic);
si fragmentXML est une balise fermante
finNode = true;
sinon {
filsType = getType(fragmentXML);
fils = document D create(filsType) ;
père D appendNode(fils);
si filsType est un sous-type de Container
appeler parse(fic, document, fils);
sinon
fils D value = extractValue(fragmentXML);
}
}
}
Voici quelques explications :
5 La fonction parseDoc() peut être considérée comme une implantation simplifiée d’un parseur
DOM : elle prend comme argument un fichier XML fic et retourne un document de type Document
qui est le résultat de l’analyse. Elle crée tout d’abord un nœud de type Document qui est ensuite
envoyé comme paramètre à la fonction parse().
5 La fonction parse() effectue l’analyse du fichier fic passé en paramètre. En plus des paramètres,
elle définit quatre variables qui représentent respectivement un fils du nœud à construire (fils), son
type (filsType), un fragment du document XML (fragmentXML) à analyser et une variable
booléenne qui est égale à true si l’analyse du nœud père est terminée.
Ensuite, la fonction entre dans une boucle qui lit successivement le fichier à analyser et s’arrête
quand le fichier est consommé ou l’analyse du nœud actuel est terminé. Chaque étape de cette
boucle effectue les tâches suivantes :

– La fonction lireToken() (code non spécifié) sépare les segments du flux de caractères par
rapport à leur type DOM. Ainsi cette fonction doit reconnaître toutes les balises (ouvrantes et
fermantes), mais également distinguer les noms d’attributs et leur valeurs, et ainsi de suite.
– Si le fragment retourné par la fonction lireToken() est une balise fermante, on sort de la
boucle et de la fonction parse() en mettant finNode à true.
– Sinon la fonction getType() (code non spécifié) détermine le type du fragment XML par
sa balise (un fragment sans balise est reconnu comme un nœud de type Text). Ce type permet
ensuite de créer un nœud du même type qui sera ajouté comme fils du nœud père :
père D appendNode(fils)
Si le fils peut avoir lui-même des fils, c’est-à-dire s’il est de type Container, on fait un appel
récursif de la fonction parse() avec le fils comme nouveau père. Sinon le fils est une feuille
et sa valeur est le fragment XML retourné par la fonction extractValue().

Ce parseur est très simplifié et, par exemple, ne prend pas en compte la la DTD du document et les
entités. Néanmoins il devrait permettre une meilleure compréhension du passage XML –> DOM.
L’application de cet algorithme au document précédent est illustrée dans le tableau 2.12. Pendant
l’analyse d’un document XML, les espaces (#20) et retours à la ligne (#xA) sont considérés comme
78 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Fragment lu Code exécuté


<A> b=a D createElement(A);
a D appendNode(b);
parse(fic,a,b);
#xA#x20 c=a D createTextNode(#xA#x20);
b D appendNode(c);
<B> d=a D createElement(B);
g D appendNode(d);
parse(fic,a,d);
texte simple e=a D createTextNode(texte simple);
d D appendNode(e);
</B> retour (d)
#xA#x20 f=a D createTextNode(#xA#x20);
b D appendNode(c);
<C> g=a D createElement(C);
b D appendNode(d);
parse(fic,a,g);
#xA#x20#x20 h=a D createTextNode(#xA#x20#x20);
b D appendNode(h);
<D> i=a D createElement(D);
g D appendNode(i);
parse(fic,a,i);
#x20 j=a D createTextNode(#x20);
i D appendNode(j);
</D> retour (i)
#xA#x20 k=a D createTextNode(#xA#x20);
g D appendNode(k);
</C> retour (g)
#xA l=a D createTextNode(#xA);
b D appendNode(l);
</A> retour (b)

Table 2.12: Fragmentation du document XML

des caractères. En effet, la norme du W3C préconise que tous ces « blancs » doivent être transmis sans
modification par le parseur à l’application. L’arbre DOM résultant est représenté dans la figure 2.9.

2.3.2 Traitement des espaces pendant la construction


En étudiant cet arbre DOM on peut observer qu’il existe six nœuds de type Text – identifiés par les entiers
3, 6, 8, 10, 11 et 12 – qui ne contiennent que des espaces (white-space node). Tous ces nœuds (white-space
node) sauf le nœud 10 apparaissent comme nœud « séparateurs » entre deux éléments. Le nœud 10 est le
seul fils d’un élément de type D.
Souvent les espaces entre deux éléments ne sont pas porteurs d’une information significative et servent
essentiellement à améliorer la lisibilité d’un document sérialisé par une hiérarchisation du contenu. Aussi,
la recommandation XML a décidé de distinguer entre les nœuds-espace significatifs et non-significatifs :
cette distinction est seulement possible si le document a une DTD et si on utilise un parseur XML validant
qui vérifie la conformité du document par rapport à sa DTD.
XSLT permet également de distinguer espaces significatifs et non-significatifs. Néanmoins, les créa-
teurs de XSLT ont décidé que cette séparation ne doit pas dépendre du parseur utilisé avant le traitement
2.3. DU DOCUMENT SÉRIALISÉ À L’ARBRE DOM 79

Document (1)
-

Element (2)
A

Text (3) Element (4) Text (6) Element (7) Text (12)
- B - C -
#xA#x20 #xA#x20 #A

Text (5) Text (8) Element (9) Text (11)


- - -
texte simple D
#xA#x20#x20 #xA#x20

Text (10)
-
#x20

Figure 2.9: Représentation DOM du fichier XML

XSLT, mais uniquement du contenu source du document et du programme XSLT. Ainsi, un programme
XSLT suppose par défaut que tous les espaces dans un document (plus précisément dans l’élément racine
de ce document) sont transmis au programme, à l’exception des espaces dans les valeurs d’attributs qui
subissent un traitement spécifiques, et des fins de lignes qui sont normalisées et représentées par le carac-
tère #xA.
Nous n’avons pas représenté, pour des raisons de lisibilité; tous les espaces dans les arbres DOM
jusqu’ici. Nous continuerons à le faire quand les espaces ne sont pas cruciaux pour la représentation du
contenu d’un document ou pour la compréhension du comportement d’un programme.

2.3.3 Deux fonctions de navigation


Pour conclure cette partie sur la syntaxe XML et le modèle DOM, voici deux exemples de fonctions qui
permettent d’extraire des éléments dans un document XML. Elles prennent comme argument un nœud
DOM et une chaîne de caractères qui correspond au type des éléments fils recherchés.

boolean fonction testNode(Node node, DOMString elType) {


retourner (node D nodeType == ELEMENT_NODE) et
(elType == “*” ou node D nodeName == elType);
}

NodeList fonction child(Node node, DOMString elType) {


Node fils;
DocumentFragment résultat = new DocumentFragment;
integer i=0;
tant que i < node D childNodes() D length() {
fils = node D childNodes() D item(i);
si testNode(fils, elType);
résultat = résultat D appendChild(fils)
i = i+1;
}
retourner résultat D childNodes();
80 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

La fonction child(node, elType) parcourt tous les fils du nœuds node et vérifie avec testN-
ode() que le nœud correspond à un élément de type elType (cette condition est également vérifiée si
elType est égal à « * »).
L’évaluation de cette fonction avec différents nœuds de l’arbre DOM correspondant au fichier ExXML2DOM.xml
est illustrée dans le tableau 2.13. Nous utilisons toujours nos identificateurs pour distinguer entre les dif-
férents nœuds de l’arbre.

Appel de fonction Résultat


child(1,"*") [2]
child(1,"A") [2]
child(1,"B") []
child(2,"*") [4,7]
child(2,"B") [4]
child(2,"C") [7]
child(2,"D") []

Table 2.13: Application de la fonction child() à ExXML2DOMa.xml

La fonction suivante cherche les éléments parmi les descendants de type Element du nœud donné et
utilise la fonction testNode() définie plus haut.

NodeList fonction descendant(Node node, DOMString elType) {


Node fils;
DocumentFragment résultat = new DocumentFragment;
NodeList descList;
integer i=0, j;
tant que i < node D childNodes() D length() {
fils = node D childNodes() D item(i);
si testNode(fils, elType)
résultat = résultat D appendChild(fils)
descList = descendant(fils, elType);
nombreDesc = descList D length();
j = 0;
tant que j < descList D length() {
résultat = résultat D appendChild(descListitem(j));
j = j+1;
}
i = i+1;
}
retourner résultat D childNodes();
}

Comme la fonction child(), cette fonction parcourt les fils du nœud donné et sélectionne ceux qui
satisfont le critère de sélection défini par le paramètre elType. Mais elle ne s’arrête pas là, et demande,
par un appel récursif avec le même critère de sélection, les descendants de tous ses fils. L’évaluation de
cette fonction est illustrée dans le tableau 2.14.
L’appel descendant(1,"*"), ou 1 est l’identificateur de la racine du document, retourne tous les
éléments du document XML.
2.4. LE LANGAGE XPATH 81

Appel de fonction Résultat


descendant(1,"*") [2,4,7,9]
descendant(1,"A") [2]
descendant(1,"B") [4]
descendant(1,"C") [7]
descendant(1,"D") [9]
descendant(2,"*") [4,7,9]
descendant(2,"B") [4]
descendant(2,"C") [7]
descendant(2,"D") []

Table 2.14: Application de la fonction descendant() à ExXML2DOMa.xml

2.4 Le langage XPath


Le modèle DOM définit les opérations applicables à un document XML, soit pour en modifier la struc-
ture (exemple de la fonction parse()), soit pour « naviguer » au sein de ce document (exemples des
fonctions child() et descendant()).
Le terme de « navigation » que nous avons utilisé assez intuitivement jusqu’à présent, peut être défini
plus précisément comme le référencement, à partir d’un nœud contexte, de un ou plusieurs autres nœuds
de l’arbre DOM. Le langage XSLT est fortement fondé sur ce type de référencement.
Bien que les opérations applicables aux objets constituant un arbre DOM fournissent un moyen précis
et puissant d’effectuer un tel référencement, elles impliquent un recours systématique à la programmation
qui s’avèrerait assez lourd. Le langage XPath fournit des expressions beaucoup plus simples et concises
pour désigner des nœuds dans un arbre DOM à l’aide de chemins. Ce référencement s’effectue en décrivant
les parcours – ou chemins – qui partent du nœud contexte et mènent aux nœuds référencés.
Voici quatre exemples d’utilisation de XPath comme langage de référencement dans XSLT :

1. Sélection de nœuds auxquels on souhaite appliquer une règle : dans ce cas l’expression XPath ap-
paraît dans l’attribut select d’une instruction XSLT de type xsl:apply-templates. Par
exemple l’instruction XSLT suivante :

<xsl:apply-templates select="CINEMA/SALLE"/>

va sélectionner tous les nœuds de type SALLE, fils d’un nœud de type CINEMA, lui-même fils du
nœud contexte.

2. Sélection de règles qui doivent être appliquées à des nœuds : l’expression XPath apparaît dans
l’attribut match. Par exemple la règle suivante :

<xsl:template match="FILM/TITRE">
...
</xsl:template>

pourra uniquement être appliqué aux éléments de type TITRE, qui sont des fils d’autres éléments
de type FILM. Seul un sous-ensemble des expressions XPath (les « patterns ») peut être utilisé dans
l’attribut match (voir page 119).

3. Extraction de valeurs : par exemple l’expression :

<xsl:value-of select="SALLE/@NO">

extrait la valeur de l’attribut NO d’un élément de type SALLE fils du nœud contexte.
82 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

4. Prédicats de test : voici un exemple rencontré dans le premier chapitre :

<xsl:if test=" ($titre = ’’ or TITRE = $titre)


and ($seance = ’’ or HEURE &gt;= $seance)
and ($ville = ’’ or VILLE = $ville)">

2.4.1 Représentation XPath d’un document XML


XPath s’appuie sur une modélisation DOM restreinte : seuls certains types d’éléments sont considérés, et il
n’est pas possible de modifier le document source ou de créer de nouveaux documents. Ces limitations sont
compensées – et justifiées – par la grande simplification qui en résulte. Le sous-ensemble des interfaces
DOM pris en compte par XPath est mis en évidence dans la figure 2.10 par un fond gris.

Node

Attribute TreeNode

Leaf Container

Character Processing Entity Document


Notation Entity Document Element
Data Instruction Reference Type

Comment Text

CData
Section

Figure 2.10: Sous-ensemble des interfaces DOM pris en compte par XPath

Les arbres DOM restreints aux nœuds connus par XPath seront désignés quand besoin est par le terme
« arbres XPath » dans ce qui suit.
On ne peut donc traiter avec XPath la DTD d’un document XML (un nœud de type DocumentType)
ou des références vers des entités externes (nœuds de type Entity et EntityReference). Concrètement, cela
signifie qu’une application faisant appel à des expressions XPath – par exemple un processeur XSLT – doit
résoudre au préalable les références aux entités et ne pas prendre en compte la DTD, hypothèses que nous
avions déjà envisagées précédemment.
En ce qui concerne les sections littérales (de type CDataSection), les simplifications suivantes sont
effectuées :

1. Le contenu des nœuds CDataSection est transformé en texte ; tout ce passe donc comme si ce type de
nœud était en fait de type Text, avec un contenu transmis tel quel par le parseur. Cette transformation
des sections CDATA en nœuds de type Text est naturelle car l’interface CDataSection est un sous-
type de l’interface Text.
2.4. LE LANGAGE XPATH 83

2. Puis, si plusieurs nœuds textes sont frères et adjacents dans l’arbre DOM, ils sont réunis dans l’arbre
XPath.

La seconde opération vise à satisfaire une règle de base de XML : la séparation d’un texte d’un seul
tenant en deux parties pour constituer deux nœuds distincts n’est pas autorisée. Si on n’opérait pas cette
opération de fusion (dite normalise() dans DOM), l’arbre obtenu après la première simplification ci-dessus
(transformation de CDataSection en Text) serait incorrect.
Prenons un exemple pour illustrer cette simplification. La figure 2.11 montre un arbre DOM avec deux
nœuds frères adjacents. Le nœud de type CDataSection contient des caractères réservés qui n’auraient pas
pu passer tels quels la phase de parsing s’ils n’étaient pas inclus dans une section littérale.

Document
-

Element
EXEMPLE

CDATASection
Text -
- Ceci est une section littérale
Du texte G H
avec des ’&’, des ’ ’ et des ’ ’

Figure 2.11: Un arbre DOM avec deux nœuds de type Text et CDataSection

XPath travaille sur une version simplifiée de cet arbre dans laquelle les deux nœuds ont été fusionnés
(figure 2.12). On constate donc qu’il est possible de trouver des caractères réservés (voire des balises ou
des documents XML entiers) dans les nœuds Text des arbres XPath.

Document
-

Element
EXEMPLE

Text
-
G H
Du texteCeci est une section littérale avec des ’&’, des ’ ’ et des ’ ’

Figure 2.12: L’arbre traité par XPath, après regroupement

Un deuxième point déjà soulevé déjà plusieurs fois dans ce livre concerne le traitement des espaces dans
un document XML. Nous avons signalé que la recommandation XML préconise la propagation de tous les
espaces blancs dans un document XML à l’application qui traite le document. Voici donc un document
XML simple avec des espaces :
Exemple 26 ExBlanc.xml : Fichier XML avec des espaces
84 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

<?xml version="1.0"
encoding="ISO-8859-1"?>
<?xml-stylesheet href="ex.xsl"
type="text/xsl"?>

<!-- commentaire -->

<!DOCTYPE A SYSTEM "ex.dtd" >


<A>
<B at1=’ val1 ’
at2=’ valeurs avec blancs ’
/>
<C> </C>
<D> texte </D>
</A>

En comptant bien, on peut vérifier que ce document contient une trentaine d’espaces qui peuvent être
caractérisés par rapport à leur position dans le document. Ainsi, on trouve des espaces :
5 avant la balise ouvrante de l’élément racine ;
5 à l’intérieur d’une balise ;
5 à l’intérieur d’un élément ;
5 à l’intérieur de la valeur d’un attribut ;
5 entre deux balises ;
5 entre deux attributs.
Une grande partie de ces espaces ne joue pas un rôle significatif pour l’interprétation du contenu d’un
document XML par XPath. Ainsi, il est évident que la plupart des espaces qui apparaissent avant l’élément
racine du document ou dans des nœuds de types DOM qui ne sont pas représentés dans XPath – comme
la déclaration XML ou la DTD – n’ont pas de signification et peuvent être ignorés. De même, certains
espaces servent uniquement comme séparateurs entre des composants syntaxiques XML. C’est vrai par
exemple pour les espaces séparant les attributs d’un élément qui peuvent être « simplifiés » ou remplacés
par un espace simple.
En prenant en compte toutes ces remarques, le document suivant est équivalent au document précédent
du point de vue de XPath :

<?xml-stylesheet href="ex.xsl" type="text/xsl"?><!-- commentaire --><A>


<B at1=’ val1 ’ at2=’ valeurs avec blancs ’/>
<C> </C>
<D> texte </D>
</A>

Après cette première élimination des espaces non-significatifs, XPath considère que le parseur XML a
effectué les transformations suivantes avant de passer les données au processeur XSLT :

1. toutes les fins de lignes sont représentées par le caractère #xA;


2. les valeurs d’attributs sont normalisées et ne contiennent que des caractères blancs (#x20). Les
autres caractères (#xA et #xD) ne sont pas éliminés mais remplacés par le #x20. Dans certains cas
(quand l’attribut n’est pas de type CDATA – voir section 4.1) les caractères au début et à la fin de la
valeur sont effacés. Si, par exemple, l’attribut at1 est de type NMTOKEN (voir page 154), sa valeur
devient « val1 ».
2.4. LE LANGAGE XPATH 85

Document
-

Instruction Comment
xml-stylesheet - Element
A
href="ex.xsl" type="text/xsl" un commentaire

Text Element Text Text Element Text Element Text


- B - - C - D -
#xA#20 #xA#20 #xA#20 #xA#20 #xA#20

Attr Attr Text Text


at1 at1 - -
#20val1#20 #20valeurs#20avec#20blancs#20 #20 #20texte#20

Figure 2.13: Arbre XPath du document ExBlanc.xml

L’arbre XPath du document résultant est donné dans la figure 2.13. Parmi les espaces qui restent, on
peut distinguer ceux qui se trouvent :
1. entre des éléments ou entre d’autres types de nœuds DOM ;
2. comme unique fils d’un élément (élément de type D), dans un nœud de type Text (" texte ").
Ce sont surtout les deux premiers cas qui sont intéressants, car il représentent des situations ambiguës
concernant l’interprétation des espaces :
1. Dans le cas où un espace apparaît comme nœud de type Text entre deux éléments, on peut souvent
considérer qu’il sert uniquement à augmenter la lisibilité du document.
2. Dans le deuxième cas, la question est de savoir si l’élément doit être considéré comme vide ou pas.
XPath ne permet pas un traitement spécifique de ces cas, mais XSLT fournit les instructions nécessaires
pour rendre ces situations non-ambigues. Une de ces instructions est xsl:xsl:strip-space qui
permet de désigner une liste de types d’éléments dont les fils constitués uniquement d’espace peuvent être
supprimés (strip). Ainsi, par exemple, la commande suivante supprime ce type de nœud pour tous les
éléments du document :
<xsl:strip-space elements="*"/>
En ajoutant cette instruction au début d’une feuille de style, le document précédent devient équivalent
au document suivant, qui ne contient plus de nœuds d’espace (normalement le document contient une seule
ligne que nous avons coupé en deux à cause de la largeur limitée des pages de ce livre) :

<?xml-stylesheet href="ex.xsl" type="text/xsl"?><!-- commentaire -->


<A><B at1=’val1’ at2=’ valeurs avec blancs ’/><C/><D> texte </D></A>

L’arbre XPath de ce document est donné dans la figure 2.14. On remarque que l’élément de type C est
maintenant un élément vide et les espaces dans le texte de l’élément D n’ont pas été supprimés.
86 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Document
-

Instruction Comment
xml-stylesheet - Element
A
href="ex.xsl" type="text/xsl" un commentaire

Element Comment Element Element


B - C D
autre commentaire

Attr Attr Text


at1 at1 -
val1 #20valeurs#20avec#20blancs#20 #20texte#20

Figure 2.14: Arbre XPath après suppression des nœuds constitués d’espaces.

2.4.2 Expressions XPath


Le langage XPath désigne un ou plusieurs nœuds en exprimant des chemins dans un arbre conforme à la
structure décrite précédemment. L’évaluation d’un chemin donne un résultat qui peut être soit une valeur
numérique ou alphanumérique, soit un sous-ensemble des nœuds de l’arbre. Enfin cette évaluation tient
compte d’un contexte qui détermine le résultat.

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.15: Exemple d’un arbre XPath

Nous allons développer chacun de ces aspects ci-dessous, en prenant pour exemple principal l’arbre
de la figure 2.15. Comme on peut le constater cet arbre présente à peu près tous les types de nœuds
manipulables par XPath, avec plusieurs configurations. Rappelons que dans nos représentations chaque
nœud est caractérisé par les trois composants suivants :

1. le type DOM du nœud, toujours présent, en gras ;


2. le nom pour les nœuds de type Element (ou la cible pour le type ProcessingInstruction) ; pour tous
les autres types de nœud il n’y a pas de nom ;
2.4. LE LANGAGE XPATH 87

3. la valeur, valable pour tous les types de nœuds, y compris les attributs, à l’exception du type Ele-
ment.

Cet arbre est obtenu à partir du document sérialisé suivant, que vous pouvez récupérer sur notre site
pour tester les expressions XPath (les outils permettant d’effectuer ces tests sont présentés dans l’annexe A).

Exemple 27 ExArbreXPath.xml : Le fichier XML pour les exemples XPath

<?xml version="1.0" encoding="ISO-8859-1"?>

<?java ins1?>
<A>
<B att1=’a1’>
<D>Texte1</D>
<D>Texte2</D>
</B>
<B att1=’a2’>
<D>Texte2</D>
</B>
<C att2=’a3’ att3=’15’/>
</A>
<!-- CommFin -->

Chemins XPath
Un chemin peut être absolu, et prendre son origine à la racine du document, notée « / ». Par exemple
l’expression :

/A/B/@att1

correspond à un chemin qui part de la racine du document (« / »), puis passe par l’élément racine si le type
de cet élément est A, parcourt tous les éléments de type B fils de cet élément racine, et enfin désigne les
attributs att1 de ces éléments B. La figure 2.16 montre les deux nœuds, de type Attr, désignés par ces
chemins.

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.16: Chemin vers les attributs des nœuds B


88 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Un chemin peut également être relatif et prendre pour origine un nœud du document, dit nœud contexte.
En pratique l’utilisation de chemins relatifs est la plus répandue avec XSLT puisque le principe de base
consiste à déclencher des règles à partir de nœuds considérés comme les nœuds contextes des chemins
XPath. L’expression (noter l’absence du « / » initial) :
A/B/@att1
désigne un chemin qui partant d’un nœud contexte de type quelconque, passe successivement par les nœuds
de type A, B et aboutit aux attributs de nom att1. Ce type d’expression est en principe plus puissant
puisqu’il s’applique à tous les types de documents dans lesquels on retrouve un motif de ce type, quel que
soit par ailleurs la position relative de ce motif par rapport à la racine du document. On peut considérer
un chemin absolu comme une forme particulière de chemin relatif dans laquelle le nœud contexte est
systématiquement la racine du document.

Syntaxe XPath
Un chemin est constitué d’une suite d’étapes, séparées par des « / ». La forme générale est donc :
[/]étape I /étape J /.../étape K
le « / » initial étant optionnel, et distinguant les chemins relatifs des chemins absolus, comme nous l’avons
expliqué précédemment.
Chaque étape peut elle-même se subdiviser en trois composants :
1. l’axe qui définit le sens de parcours des nœuds à partir du nœud contexte ;
2. le filtre qui indique le type des nœuds qui seront retenus dans l’évaluation du chemin ; la notion de
type recouvre ici les types DOM (commentaire, texte, instruction de traitement,...) ainsi que, pour
les éléments et les attributs, le nom de la balise ou de l’attribut ;
3. le (ou les) prédicat(s) qui exprime(nt) des propriétés que doivent satisfaire les nœuds retenus à l’issue
du filtrage pour être finalement inclus dans le résultat.
La forme générale d’une étape est donc :
axe::filtre[prédicat1][prédicat2] :):;:
Signalons dès maintenant qu’il est possible, quand on utilise XPath avec XSLT, d’effectuer une union
de chemins avec l’opérateur « | ». Par exemple l’expression « //A | B/@att1 » désigne l’union des
ensembles désignés par les expressions « //A » et « B/@att1 ».
Les expressions de chemins que nous avons utilisées jusqu’ici correspondaient aux formes les plus
simples du langage XPath. En particulier, comme nous l’avons souligné dans le chapitre 1, nous n’avons
jamais jusqu’ici eu recours aux prédicats qui sont optionnels et nous avons toujours choisi d’utiliser comme
axes de parcours les fils ou les attributs du nœuds contexte. Le premier axe, noté child dans XPath, est
également considéré comme celui par défaut. Le deuxième axe, noté attribute, est distingué par le
symbole « @ » avant le nom de l’attribut. On peut noter que les attributs sont traités par un axe spécifique.

Évaluation d’une expression XPath


L’évaluation d’une étape peut être soit une valeur, soit un ensemble de nœuds (node-set). Nous laissons
de côté, jusqu’à la page 103, le cas des valeurs pour nous concentrer sur le cas où l’évaluation revient à
désigner un ensemble de nœuds du document source.
Il est bon de noter qu’un nœud n’est jamais extrait du document et placé hors de son contexte (à savoir
sa position dans l’arbre). Un node-set doit donc plutôt être considéré comme un ensemble de références
vers des nœuds de l’arbre DOM. Notons également qu’un même nœud ne peut être référencé qu’une seule
fois dans un même ensemble.
Quand une expression est constituée de plusieurs étapes, on se trouve en général dans la situation où
l’évaluation de chaque étape donne un ensemble de nœuds. L’évaluation de l’expression complète est alors
basée sur les principes suivants :
2.4. LE LANGAGE XPATH 89

5 à partir du nœud contexte, on évalue l’étape 1 ; on obtient un ensemble de nœuds ;


5 on prend alors, un par un, les nœuds de cet ensemble, et on les considère chacun à leur tour comme
nœud contexte pour l’évaluation de l’étape 2 ;
5 la règle précédente se généralise comme suit : à chaque étape, on prend successivement comme nœud
contexte chacun des nœuds faisant partie du résultat de l’étape précédente.
Reprenons un des exemples donnés précédemment pour clarifier cette évaluation :
/A/B/@att1
L’expression ci-dessus est un chemin absolu, constitué de trois étapes, dont le nœud contexte initial est
donc la racine du document (figure 2.17). L’axe de recherche n’est jamais indiqué, et on suit donc celui par
défaut, child, consistant à parcourir les fils du nœud contexte.

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.17: Le nœud contexte initial

À partir de la racine, on évalue donc l’étape 1. Le filtre est A : on recherche un nœud fils, dont le type
DOM est Element, et le nom de balise A. Si on le trouve, il ne peut y en avoir qu’un seul car c’est l’élément
racine du document : le résultat de l’étape 1 est donc un ensemble réduit à un seul nœud (figure 2.18).

Maintenant on prend ce nœud comme contexte, et on évalue l’étape 2 dont le filtre est B. Le résultat
de cette évaluation va être l’ensemble des nœuds dont le type DOM est Element, et le nom de balise B
(figure 2.19).

Enfin, on va prendre chaque nœud de type B comme nœud contexte, et on cherchera pour chacun un
attribut att1 : le résultat final est un ensemble d’attributs, autrement dit de nœuds dont le type DOM est
Attr. On obtient le résultat de la figure 2.16, page 87.
L’évaluation du chemin /A/B/@att1 peut également être illustré par un programme qui utilise la
fonction child(Node node, DOMString elType). Cette fonction prenait comme paramètre un
nœud – le nœud contexte – et un nom d’élément. Le résultat était l’ensemble des fils de type elType du
nœud contexte. Voici un fragment de programme qui évalue le chemin /A/B/@att1 (on suppose que
doc correspond au nœud racine du document) :
90 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Document
-

Instruction Element Comment


Java -
A CommFin
ins1

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.18: Première étape de l’évaluation du chemin /A/B/@att1

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.19: Seconde étape de l’évaluation du chemin /A/B/@att1


2.4. LE LANGAGE XPATH 91

pour tous les fils a dans child(doc, "A")


pour tous les fils b dans child(a, "B")
pour tous les fils at dans attributes(b, "att1")
ajouter at à la liste du résultat
Ce programme utilise également une fonction attributes() dont la définition est très similaire à
la fonction child().

Contexte d’évaluation
Chaque étape d’une expression XPath est évaluée en fonction d’un ensemble d’informations qui constituent
le contexte de l’évaluation. Il est très important d’être conscient que le contexte change à chaque étape,
d’une part pour comprendre le résultat d’une évaluation XPath, d’autre part pour construire correctement
des expressions.
Ce contexte comprend en premier lieu le nœud que nous avons appelé nœud contexte jusqu’à présent,
à partir duquel sont construits les chemins des étapes suivantes. Mais le contexte d’évaluation d’une étape
comprend également l’ensemble de nœuds obtenu par l’évaluation de l’étape précédente, constituant le
contexte commun d’évaluation pour chaque nœud pris individuellement.
Reprenons l’exemple précédent pour clarifier cette notion de contexte. L’expression XPath est
/A/B/@att1
avec trois étapes. À l’issue de la seconde étape, correspondant au filtre B, on obtient un ensemble com-
portant deux nœuds, représenté dans la figure 2.19. Cet ensemble va constituer le contexte commun à
l’évaluation de l’étape suivante, @att1.
Les nœuds de cet ensemble sont alors considérés chacun leur tour en tant que nœud contexte. L’évaluation
de l’étape @att1 s’effectue autant de fois qu’il y a de nœuds contextes, en tenant compte du contexte com-
mun. En pratique, on pourra connaître la position d’un nœud dans son contexte (fonction position()) ou
savoir si un nœud est le dernier de son contexte (fonction last()). Ici il y a deux positions, 1 et 2, carac-
térisant les deux occurrences de nœuds de type B.
Le contexte d’évaluation d’une étape dans une expression XPath comprend également des variables,
des fonctions et des espaces nominaux, aspects complémentaires sur lesquels nous reviendrons ultérieure-
ment.

2.4.3 Les axes


Nous présentons maintenant de manière exhaustive les options des trois composants d’une étape dans un
chemin XPath (axes, filtres et prédicats), en commençant par les axes. Rappelons que tout axe s’interprète
par rapport à un nœud contexte. Un axe XPath recouvre alors les deux notions suivantes :
1. un sous-ensemble des nœuds de l’arbre relatif au nœud contexte ;
2. l’ordre de parcours de ces nœuds à partir du nœud contexte.
Le tableau 2.15 donne la liste des axes XPath. Tous ces axes désignent des nœuds de l’arbre DOM, à
l’exception de l’axe attribute qui s’applique à l’arbre des attributs et namespace qui s’applique aux
espaces de nom, ce dernier aspect étant laissé de côté jusqu’au chapitre 6.
Il est toujours possible de spécifier une étape XPath en donnant pour axe un des noms de la première
colonne du tableau 2.15. Certaines facilités d’écriture sont cependant permises :
5 quand l’axe n’est pas indiqué dans une étape, c’est child qui est pris par défaut ;
5 certains axes peuvent être notés de manière abrégée, comme par exemple « @ » qui remplace at-
tribute.
Nous décrivons maintenant chaque axe, en prenant comme exemple de référence l’arbre de la fig-
ure 2.20, avec comme nœud contexte le second nœud de type B, comme illustré sur la figure.
92 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Axe Description
child Les fils du nœud contexte
attribute Les attributs du nœud contexte
parent Le père du nœud contexte
descendant Tous les descendants du nœud contexte
ancestor Tous les ancêtres du nœud contexte
self Le nœud contexte lui-même
preceding-sibling Tous les frères gauches du nœud contexte
following-sibling Tous les frères droits du nœud contexte
preceding Les nœuds précédant le nœud contexte dans l’ordre de parcours du doc-
ument
following Les nœuds suivant le nœud contexte dans l’ordre de parcours du docu-
ment
descendant-or-self Les descendants du nœud contexte, et le nœud contexte lui-même
ancestor-or-self Les ancêtres du nœud contexte, et le nœud contexte lui-même
namespace S’applique aux espace de noms : voir chapitre 6

Table 2.15: Les axes XPath

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.20: Exemple de référence pour les axes XPath

L’axe child
L’axe child désigne les fils du nœud contexte. Cet axe ne s’applique pas aux attributs, mais prend en
compte en revanche tous les autres types de nœuds DOM. La figure 2.21 montre l’unique nœud désigné
par cet axe à partir de notre nœud contexte.

L’axe peut être utilisé explicitement :


/child::A/child::B/child::D
Mais le plus souvent on omettra l’indication child pour se reposer sur l’interprétation par défaut.
L’expression ci-dessous est donc équivalente à la précédente :
/A/B/D
Notons que l’évaluation de l’expression ci-dessus, appliquée à notre arbre-exemple, donne tous les
nœuds de type D.
2.4. LE LANGAGE XPATH 93

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element
B Nœud contexte C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.21: L’axe child

L’axe attribute
Cet axe constitue une exception car il est le seul à s’appliquer à l’arbre des attributs. Cet arbre est lui-même
très particulier puisqu’il a toujours pour racine un nœud de type Element, et un seul niveau constitué de
feuilles, non ordonnées mais identifiées par leur nom, les attributs.

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element
B Nœud contexte C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.22: Résultat de attribute::att1

En conséquence, l’axe sera toujours utilisé dans la dernière étape d’une expression XPath, et l’attribut
sera désigné par son nom. L’étape permettant de sélectionner l’attribut de nom att1 à partir de notre nœud
contexte (figure 2.22) est donc :

attribute::att1

On utilise le plus souvent l’abréviation @nom pour remplacer attribute::nom (remarquez la dis-
parition des ::). On notera donc l’étape précédente de manière équivalente :

@att1
94 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

L’ensemble des attributs de nom att1 associés à un élément de type B lui-même fils d’un élément-
racine de type A est donc désigné par l’expression :
/A/B/@att1

L’axe parent
Cet axe désigne le nœud père du nœud contexte (figure 2.23). L’étape suivante permet donc de « remonter »
d’un niveau dans l’arbre à partir de notre nœud de type B :
parent::A

Document
-

Instruction Element Comment


Java -
A CommFin
ins1

Element Element
B Nœud contexte C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.23: Résultat de parent::A

L’abréviation pour cet axe est « .. », conformément à une convention largement utilisée dans des sys-
tèmes de fichiers hiérarchique sous Unix ou DOS. En fait cette abréviation n’est pas strictement équivalente
à parent::A qui utilise le filtre A alors que « .. » désigne le nœud père quel que soit son type. L’équivalent
de « .. » en notation développée est :
parent::node()
où node() est un filtre qui sélectionne tous les types de nœuds de l’arbre DOM (à l’exception des at-
tributs).
On peut composer cet axe pour remonter d’un nombre donné de niveaux dans l’arbre. Par exemple
l’expression suivante :
../..
désigne, à partir de notre nœud contexte de référence, la racine du document. On pourrait à partir de là
redescendre sur l’un des trois fils de la racine, mais on rencontre alors un problème de nommage puisque
seul l’un de ces fils est de type Element avec un nom. Nous verrons page 98 comment utiliser des modes
de référencement alternatifs au nommage des nœuds. On peut utiliser node() pour éviter ce problème de
nommage :
../../node()
Cette expression désigne donc les trois fils de la racine du document, qui sont de trois types différents.
Notez bien que cette expression est une abréviation de
parent::node()/parent::node()/child::node()
où le dernier axe child indique bien que les attributs – s’il y en avait – ne sont pas concernés.
2.4. LE LANGAGE XPATH 95

L’axe descendant
Cet axe permet de désigner tous les nœuds de l’arbre DOM principal (à l’exception donc des attributs et
des espaces de nom) qui sont descendants du nœud contexte. Voici l’expression donnant les descendants
de notre nœud contexte, tous types confondus (figure 2.24) :
descendant::node()

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element
B Nœud contexte C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.24: Résultat de descendant::node()

Le filtre node() est ici important pour désigner à la fois un nœud de type Element et un nœud de type
Text. Le premier, seul, serait obtenu par :
descendant::D
et le second par
descendant::text()

L’axe ancestor
L’axe ancestor est réciproque de descendant : il désigne tous les ancêtres du nœud contexte, et ce
quel que soit leur type (toujours à l’exception du type Attr). La figure 2.25 montre, sur notre exemple de
référence, les nœuds désignés par
ancestor::node()

L’axe self
Cet axe désigne le nœud contexte lui-même. Le résultat dépend ensuite du filtre qui est appliqué. Sur notre
exemple, l’expression suivante :

self::B

revient bien à sélectionner le nœud de type B qui constitue notre nœud contexte. En revanche
self::A
96 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Document
-

Instruction Element Comment


Java -
A CommFin
ins1

Element Element
B Nœud contexte C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.25: Résultat ancestor::node()

renverrait, toujours sur notre exemple, un ensemble vide puisque le nœud contexte n’est pas de type A.
Afin de pouvoir désigner le nœud contexte sans avoir à s’embarasser de donner son type, on utilise souvent
l’expression
self::node()
qui utilise le filtre node(), valide pour tout type de nœud (sauf les attributs !). Il existe une notation abrégée,
« . », pour self::node(), très fréquemment utilisée. L’expression suivante utilise donc des notations
abrégée pour désigner l’attribut att1 du nœud contexte :
./@att1
Sans utiliser la notation abrégée, cette expression s’écrirait :
self::node()/attribute::att1

Les axes preceding-sibling et following-sibling

Ces deux axes désignent respectivement les frères à gauche et à droite du nœud contexte. La figure 2.26
montre l’axe preceding-sibling appliqué à notre exemple, avec un filtre node().
preceding-sibling::node()
On obtient évidemment en l’occurrence le même résultat avec l’expression suivante, dont le filtre limite
la sélection des nœuds aux éléments de type B :
preceding-sibling::B

Les axes preceding et following


Ces deux axes désignent respectivement l’ensemble des nœuds qui précèdent ou qui suivent le nœud con-
texte dans l’ordre de parcours du document. Rappelons que cet ordre correspond, pour la représentation
arborescente, à un parcours gauche en profondeur d’abord, et plus simplement, pour la représentation séri-
alisée, à un parcours séquentiel des nœuds.

La figure 2.27 montre sur notre exemple les nœuds sélectionnés par l’expression :
following::node()
2.4. LE LANGAGE XPATH 97

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Nœud contexte Element


B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.26: Résultat de preceding-sibling::node()

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Nœud contexte Element


B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.27: Résultat de following::node()


98 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Les axes descendant-or-self et ancestor-or-self


Comme l’indiquent leurs noms, ces axes désignent respectivement l’union des axes descendant et
self, et l’union des axes ancestor et self, Par exemple l’expression suivante :

descendant-or-self::node()

désigne les mêmes nœuds que ceux déjà montrés dans la figure 2.24, avec le nœud contexte en plus.

2.4.4 Les filtres


Un filtre permet d’éliminer un certain nombre de nœuds parmi ceux sélectionnés par un axe. Il existe
essentiellement deux façons de filtrer les nœuds :

1. par leur nom ;

2. par leur type DOM.

Filtrage par nom


Le filtrage par nom ne s’applique qu’aux nœuds pour lesquels cette notion de nom est pertinente, à savoir
ceux de type Element, de type ProcessingInstruction et de type Attr. Il s’effectue simplement en indi-
quant le nom, ou une partie du nom.
La plus grande part des exemples d’expression XPath que nous avons vus jusqu’à présent comprenaient
un filtrage par nom. Par exemple l’expression suivante :

/A/B/D

désigne, en partant de la racine du document, l’élément de nom A, puis les éléments de nom B fils de A,
et enfin les éléments de nom D fils de B. Les chemins obtenus sur notre exemple sont montrés dans la
figure 2.28.

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.28: Filtre avec noms d’éléments (/A/B/D)


2.4. LE LANGAGE XPATH 99

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.29: Filtre avec noms d’attributs (/descendant::node()/@att2)

Un filtrage avec nom d’attributs ne peut intervenir que dans la dernière étape d’une expression XPath
(puisqu’un attribut est toujours un nœud feuille). Voici par exemple une expression qui désigne tous les
attributs nommés att2, quelle que soit par ailleurs leur position dans l’arbre. On combine une étape
/descendant::node() qui, à partir de la racine, va sélectionner tous les nœuds à l’exception des
attributs, puis pour chacun de ces nœuds on regarde s’il existe un attribut att2.

/descendant::node()/@att2

Le résultat est montré dans la figure 2.29.


Il est possible de désigner tous les nœuds de type Attr (pour l’axe attribute) ou de type Element
(pour tous les autres axes) avec le caractère « * ». L’expression suivante va donc sélectionner tous les
attributs de l’arbre, quel que soit leur nom :

/descendant::node()/@*

De même l’expression suivante sélectionne tous les éléments fils de l’élément racine F AE , quel que
soit leur nom :
/A/*
Le résultat est donné dans la figure 2.30. Notez que seuls les éléments de type Element sont concernés,
et pas ceux de type Comment, Text (qui n’ont pas de nom) ou ProcessingInstruction (qui peuvent être
filtré différemment).

Filtre sur le type de nœud


Les filtres par nommage ne concernent que les attributs ou les nœuds de type Element. Des filtres
spécifiques existent donc pour les autres types, à savoir Text, Comment et ProcessingInstruction. Le
tableau 2.16 montre les filtres sur les types de nœuds.
Voici quelques exemples pour illustrer l’utilisation de ces filtres. L’expression
/processing-instruction()
désigne les nœuds fils de la racine du document de type ProcessingInstruction. En prenant notre exemple
on obtient le premier fils de la racine du document. De même, pour désigner le troisième fils, de type
Comment, on utiliserait :
100 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.30: Résultat de /A/*

Filtre Description
text() Désigne les nœuds de type Text
comment() Désigne les nœuds de type Comment
processing-instruction() Désigne les nœuds de type ProcessingInstruction
node() Désigne tous les types de nœud

Table 2.16: Les filtres sur les types de nœud

/comment()
L’expression ci-dessus désigne tous les commentaires fils de la racine, sans qu’il soit possible d’être
plus précis puisqu’un commentaire n’a pas de caractère distinctif. En revanche on peut faire référence de
manière plus précise à une instruction de traitement en utilisant son nom :
/processing-instruction(’java’)
Enfin le filtre text() désigne les nœuds de type Text. Voici l’exemple d’une expression désignant
tous les nœuds de texte situés sous un élément F B E

/A/B//text()

Notez l’utilisation de la notation abrégée « // ». En notation non abrégée on aurait :

/A/B/descendant-or-self::node()/text()

Le résultat de l’expression appliquée à notre exemple de référence est donné dans la figure 2.31.

2.4.5 Prédicats
La troisième partie d’une étape est un prédicat, autrement dit une expression booléenne constituée d’un ou
plusieurs tests, composés avec les connecteurs logiques habituels and et or (la négation est fournie sous
la forme d’une fonction not()).
Un test est toute expression donnant un résultat booléen (true ou false). En fait à peu près n’importe
quelle expression peut être convertie en un booléen avec XPath, ce qui donne beaucoup de liberté, au prix
parfois d’une certaine obscurité.
2.4. LE LANGAGE XPATH 101

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.31: Résultat de /A/B//text()

Un ensemble de nœuds par exemple est interprété comme true s’il n’est pas vide, et comme false
sinon. L’expression

/A/B[@att1]

a donc la signification suivante : le prédicat est l’ensemble des attributs de nom att1 des éléments de type
B. S’il n’y a pas d’attribut att1 l’ensemble est vide, donc il a pour valeur booléenne false. Pour dire
les choses simplement, cette expression sélectionne les éléments de type B qui ont un attribut att1.
Les tests peuvent également consister à exprimer des conditions sur les valeurs de certains nœuds ou
variables, et à appeler des fonctions parmi celles proposées par XPath.

Prédicats simples
Les fonctions les plus utilisées sont probablement position() qui donne la position du nœud au sein de
contexte, et last() qui donne la position du dernier nœud dans le contexte (autrement dit le nombre de
nœuds dans le contexte puisque les positions sont numérotées à partir de 1). Voici un premier exemple
d’une expression XPath avec prédicat.

/A/B/descendant::text()[position()=1]

Le résultat est celui de la figure 2.32 : on obtient les premiers nœuds de type Text descendant de
chacun des deux nœuds désignés par /A/B. Il est très important de noter que le prédicat d’une étape prend
en compte le contexte constitué de l’ensemble de nœuds obtenu par évaluation de l’axe et du filtre de cette
même étape. Ici l’étape est évaluée deux fois, pour chacun des nœuds de type B, et à chaque fois le prédicat
est appliqué aux nœuds obtenus par évaluation de descendant::text().

Revenons sur les fonctions position() et last(). Elle s’appuient sur une numérotation des nœuds dans
un ensemble, elle-même fonction de deux critères :

1. l’ordre des nœuds du document XML ;


2. l’axe utilisé dans l’étape XPath : la plupart des axes respectent l’ordre du document (forward-axes),
mais d’autres, dits reverse-axes, adoptent l’ordre inverse. La règle générale est que tous les axes qui
peuvent désigner des nœuds situés avant le nœud contexte (ancestor, ancestor-or-self,
preceding-sibling, et preceding) sont des reverse-axes.
102 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.32: Résultat de /A/B/descendant::text()[position()=1]

Il est possible de tester les valeurs de certains nœuds en faisant référence à ces nœuds par des expres-
sions XPath. Voici un premier exemple simple : une expression qui sélectionne tous les éléments de nom
B ayant un attribut att1 dont la valeur est a1.

/A/B[@att1=’a1’]

Les prédicats peuvent ainsi référencer des nœuds très éloignés du nœud contexte. Voici par exemple
une expression qui sélectionne tous les nœuds de nom B si et seulement si il existe un nœud fils de l’élément
racine donc le type est C avec un attribut att3 ayant la valeur 15.

/A/B[/A/C/@att3=15]

On peut s’attendre à ce que cette expression soit très coûteuse à évaluer puisqu’il faudra, pour chaque
nœud B, tester le prédicat en suivant le chemin dans l’arbre DOM (à moins d’utiliser un processeur XPath
assez malin pour s’apercevoir que le résultat du prédicat est indépendant du contexte et peut donc s’évaluer
une seule fois).
On peut effectuer des compositions booléennes des conditions élémentaires avec les connecteurs and
et or (le not est une fonction not() dans XPath). Voici une expression qui prend le dernier élément B fils
de l’élément racine A, et ce seulement si ce dernier élément a un attribut att1 dont la valeur est a1.

/A/B[@att1=’a1’ and position()=last()]

Composition de prédicats
L’utilisation d’une succession de prédicats marqués par les crochets [ ] dénote une composition. La dif-
férence essentielle d’une telle composition, par rapport à l’utilisation de connecteurs logiques and et
or, est que l’ensemble de nœuds issus de l’évaluation du premier prédicat est pris comme contexte pour
l’évaluation du second, et ainsi de suite. Reprenons l’exemple précédent pour clarifier les choses.

/A/B[@att1=’a1’ and position()=last()]

On pourrait très bien dans cet exemple inverser les deux termes du and sans changer la signification de
l’expression : le prédicat s’évalue dans les deux cas en prenant pour contexte l’ensemble des nœuds obtenu
à l’issue de A/B. Prenons maintenant l’expression suivante :

/A/B[@att1=’a1’][position()=last()]
2.4. LE LANGAGE XPATH 103

Ici on va pendre tous les éléments B petit-fils de la racine du document qui ont un attribut att1 valant
a1 (premier prédicat). Puis on évalue le second prédicat pour ne garder que le dernier parmi les nœuds qui
ont satisfait le premier prédicat. Si on inverse les deux prédicats on a l’expression :

/A/B[position()=last()][@att1=’a1’]

Ici on commence par prendre le dernier nœud de type B, et on ne le garde que s’il a un attribut att1
de type a1. On obtient donc un résultat différent.

2.4.6 Types et opérations XPath


XPath fournit un support limité pour effectuer des opérations ou des comparaisons sur des nombres ou des
chaînes de caractères. Ces opérations ou comparaisons impliquent le plus souvent un typage de certaines
parties d’un document XML. On peut les utiliser pour les prédicats, afin de tester des valeurs numériques
par exemple, mais aussi avec XSLT quand on chercher à produire un résultat calculé à partir des informa-
tions du document source. On peut vouloir par exemple prendre des sous-chaînes, effectuer des calculs
arithmétiques, etc.
XPath connaît quatre types de données :

1. les numériques utilisent la notation décimale habituelle, avec un point pour les flottants (10.5) et un
signe moins (-) devant les nombres négatifs (-10) ;

2. les chaînes de caractères sont constituées d’une suite de caractères reconnus par le codage du docu-
ment, et délimitées par des guillemets (") ou des apostrophes (’) : attention les blancs sont significatifs
(“azerty” est différent de “ azerty “) ;

3. les booléens correspondent aux valeurs habituelles true et false ;

4. enfin les ensembles de nœuds sont un sous-ensemble, sans doublon, des nœuds du document source.

Les comparateurs usuels ( F , E , !=, =, F+L , E+L ) peuvent être utilisés pour tous les types scalaires
(numériques, chaînes et booléens). Pour les opérations on peut avoir besoin d’effectuer une conversion
d’un type à un autre. Ces conversions peuvent être soit implicites, quand l’expression indique clairement
que l’une des opérandes appartient à un type donné, soit explicites avec les fonctions number(), boolean()
et string().
Il faut bien noter qu’un document XML est essentiellement une chaîne de caractères structurée par des
balises, et n’est donc pas typé, comme peut l’être un programme écrit dans un langage comme Java ou
C++, chaque variable y étant déclarée comme appartenant à un certain type. Il ne peut donc y avoir de
garantie que le résultat d’une expression XPath puisse être converti dans le type attendu, et ce même si le
document est valide (conforme à une DTD). Cependant toute expression peut être convertie (« interprétée »)
soit comme un booléen, soit comme une chaîne, ce qui est particulièrement important pour les raisons
suivantes :

1. les tests effectués dans XSLT (xsl:if, xsl:when) peuvent prendre n’importe quelle expression,
l’évaluer, et considérer le résultat comme true ou false ;

2. la production de texte en XSLT (balise xsl:value-of) doit convertir le résultat d’une expression
XPath en chaîne de caractères pour l’incorporer au document résultat.

La compréhension des principales règles de typage, d’évaluation d’expressions typées et de conversions


d’un type à un autre ci-dessous est donc essentielle. Nous ne donnons pas en revanche dans ce chapitre la
liste complète des fonctions XPath qui figure dans l’annexe B
104 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Opérateurs Syntaxe et description


+ Addition : n1 + n2
- Soustraction : n1 - n2. Attention à laisser un blanc de chaque
côté du ’-’, sinon le signe est interprété comme faisant partie de
M n1 ou n2.
Multiplication : n1 * n2
div Division : n1 div n2 (laisser un blanc de chaque côté)
mod Reste de la division : n1 mod n2 (laisser un blanc de chaque
côté)

Table 2.17: Opérateurs numériques

Les numériques
Les opérateurs sur les types numériques sont donnés dans le tableau 2.17. La valeur numérique d’un nœud
est obtenue en lui appliquant la fonction number() qui fonctionne de la manière suivante :
5 élimination des blancs avant le premier caractère et après le dernier caractère ;
5 recherche du signe ’-’ ;
5 interprétation de la chaîne restante comme un numérique.
Si la conversion est impossible, la fonction renvoie NaN (« Not a Number »). Voici par exemple une
expression XPath qui recherche tous les nœuds ayant un attribut dont la valeur est impaire.
//node()[number(@att1) mod 2 = 1]
Sur notre exemple de référence, on obtiendrait le nœud C (figure 2.33).

Document
-

Instruction Element Comment


Java A -
ins1 CommFin

Element Element Element


B B C

Attr Element Element Attr Element Attr Attr


att1 att1 att2 att3
a1
D D a2
D a3 15

Text Text Text


- - -
Texte1 Texte2 Texte3

Figure 2.33: Résultat de //node()[number(@att1) mod 2 = 1]

Pour tous les nœuds ayant un attribut dont la valeur est une chaîne de caractères qui ne peut être
convertie vers un numérique, le résultat de la fonction est NaN,
Les comparaisons avec un NaN donnent des résultats assez étranges. Un test d’égalité renvoie false
si l’une des opérandes est NaN. En revanche un test d’inégalité (« != ») renvoie toujours true quand une
des opérandes est NaN. Voici quelques conséquences que nous vous laissons méditer :
2.4. LE LANGAGE XPATH 105

1. NaN = NaN vaut false ;


2. NaN != NaN vaut true ;
3. number(X) != number(X) vaut true si X n’est pas un nombre !
Nous voici donc dotés d’un bon moyen de rendre des expressions incompréhensibles. Ce n’est pas le
dernier.

Les booléens
Les booléens prennent deux valeurs, true et false, que l’on peut explicitement introduire dans les
expressions avec les fonctions true() et false(). Toutes les chaînes avec au moins un caractère, ainsi que
tous les numériques non nuls, sont assimilés à la valeur booléenne true ; les chaînes vides, la valeur 0
ou NaN sont assimilés à false. Ces règles permettent d’interpréter (en se donnant un peu de mal) les
conversions effectuées depuis une valeur de type numérique ou chaîne de caractères vers un booléen, soit
implicitement, soit avec la fonction boolean().
La conversion d’un booléen vers un autre type scalaire s’effectue selon les règles suivantes :
5 Vers un numérique (fonction number()) : on obtient 1 avec true, et 0 avec false.
5 Vers une chaîne (fonction string()) : on obtient la chaîne false ou la chaîne true.
Voici quelques exemples :
1. boolean(’azerty’) = true
2. boolean(’0’) = true
3. boolean(0) = false
4. number (1 = 0) = 0
5. number (1 = 1) = 1
6. string (1 = 1) = ’true’
Les choses se compliquent un peu plus quand on doit effectuer une comparaison entre un booléen et
une autre valeur, et notamment quand la conversion des deux opérandes est nécessaire pour les ramener
toutes deux au même type. Voici les règles de base :
1. quand l’opérateur est « = » ou « != » (comparison operator) la valeur non booléenne est convertie en
booléen ;
2. pour les autres opérateurs, on tient compte du type de l’opérande non booléenne :
(a) si c’est un numérique, on convertit le booléen en numérique (donc 0 ou 1) ;
(b) si c’est une chaîne, on convertit les deux opérandes en numérique.
Voici quelques exemples :
1. true() = 5 : on convertit 5 en booléen, ce qui donne true, et le résultat de la comparaison est
true ;
2. true() E 5 : on convertit le booléen true en numérique, ce qui donne 1, et le résultat de la
comparaison est false ;
3. true() != ’azerty’ : on convertit azerty en booléen, ce qui donne true, et le résultat de
la comparaison est false ;
4. false() E ’azerty’ : on convertit le booléen false en numérique, ce qui donne 0, ainsi que
azerty, ce qui donne 1, et le résultat de la comparaison est false ;
106 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Ensembles de nœuds
Étudions pour finir le cas des ensembles de nœuds. Notons tout d’abord qu’il est impossible de convertir
un type scalaire vers un ensemble de nœuds, ce qui divise par deux le problème : les conversions seront
toujours appliquées à un ensemble pour le transformer vers un type scalaire.
La conversion la plus courante s’effectue vers une chaîne de caractères. Voici tout d’abord les règles
donnant une valeur textuelle pour chaque type de nœud d’un arbre XPath :
5 pour un nœud de type Text, on obtient directement le contenu du nœud ;
5 pour un nœud de type Comment, on obtient toute la chaîne comprise entre ’ F !--’ et ’-- E ’ ;
5 pour un nœud de type ProcessingInstruction, on obtient toute la chaîne comprise entre le nom (ou
« cible ») de l’instruction et ’? E ’ ;
5 pour un nœud de type Attr, on obtient la valeur de l’attribut ;
5 enfin pour un nœud de type Element ou de type Document, le contenu textuel est la concaténation
de tous les contenus des descendants du nœud qui sont de type Text.

Par exemple, en reprenant encore une fois notre exemple de référence, le contenu de l’élément /A est la
concaténation de Texte1, Texte2 et Texte3 ; le contenu de l’élément /A/B[1]5 est la concaténation
de Texte1, Texte2, etc.
On peut maintenant définir comme suit les conversions d’un ensemble de nœuds vers les types scalaires :
1. vers une chaîne de caractères : c’est le contenu textuel du nœud de l’ensemble qui apparaît en
première position dans l’ordre du document.
2. vers un numérique : on convertit d’abord en chaîne, puis on convertit la chaîne avec number() ;
3. vers un booléen : la conversion booléenne d’un ensemble de nœuds donne true si l’ensemble n’est
pas vide, false sinon.
Le tableau 2.18 résume les règles de conversion que nous avons vues jusqu’ici.

De/Vers Booléen Numérique Chaîne Ensemble de nœuds


Booléen – false N 0; false N’false’ ; Interdit
true N1 true N ’true’
Numérique O et NaN N – format décimal Interdit
false ; sinon
true
Chaîne si vide Nfalse ; conversion vers – Interdit
sinon true nombre
Ensemble de nœuds si vide Nfalse ; conversion chaîne contenu du premier –
sinon true puis nombre nœud dans l’ordre
du document

Table 2.18: Conversions de types XPath

Il est maintenant possible d’effectuer des comparaisons entre un ensemble de nœuds et une instance de
n’importe quel autre type XPath. Voici les règles à appliquer à un ensemble de nœuds dénoté O :

1. pour comparer O et une chaîne P , on convertit tous les nœuds de O vers leurs valeurs textuelles ; si
une seule de ces valeurs est égale à P la comparaison renvoie true, et false sinon ;
2. pour comparer O et un nombre Q , on effectue comme précédemment une conversion de chaque
nœuds vers une valeur numérique, et on compare avec Q ;
5 Cette expression est équivalent à /A/B[position() = 1].
2.4. LE LANGAGE XPATH 107

3. pour une comparaison avec une valeur booléenne, on prend simplement la conversion de O vers un
booléen ;
4. enfin pour comparer O avec un second ensemble ORJ , on prend les valeurs textuelles des nœuds de
O et de ORJ et on les compare deux à deux : si on obtient true pour au moins une paire, alors la
comparaison globale renvoie true également.

2.4.7 Exemples d’expressions XPath


Nous concluons ce chapitre par des exemples (commentés !) d’expression, en abandonnant à partir de
maintenant l’exemple de référence que nous avons utilisé tout au long de cette section afin de pouvoir
explorer des cas plus riches et généraux.
Toutes les expressions qui suivent sont données d’abord dans leur forme développée puis, le cas
échéant, en utilisant la forme abrégée.
5 child::A/descendant::B : donne les éléments de type B descendants d’un élément de type
A, lui-même fils du nœud contexte ;
Forme abrégée : A//B
5 child::*/child::B : donne les éléments de type B petit-fils du nœud contexte ;
Forme abrégée : */B
5 descendant-or-self::B : donne les éléments de type B fils du nœud contexte, et le nœud
contexte lui-même s’il est de type B ;
5 child::B[position()=last() - 1] : donne l’avant-dernier élément de type B fils du nœud
contexte ;
Forme abrégée : B[last()-1]
5 following-sibling::B[position()=1]: donne le premier frère de droite du nœud con-
texte dont le type est B ;
5 /descendant::B[position()=12] : donne le douzième élément de type B du document ;
5 child::B[child::C] : donne les fils de type B qui ont eux-mêmes au moins un fils de type C :
le prédicat est ici une expression XPath qui renvoie un ensemble de nœuds, interprété comme false
s’il est vide, et true sinon ;
Forme abrégée : B[C]
5 /descendant::B[attribute::att1 and attribute::att2] : donne les éléments de
type B qui ont au moins un attribut att1 et un attribut att2 ;
Forme abrégée : //B[@att1 and @att2]
5 child::*[self::B or self::C] : donne les fils de type B ou de type C ;

Le tableau 2.19 récapitule les abréviations des expressions XPath. Il faut être prudent dans l’utilisation
de ces abréviations, et toujours se ramener à la forme développée quand on n’est pas sûr de la signification
de la forme abrégée. Si vous n’êtes pas convaincus, nous vous suggérons par exemple le lecteur de réfléchir
à la différence entre //B[1] et de /descendant::B[1]...
L’annexe B complète la description de XPath qui précède, en donnant notamment une liste complète
des fonctions reconnues par la norme.
108 CHAPTER 2. DOCUMENTS XML : STRUCTURE ET NAVIGATION

Abréviation Description
. Équivalent à self::node()
.. Équivalent à parent::node()
// Équivalent à /descendant-or-self::node()/
.// Équivalent à self::node()/descendant-or-self::node()/
@att Équivalent à attribute::att

Table 2.19: Les abréviations XPath


Chapter 3

XSLT

Sommaire
3.1 Programmes XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
3.1.1 Structure d’un programme XSLT . . . . . . . . . . . . . . . . . . . . . . . . . 111
3.1.2 Modularité : xsl:import et xsl:include . . . . . . . . . . . . . . . . . 115
3.1.3 Application d’un programme XSLT . . . . . . . . . . . . . . . . . . . . . . . . 117
3.2 Les règles XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
3.2.1 Les patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
3.2.2 Règles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
3.2.3 Déclenchement de règles avec xsl:apply-templates . . . . . . . . . . . 124
3.2.4 Sélection des règles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
3.2.5 Appel de règle avec xsl:call-template . . . . . . . . . . . . . . . . . . 131
3.2.6 Paramètres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
3.3 Instructions de contrôle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
3.3.1 Tests : xsl:if et xsl:choose . . . . . . . . . . . . . . . . . . . . . . . . . 134
3.3.2 Boucles : xsl:for-each . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
3.3.3 Variables : xsl:variable . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
3.3.4 Tri : xsl:sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
3.3.5 Itérations par récursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
3.4 Évaluation d’un programme XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Dans ce chapitre nous commençons notre étude approfondie de XSLT par les aspects relatifs à la pro-
grammation. Nous rassemblons sous ce terme toutes les instructions qui permettent de spécifier une trans-
formation d’un document source vers un document résultat. Il n’est sans doute pas inutile d’expliciter les
parties de XSLT qui ne relèvent pas directement de cette notion de programmation, et qui seront abordées
plus loin dans ce livre :

1. nous ne nous intéressons pas au style de programmation XSLT ;

2. les spécificités du langage de sortie sont pour l’instant ignorées : les exemples seront basés sur la
production de documents HTML simples ;

3. enfin nous délaissons pour l’instant les instructions qui sont orientées vers la mise en forme du
document résultat.

Si vous avez lu les chapitres qui précèdent – ce qui est recommandé – vous devriez déjà avoir une
compréhension intuitive d’une part des principes de base de XSLT, et d’autre part de la structuration d’un
document XML. Nous nous plaçons donc directement dans la situation où un programme, le processeur
XSLT, dispose en entrée de deux documents (figure 3.1) :

109
110 CHAPTER 3. XSLT

Processeur
arbre arbre
XSLT
DOM résultat

Sérialisation
Analyse

Document XML Document XSLT Document résultat

Figure 3.1: Schéma du traitement d’une transformations XSLT

S le document XML source


S le programme XSLT

Nous supposons que le document source a été analysé et se trouve disponible pour le processeur sous
forme d’un arbre DOM. Notez bien qu’il s’agit d’une vue « conceptuelle » et que, en pratique, les pro-
cesseurs XSLT sont libres de s’appuyer sur une représentation interne de leur choix. Sur la base des
informations trouvées dans le document source et des instructions du programme XSLT, le processeur pro-
duit un document résultat, qui peut également être vu comme un arbre construit au fur et à mesure de
l’évaluation (nous donnerons un exemple d’une telle évaluation en fin de chapitre). Une fois la transfor-
mation terminée, l’arbre résultat peut être sérialisé si besoin est pour être stocké, transmis sur le réseau,
etc
Nous prendrons comme exemple principal dans ce chapitre le document suivant, décrivant un cours (ou
l’ébauche d’un cours..) basé sur le présent livre.

Exemple 28 CoursXML.xml : Document XML pour le cours associé à ce livre

<?xml version=’1.0’ encoding="ISO-8859-1"?>

<COURS CODE="TC234">
<SUJET>Publication XSLT</SUJET>
<ENSEIGNANTS>
<!-- Enseignant responsable -->
<NOM>Amann</NOM>
<NOM>Rigaux</NOM>
</ENSEIGNANTS>
<PROGRAMME>
<SEANCE ID="1">Documents XML</SEANCE>
<SEANCE ID="2">Programmation XSLT</SEANCE>
<ANNEE>2002</ANNEE>
</PROGRAMME>
</COURS>

Nous commençons par décrire de manière globale le contenu d’un programme XSLT et des différents
types d’éléments que l’on peut y trouver. Nous passons ensuite à la description des règles (template), puis
aux instructions de contrôle qui permettent d’effectuer des itérations et tests. Enfin nous concluons ce
chapitre par l’exemple détaillé d’une évaluation d’un traitement XSLT.

3.1 Programmes XSLT


Un programme XSLT est un document XML. Ce document doit bien entendu être bien formé (fermeture
des balises, non-imbrication des balises ouvrante et fermante, etc). Les instructions spécifiques à XSLT
doivent aussi respecter une certaine structure – relativement simple – et se limiter à des types d’éléments
prédéfinis.
3.1. PROGRAMMES XSLT 111

3.1.1 Structure d’un programme XSLT


Un programme XSLT doit respecter les règles syntaxiques XML. Il faut bien être conscient que cela
s’applique non seulement aux éléments XSLT eux-mêmes, mais également aux éléments qui sont destinés à
être insérés dans le résultat, que nous appellerons élément littéraux par la suite. Le document XSLT suivant
par exemple n’est pas bien formé.

Exemple 29 ExXSLT1.xsl : Un document XSLT mal formé

<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="COURS">
<html>
<head><title>Fiche du cours</title></head>
<body bgcolor="white">
<p>
<h1>
<i><xsl:value-of select="SUJET"/></i>
</h1>
<hr>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Les éléments XSLT ne posent pas de problème, mais l’unique règle tente de produire le résultat suivant :
<html>
<head><title>Fiche du cours</title></head>
<body bgcolor="white">
<p>
<h1>
<i>Publication XSLT</i>
</h1>
<hr>
</body>
</html>
Bien qu’il s’agisse d’un document HTML très correct (en tout cas conforme à la norme HTML 4.0),
les éléments littéraux T p U et T hr U ne sont pas refermés. La présence de ce fragment HTML n’est donc
pas acceptée dans le programme XSLT.
Cela illustre bien le fait que XSLT est avant tout destiné à transformer un document XML en un
autre document XML, par production de fragments bien formés. La sortie d’un document « texte » qui
ne serait pas du XML bien formé est possible mais implique des options spéciales qui seront étudiées dans
le chapitre 4.

L’élément xsl:stylesheet
L’élément racine d’un document XSLT est de type xsl:stylesheet. La forme habituelle de cet élé-
ment est :

<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
112 CHAPTER 3. XSLT

On trouve donc en général deux attributs :

1. L’attribut version est obligatoire et correspond au numéro de version de la « recommandation »


XSLT publiée par le W3C. La seule recommandation à l’heure où ce livre est écrit est la 1.0, la 1.1
étant à l’état de Working Draft.
2. L’attribut xlmns:xsl définit l’espace de nom (namespace) xsl et l’associe à l’URI
http://www.w3.org/1999/XSL/Transform
Ce mécanisme permet de qualifier tous les éléments XSLT par le préfixe xsl:, et de considérer tous
les autres éléments comme des éléments littéraux à inclure dans le document résultat. Les espaces
de nom sont étudiés dans le chapitre 6.

Il existe d’autres attributs possibles pour xsl:stylesheet. Ils seront présentés au fur et à mesure.
Notez qu’il existe également un type d’élément xsl:transform qui est l’exact synonyme de xsl:stylesheet.

Remarque : Dans ce chapitre et les suivants nous avons choisi de ne pas donner une présentation ex-
haustive des attributs et des règles syntaxiques relatives à chaque élément XSLT, afin de rendre la lecture
plus facile et de privilégier la « mise en contexte » de ces éléments. L’annexe B en revanche contient une
référence XSLT avec la syntaxe de chaque élément : l’élément xsl:stylesheet par exemple est décrit
page 278.

Sous l’élément racine xsl:stylesheet on trouve le contenu du programme au sein duquel on dis-
tingue communément deux types d’éléments. Tout d’abord les éléments de premier niveau (top-level ele-
ments) sont fils de l’élément racine xsl:stylesheet. Le principal élément de ce type est xsl:template
qui est utilisé pour définir les règles XSLT. Les instructions constituent le second type d’élément : on les
trouve essentiellement dans les corps de règles.

Éléments de premier niveau


Les types d’élément qui peuvent être fils de l’élément racine T xsl:stylesheet U sont dit « éléments
de premier niveau » (top-level éléments). Ils sont tous (du moins ceux de la version 1.0) rassemblés dans le
tableau 3.1, avec une courte description et la page où vous pouvez trouver la référence pour l’élément.

Type d’élément Description


xsl:attribute-set Définit un groupe d’attributs (page 259)
xsl:decimal-format Définit un format d’affichage pour les numériques (page 266)
xsl:import Import d’un programme XSLT (page 268)
xsl:include Inclusion d’un programme XSLT (page 269)
xsl:key Définit une clé pour un groupe de nœuds (page 270)
xsl:namespace-alias Définit des alias pour certains espaces de nom (page 271)
xsl:output Indique le format de sortie (HTML, XML, texte) (page 273)
xsl:param Définit un paramètre (page 273)
xsl:preserve-space Conserve les nœuds texte constitués d’espaces pour certain éléments (page 274)
xsl:strip-space Supprime les nœuds texte constitués d’espaces pour certains éléments (page 278)
xsl:template Définit une règle XSLT (page 279)
xsl:variable Définit une variable XSLT (page 281)

Table 3.1: Éléments XSLT de premier niveau

Tous ces types d’élément ne sont pas de la même importance, et tous ne couvrent pas le même type
de fonctionnalité. Même s’il est difficile d’établir une classification qui ne soit pas, au moins en partie,
arbitraire, on peut grossièrement distinguer
S les éléments qui affectent la production du document résultat ;
3.1. PROGRAMMES XSLT 113

S les éléments qui s’appliquent à la transformation du document source.

Dans ce chapitre nous décrivons les éléments qui relèvent de la seconde catégorie : xsl:template,
xsl:param et xsl:variable. Les éléments relatifs à la production du résultat sont pour l’essentiel
présentés dans le prochaine chapitre.
L’ordre des éléments de premier niveau n’a pas d’impact sur le comportement du programme XSLT
(à l’exception de xsl:import : voir ci-dessous), et on peut les arranger dans l’ordre qui semble le plus
convenable pour la lecture. Cette particularité constitue l’un des aspects du caractère « déclaratif » de
XSLT : on indique les actions à effectuer en présence de certains événements, à charge pour le processeur
de déclencher ces actions de manière appropriée.
Quels sont les autres fils possibles de xsl:stylesheet ? Il est interdit d’avoir des nœuds de type
Text, autrement dit du texte placé immédiatement sous l’élément racine. En revanche on peut trouver des
commentaires et des instructions de traitement, les premiers étant ignorés, et le second pris en compte
seulement s’ils contiennent des instructions reconnues par le processeur.
Dans le même esprit, on peut trouver au premier niveau des éléments dont le type est spécifique au
processeur XSLT. En général ces éléments se distinguent par un préfixe comme xalan:, msxml3: ou
saxon:. L’introduction de ce type d’élément non normalisé risque de poser des problèmes de portabilité
si on souhaite qu’un programme XSLT puisse être traité par n’importe quel processeur.
Enfin le concepteur d’un programme peut lui-même définir ses propres éléments de premier niveau,
en les caractérisant par un préfixe. Cela n’a d’intérêt que pour introduire du contenu (par exemple : des
codifications, des messages en plusieurs langues, des paramètres..) au sein d’un programme, en plus des
instructions de ce programme. Ces éléments sont ignorés par le processeur, et leur utilité est douteuse. On
peut en tout cas toujours s’en passer et utiliser d’autres mécanismes.
En résumé les éléments du tableau 3.1 constituent la référence des types d’éléments, fils de xsl:stylesheet,
reconnus par n’importe quel processeur XSLT conforme à la recommandation XSLT 1.0. Un des ajouts
importants prévus dans la version 1.1 est un élément xsl:script qui permettra d’introduire des parties
programmées (en Java ou JavaScript) dans un programme XSLT. Cette extension risque de soulever des
problèmes de portabilité et fait l’objet d’un débat au sein du groupe de normalisation.

Instructions XSLT
L’exécution d’un programme XSLT consiste à déclencher (ou instancier) des règles définies par des élé-
ments de premier niveau xsl:template. L’instanciation d’une règle consiste à produire un fragment du
document résultat en fonction :

1. d’éléments littéraux ;
2. de texte ;
3. d’instructions XSLT.

Toute combinaison de tels constituants est nommée un corps de règle. Alors que les deux premières
catégories (éléments littéraux et texte) sont insérés dans le document résultat, les instructions XSLT sont
interprétées par le processeur XSLT. Voici par exemple un corps de règle que nous avons rencontré dans le
chapitre introductif : il crée une liste HTML avec les séances d’une salle de cinéma :

<h3>Séances</h3><ol>
<xsl:for-each select="SEANCES/SEANCE">
<li><xsl:value-of select="."/></li>
</xsl:for-each>
</ol>

On trouve donc des éléments littéraux (balises T h3 U , T ol U , T li U et leurs fermetures), des nœuds
de type Text (par exemple le nœud fils de T h3 U dont le contenu est Séances), et enfin des instructions,
éléments dont le nom est préfixé par xsl:. La notion de corps de règle est assez large et recouvre toute
partie du programme destinée à produire un fragment du document résultat.
114 CHAPTER 3. XSLT

Le tableau 3.2 donne la liste de toutes les instructions XSLT 1.0 à l’exception de xsl:document qui
est défini dans XSLT 1.1, mais déjà largement présent dans les implantations actuelles. Comme pour les
éléments de premier niveau, nous donnons une brève description, ainsi que la page de l’annexe B où vous
pouvez trouver la référence de l’instruction.

Type d’élément Description


xsl:apply-imports Permet d’appliquer une règle importée, tout en la
complétant par un nouveau corps (page 255)
xsl:apply-templates Déclenche l’application de règles (page 256)
xsl:attribute Insère un attribut dans un élément du document
résultat (page 258)
xsl:call-template Appelle une règle par son nom (page 259)
xsl:choose Structure de test équivalente au switch d’un lan-
gage comme Java ou C++ (page 261)
xsl:comment Insère un nœud Comment dans le document ré-
sultat (page 262)
xsl:copy Copie un nœud du document source dans le docu-
ment résultat (page 264)
xsl:copy-of Copie un nœud, ainsi que tous ses descendants
(page 265)
xsl:document Permet de créer plusieurs documents résultats
(XSLT 1.1) (page 266)
xsl:element Insère un nœud Element dans le document résul-
tat (page 267)
xsl:fallback Règle déclenchée si le processeur ne reconnaît une
instruction (page 268)
xsl:for-each Pour effectuer des itérations (page 268)
xsl:if Pour effectuer un branchement conditionnel
(page 268)
xsl:message Pour produire un message pendant le traitement
XSLT (page 270)
xsl:number Permet de numéroter les nœuds du document ré-
sultat (page 272)
xsl:variable Permet de définir un paramètre (page 273)
xsl:processing-instruction Insère un nœud ProcessingInstruction dans le
document résultat (page 275)
xsl:text Insère un nœud Text dans le document résultat
(page 280)
xsl:value-of Évalue une expression XPath et insère le résultat
(page 280)
xsl:variable Permet de définir une variable (page 281)

Table 3.2: Instructions XSLT

On peut noter que xsl:variable et xsl:param sont les types d’élément à apparaître à la fois
comme élément de premier niveau et comme instruction. L’emplacement de l’élément définit la portée de
la variable et du paramètre : voir page 138.
Si l’on s’en tient à la classification déjà faite précédemment, on constate que les instructions rela-
tives à la transformation du document source plutôt qu’à la production du résultat sont xsl:apply-
templates et xsl:call-template qui toutes deux déclenchent des règles, xsl:choose, xsl:for-
each, xsl:if, xsl:message et xsl:variable qui correspondent à peu près aux tests, itérations,
sorties à l’écran et définitions de variables que l’on trouve dans la programmation la plus classique. Ces
« instructions de contrôle » sont présentées page 134
3.1. PROGRAMMES XSLT 115

3.1.2 Modularité : xsl:import et xsl:include


Jusqu’à présent nous avons toujours considéré qu’un programme XSLT était contenu dans un seul fichier.
Heureusement il est possible, comme dans tout langage de programmation digne de ce nom, d’introduire
une certaine modularité afin de répartir les instructions dans plusieurs fichiers d’un taille raisonnable, et
surtout de pouvoir réutiliser une règle dans plusieurs programmes.
XSLT fournit deux éléments de premier niveau pour intégrer des fichiers afin de constituer des pro-
grammes : ce sont xsl:import et xsl:include. Signalons tout de suite que les notions de « librairie »
constituée de « module » qui ne peuvent être utilisés indépendamment, et de « programme principal » con-
stitué par assemblage de librairies, n’existent pas en XSLT. Rien ne distingue, du point de vue syntaxique,
un programme destiné à être inclus d’un programme incluant ou important d’autres fichiers. Tous doivent
être des programmes XSLT conformes, avec un élément racine xsl:stylesheet.
L’assemblage de plusieurs programmes peut créer des conflits. Au moment de l’évaluation plusieurs
règles peuvent s’appliquer aux mêmes nœuds. Afin de déterminer la règle à appliquer, XSLT utilise un
système de priorités que nous décrivons page 127. La distinction entre xsl:include et xsl:import
est justement relative à la méthode appliquée pour choisir une règle en cas de conflit :

1. dans le cas de xsl:import le processeur affecte aux règles importées une préséance1 inférieure à
celles du programme importateur ;
2. dans le cas de xsl:include, le processeur traite les règles du programme inclus sans les dis-
tinguer, en terme de préséance, de celles du programme principal : tout se passe comme si xsl:include
était simplement remplacé, avant l’évaluation, par le contenu du programme référencé.

Une autre différence entre ces deux types d’élément est que xsl:import doit apparaître avant
tout autre élément de premier niveau dans un programme XSLT. On peut trouver en revanche plusieurs
xsl:import puisque rien n’empêche d’importer plusieurs fichiers dans un programme.
À l’exception des différences ci-dessus, xsl:include et xsl:import sont très proches. Dans les
deux cas un fichier inclus/importé peut lui-même inclure ou importer d’autres fichiers, tant qu’il n’existe
pas de cycle qui mènerait un fichier à s’inclure lui-même. Les deux types d’élément partagent également
la même syntaxe : le nom ou l’URI du fichier inclus est référencé dans l’attribut href :

<xsl:import href="Programme.xsl"/>

Prenons un premier exemple pour illustrer l’intérêt du mécanisme (nous utilisons xsl:import mais
on pourrait dans l’exemple ci-dessous remplacer xsl:import par xsl:include avec un résultat
équivalent – il n’y a pas de conflit de règles).
Le fichier ExXSLTImport.xsl contient une première règle qui s’applique à un élément racine de type
COURS, produit un « squelette » de document HTML avec le sujet du cours dans la balise T TITRE U , et
enfin déclenche un appel de règles avec xsl:apply-templates.

Exemple 30 ExXSLTImport.xsl : Un programme à importer


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>

<xsl:template match="/">
<html>
<head><title><xsl:value-of select="COURS/SUJET"/></title></head>
<body bgcolor="white">
<xsl:apply-templates/>
1 Nous utilisons le terme (un peu désuet) de préséance pour traduire l’anglais precedence, et distinguer cette notion de celle de

priorité d’application des règles.


116 CHAPTER 3. XSLT

</body>
</html>
</xsl:template>

<xsl:template match="SUJET | ENSEIGNANTS | PROGRAMME"/>

</xsl:stylesheet>

La seconde règle s’applique aux fils de T COURS U et ne fait rien. Le programme est donc très « neutre »
vis-à-vis du contenu du document source. Il se contente de produire le « cadre » de présentation HTML
ci-dessous.
Exemple 31 ExXSLTImport.html : Le document HTML produit par ExXSLTImport.xsl
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Publication XSLT</title>
</head>
<body bgcolor="white"></body>
</html>

On peut imaginer que cette règle pourrait produire un squelette HTML beaucoup plus sophistiqué, avec
menus, frames, contrôles JavaScript, et tout un attirail graphique rendant la présentation beaucoup plus
attrayante. L’intérêt est qu’une fois cette mise en page réalisée et insérée dans l’unique règle, on peut la
réutiliser en l’important dans d’autres programmes.
Voici un programme qui affiche la liste des enseignants du cours. Il commence par importer le fichier
ExXSLTImport.xsl, ce qui dispense de définir une règle s’appliquant à la racine du document. Ensuite on
redéfinit les règles s’appliquant au sous-arbre des enseignants pour produire une liste avec les noms. Ces
règles ont une préséance supérieure à celles du fichier importé qui ne produisaient aucun résultat.
Exemple 32 ExXSLTPrincipal.xsl : Un programme importateur de ExXSLTImport.xsl
<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:import href="ExXSLTImport.xsl"/>

<xsl:template match="COURS/ENSEIGNANTS">
<ol><xsl:apply-templates select="NOM"/></ol>
</xsl:template>

<xsl:template match="NOM">
<li><xsl:value-of select="."/></li>
</xsl:template>

</xsl:stylesheet>

La préséance doit être distinguée du niveau de priorité d’une règle, notion que nous exposerons page 127.
La préséance s’applique à l’importation de programme, et elle est toujours inférieure pour les règles du pro-
gramme importé par rapport aux règles du programme importateur.
Cette règle se généralise assez simplement à l’importation de plusieurs documents de la manière suiv-
ante :
S si un document VXW est importé avant un document VZY , alors toutes les règles de VCY ont une préséance
supérieure à celles de VXW ;
3.1. PROGRAMMES XSLT 117

S si une règle [\W a une préséance supérieure à [)Y , elle-même supérieure à [-] , alors [^W a une préséance
supérieure à [ ] (transitivité).

Prenons un exemple simple, illustré dans la figure 3.2. le document principal A importe d’abord B, qui
lui-même importe C et D, puis A importe E qui importe F.

B E

C D F

Figure 3.2: Exemple de plusieurs imports

Les règles de C ont une préséance inférieure à celles de B, et donc inférieures à celles de A. C’est vrai
aussi des règles de D, mais elles ont une préséance supérieure à celles de C puisque D est importé après C.
Enfin les règles de F ont une préséance inférieure à celles de E, mais supérieures à toutes celles issues de
B, C ou D puisque F a été importé après. En résumé l’ordre (descendant) de préséance pour ces documents
est A, E, F, B, D et C.

Remarque : On peut voir dans cet arbre que l’ordre descendant de préséance pour ces documents corre-
spond à un parcours en post-ordre (en profondeur de droit à gauche).

L’ordre de préséance est pris en compte au moment où le processeur recherche les règles applicables
à un nœud. Si plusieurs règles sont candidates, seules celles ayant l’ordre de préséance le plus élevé sont
conservées et prises en compte. Au sein de ces règles, c’est alors l’ordre de priorité qui s’applique.
Le mécanisme d’importation s’apparente à la surcharge de méthode en programmation orienté-objet.
Dans les deux cas on réutilise les parties génériques et on redéfinit les parties spécifiques à une situation
donnée. Un inconvénient possible est que la totalité de la règle importée est remplacée par la règle du pro-
gramme local, alors que l’on peut souhaiter parfois exécuter cette règle importée tout en l’enrichissant de
quelques instructions complémentaires. C’est ce que permet l’instruction XSLT xsl:apply-imports,
présentée page 255.

3.1.3 Application d’un programme XSLT


Un programme XSLT s’applique à un document XML pour en effectuer une transformation. Comment et
quand déclencher cette transformation ? Si on prend comme application de base la publication d’informations
sur le Web, on peut envisager plusieurs situations :

1. serveur statique : les transformations sont effectuées en batch afin de produire les pages HTML à
partir d’un ou plusieurs documents XML ; les pages HTML statiques sont alors transférées sur le
serveur ;

2. serveur dynamique : cette fois la transformation s’effectue la demande en fonction des requêtes
HTTP ;

3. client dynamique : le document XML et le programme XSLT sont transmis au client qui effectue la
transformation.

La première solution est simple et ne pose pas de problème de performance puisque les pages HTML
sont directement disponibles. Elle peut souffrir d’un certain manque de réactivité, le contenu étant figé
entre deux transformations.
118 CHAPTER 3. XSLT

La plupart des processeurs permettent des transformations « statiques » à partir de la ligne de com-
mande. Voici par exemple une transformation avec Xalan, le processeur XSLT de la fondation Apache
dont l’installation est décrite dans l’annexe A. La commande transforme le document Alien.xml avec le
programme Film.xsl, et produit la page HTML Alien.html.

java org.apache.xalan.xslt.Process -in Alien.xml


-xsl Film.xsl -out Alien.html

La seconde solution permet une adaptation aux évolutions en temps réel, mais risque de soulever des
problèmes de performances si de très nombreuses transformations doivent être effectuées sur des docu-
ments volumineux. Plusieurs environnements de publication basée sur ce mécanisme existent : Cocoon par
exemple, également produit par la fondation Apache, se base sur le processeur Xalan pour déclencher des
transformations dynamiquement en fonction de la requête HTTP, du type de navigateur utilisé, etc (voir
annexe A).
Enfin la dernière solution consiste à effectuer la transformation sur le client. À l’heure actuelle seul le
navigateur Internet Explorer 5 (IE5) dispose d’un processeur XSLT intégré. Outre les problèmes de com-
patibilité avec le navigateur, cette solution présente l’inconvénient de transmettre toutes les informations
du document XML au client, ce qui n’est pas forcément souhaitable,

L’instruction T ?xml-stylesheet? U
Le moyen le plus courant pour associer un document XML à un programme XSLT est une instruction
de traitement T ?xml-stylesheet? U qui doit apparaître dans le prologue du document à transformer.
Voici par exemple comment indiquer, dans le document Alien.xml, que le programme associé est Film.xsl.

<?xml-stylesheet href="Film.xsl" type="text/xsl"?>

C’est une instruction de traitement, dont le nom est xml-stylesheet, et le contenu une liste
d’attributs2 . Ces attributs sont :
S href, qui donne l’URI du programme XSLT (ce peut être un fichier local, ou un fichier accessible
sur le Web) ;
S type, qui donne le type MIME du programme XSLT : text/xml ou text/xsl sont des choix
reconnus, le premier étant celui officiellement préconisé par le W3C ;
S title, une chaîne de caractère qui peut être utilisée pour permettre le choix du programme à appli-
quer ;
S media, qui indique le format du document produit par la transformation ;
S alternate, qui vaut no si le programme XSLT référencé doit être utilisé en priorité, ou yes
sinon.

Les deux premiers attributs sont obligatoires, les autres servant essentiellement à effectuer un choix
quand plusieurs instructions T ?xml-stylesheet? U sont présentes. L’interprétation de ces attributs et
les valeurs qu’ils peuvent prendre sont en parties dépendantes du processeur ou de l’environnement. Voici
par exemple comment on peut indiquer à l’environnement de publication Cocoon une transformation par
défaut avec le programme Film.xsl, et, seulement dans le cas d’un dialogue avec un terminal WML, le
programme FilmWML.xsl.

<?xml-stylesheet href="Film.xsl" type="text/xsl"?>


<?xml-stylesheet href="FilmWML.xsl" type="text/xsl" media="wap"?>
2 Une instruction de traitement n’étant pas un élément, on ne peut pas dire qu’elle a des « attributs » au sens strict du terme. Il ne
s’agit ici que d’un choix de présentation afin de clarifier le contenu de l’instruction, mais celui-ci pourrait être constitué de texte non
structuré.
3.2. LES RÈGLES XSLT 119

L’utilisation de cette instruction n’est pas toujours souhaitable car elle va dans une certaine mesure à
l’encontre d’une séparation stricte du document XML et des programmes de transformation. Chaque pro-
cesseur définit ses propres modes d’application de programme XSLT. Signalons également que la recom-
mandation XSLT prévoit la possibilité d’inclure directement le programme XSLT dans le document XML
à transformer (embedded stylesheets). Dans ce cas il n’y a plus de document XSLT indépendant, ce qui
empêche de réutiliser un programme pour d’autres documents XML de même structure.

3.2 Les règles XSLT


Nous décrivons dans cette section les règles XSLT et leur déclenchement. Il s’agit d’un des aspects es-
sentiels de XLST puisque dans beaucoup de cas on peut écrire un programme sous la forme de règles se
déclenchant sur certains nœuds et produisant une partie du résultat. La définition d’une règle s’effectue
avec l’élément xsl:template, et le déclenchement avec xsl:apply-templates ou xsl:call-
template.
Une règle peut être déclenchée (« instanciée ») soit par son nom, soit en donnant la catégorie des nœuds
du document source auxquels elle s’applique. Cette catégorie est spécifiée par une sous-classe des expres-
sions XPath désignée par le terme pattern dans la recommandation XSLT. Nous commençons par présenter
ces patterns avant de revenir en détail sur les règles et leur instanciation.

3.2.1 Les patterns


Le déclenchement des règles basé sur les patterns n’est pas la partie la plus évidente de XSLT. Nous
prenons un exemple simple pour commencer.

Un exemple
Le programme suivant recherche et affiche les noms des enseignants, les attributs ID et l’intitulé des
séances de cours.

Exemple 33 Pattern1.xsl : Exemple pour illustrer les patterns


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<xsl:apply-templates select="//NOM"/>

<xsl:apply-templates select="//SEANCE/@ID"/>

<xsl:apply-templates select="//SEANCE"/>
</xsl:template>

<xsl:template match="NOM">
<NOM><xsl:value-of select="."/></NOM>
</xsl:template>

<xsl:template match="@ID">
<IDSEANCE><xsl:value-of select="."/></IDSEANCE>
</xsl:template>

<xsl:template match="PROGRAMME/SEANCE">
<SEANCE><xsl:value-of select="."/></SEANCE>
120 CHAPTER 3. XSLT

</xsl:template>

</xsl:stylesheet>

Appliqué à notre document CoursXML.xml (page 110), on obtient le document suivant :

Exemple 34 Pattern1.xml : Le résultat du programme

<?xml version="1.0" encoding="ISO-8859-1"?>


<NOM>Amann</NOM><NOM>Rigaux</NOM>
<IDSEANCE>1</IDSEANCE>
<IDSEANCE>2</IDSEANCE>
<IDSEANCE>3</IDSEANCE>
<SEANCE>Introduction</SEANCE>
<SEANCE>Documents XML</SEANCE>
<SEANCE>Programmation XSLT</SEANCE>

On trouve dans le programme Pattern1.xsl plusieurs expressions XPath. Certaines apparaissent comme
valeur de l’attribut match de l’élément xsl:template, d’autres comme valeur de l’attribut select
de xsl:apply-templates. Elles jouent un rôle différent :

1. l’expression dans l’élément xsl:apply-templates sert à désigner un ensemble de nœuds, et


constitue donc une utilisation classique de XPath ;

2. l’expression dans l’élément xsl:template exprime en revanche une condition sur les nœuds qui
vont permettre de déclencher la règle.

Les deux éléments fonctionnent solidairement : xsl:apply-templates permet de constituer un


ensemble de nœuds issus du document source. Puis, pour chacun de ces nœuds, le processeur XSLT va
chercher la règle (on suppose qu’il n’y en a qu’une pour l’instant) telle que le nœud « satisfait » la condition
exprimée par l’attribut match.
Il reste à définir la satisfaction d’un condition exprimée par l’expression de l’attribut match – appelons
cette expression pattern à partir de maintenant. On peut l’exprimer assez simplement de la manière suiv-
ante : un nœud _ satisfait un pattern s’il existe quelque part dans l’arbre du document source un nœud `
tel qu’en évaluant le pattern avec ` comme nœud contexte, on obtienne un ensemble qui contient _ .

La première règle

Reprenons notre exemple 33. Le premier ensemble de nœuds considéré par le processeur XSLT est la
racine du document. On cherche donc la (ou les) règle(s) dont le pattern est satisfait par ce nœud racine. Il
n’en existe qu’une, c’est la première règle. Son pattern est « / », et en l’évaluant à partir de n’importe quel
nœud du document source, on obtient la racine la racine du document.
On déclenche alors la règle qui consiste en trois éléments xsl:apply-templates.

La règle avec match="NOM"

Le premier xsl:apply-templates constitue, par évaluation de l’expression XPath, l’ensemble de


tous les nœuds de type NOM. Pour chacun de ces nœuds, le processeur XSLT va chercher la (ou les) règles
dont le nœud satisfait le pattern.
Seule la seconde règle convient. En prenant en effet comme nœud contexte le nœud de type EN-
SEIGNANT et en évaluant le pattern NOM, j’obtiens bien tous les nœuds de type NOM. Remarquez que cette
règle se déclenche pour tous les éléments de type NOM, quelle que soit leur position dans l’arbre, puisqu’il
suffit de prendre le père de ces nœuds (quel qu’il soit) et d’évaluer le pattern pour que la condition soit
satisfaite.
3.2. LES RÈGLES XSLT 121

La règle avec match="@ID"


Le second xsl:apply-templates constitue, par évaluation de l’expression XPath, l’ensemble de
tous les attributs ID des nœuds de type SEANCE. Cette fois c’est la troisième règle qui est déclenchée.
En prenant en effet le père T SEANCE U de chaque attribut et en évaluant le pattern @ID, on obtient bien
l’attribut lui-même.
Comme précédemment, remarquez que cette règle se déclenche pour tous les attributs ID, quel que soit
le type de l’élément auquel ils appartiennent.

La règle avec match="PROGRAMME/SEANCE"


Le dernier xsl:apply-templates constitue, par évaluation de l’expression XPath, l’ensemble de
tous nœuds de type SEANCE. C’est la dernière règle qui va être déclenchée. Prenons en effet le premier
nœud T SEANCE U comme nœud courant. En prenant le père de ce nœud ( T PROGRAMME U ) comme nœud
contexte et en évaluant le pattern, on obtient un ensemble vide. On ne peut donc pas dire, à ce stade, que
la condition est satisfaite.
En prenant maintenant le grand-père, le nœud T COURS U , et en évaluant PROGRAMME/SEANCE, on
obtient bien un ensemble qui contient notre premier nœud T SEANCE U , et la condition déclenchant la règle
est satisfaite.
On peut noter cette fois que la règle ne s’applique qu’aux éléments de type SEANCE, eux-même fils
d’un élément de type PROGRAMME. Cette règle est donc moins générale.
En conclusion un pattern dans une règle définit la « situation » des nœuds de l’arbre qui vont pouvoir
déclencher la règle. Cette situation peut être très générale : un pattern « NOM » définit une règle applicable
à tous les éléments de type NOM, quel que soit leur position, et que que soit le type de leurs parents. Un
pattern comme « PROGRAMME/SEANCE » est déjà plus restrictif. À l’extrême, un pattern peut être un
chemin absolu XPath, et la règle ne s’applique plus alors qu’à des arbres très particuliers.

Expressions XPath et patterns


Pourquoi distinguer les patterns et les expressions XPath ? Pour les deux raisons suivantes :

1. l’interprétation d’un pattern consiste à l’évaluer à partir d’un nœud contexte et à vérifier que le nœud
courant appartient au résultat : l’expression doit donc donner un ensemble de nœuds ;
2. si on acceptait toutes les expressions XPath donnant un ensemble de nœuds, il faudrait, pour vérifier
si un nœud vérifie un pattern, évaluer l’expression pour tous les nœuds du document source, à chaque
fois.

La règle suivante par exemple n’est pas valide : l’attribut match est une expression XPath correcte
mais dont le résultat n’est pas un ensemble de nœuds. La condition de déclenchement de la règle n’a donc
pas de sens.

<!-- Pas bon -->


<xsl:template match="1">
...
</xsl:template>

De plus, toutes les expressions XPath donnant un ensemble de nœuds ne sont pas acceptées, essentielle-
ment pour des raisons de performance et de complexité d’implantation du processeur XSLT. La règle suiv-
ante par exemple est interdite, et ce bien que l’attribut match soit une expression XPath dont l’évaluation
donne un ensemble de nœuds.

<!-- Pas bon -->


<xsl:template match="preceding::node()[5]">
...
</xsl:template>
122 CHAPTER 3. XSLT

Pour déterminer si cette règle doit être déclenchée quand on rencontre un nœud _ , il faut regarder si
on trouve un nœud en cinquième position dans l’ordre des successeurs de _ . Si un tel nœud existe, alors
l’évaluation du pattern donnera _ .
Il est clair qu’autoriser toutes les expressions XPath engendrerait des problèmes de performance, ainsi
que des difficultés de développement des processeurs XSLT. Les seuls axes autorisés dans les pattern
sont donc child et attributes ainsi que leur syntaxe abbrégé. En plus, il est possible d’utiliser la
syntaxe abbrégé // de descendant-or-self::node()/child:: (Attention, il n’est pas possible
d’utiliser l’axe descendant-or-self explicitement dans un pattern).
Cette restriction permet de décrire l’évaluation d’un pattern a par rapport à un nœud courant _ selon
l’algorithme suivant :

1. prendre _ comme nœud contexte et évaluer a ; si _ fait partie du résultat, alors _ satisfait a ;
2. sinon prendre le père de _ , et recommencer l’évaluation ; si _ fait partie du résultat, alors _ satisfait
a ;
3. sinon recommencer en parcourant les ancêtres de _ jusqu’à la racine du document.

Évidemment il est possible dans la plupart des cas d’éviter le parcours de tous les ancêtres du nœud
courant. Il faut cependant être conscient que l’évaluation d’un pattern doit être faite pour tous les nœuds
désignés par xsl:apply-templates, et qu’elle peut être longue si l’expression est complexe.

Quelques exemples
Voici quelques exemples de patterns avec leur signification.
S /COURS/ENSEIGNANTS sera satisfait par tous les nœuds de type ENSEIGNANTS fils d’un élément
racine de type COURS ;
S //SEANCE[@ID=2] ou SEANCE[@ID=2] seront satisfait par tout nœud de type SEANCE ayant
un attribut ID valant 2 (férifiez si les deux expressions sont équivalentes) ;
S NOM[position()=2] sera satisfait par tout nœud qui est le deuxième fils de type NOM de son
père ;
S *[position()=2][name()="NOM" sera satisfait par tout nœud de type NOM, second fils de
son père ;
S /COURS/@CODE[.="TC234"] sera satisfait par le nœud de type Attr, de nom CODE, fils de
l’élément racine T COURS U , et dont la valeur est TC234.

3.2.2 Règles
Une règle est définie par un élément de premier niveau xsl:template. Cet élément comprend des at-
tributs qui décrivent les conditions de déclenchement de la règle, et un contenu ou corps de règle décrivant
le texte à produire quand la règle est déclenchée (ou « instanciée » pour utiliser le vocabulaire XSLT).
L’instanciation d’une règle s’effectue toujours pour un nœud du document source qui est désigné par le
terme de nœud courant. Toute expression XPath utilisée dans le corps de la règle, que ce soit pour ef-
fectuer des tests, extraire des informations ou appeler d’autre règle, prendra le nœud courant comme nœud
contexte.

L’élément xsl:template
Les attributs sont au nombre de quatre 3 :

1. match est le pattern désignant les nœuds de l’arbre XML pour lesquels la règle peut se déclencher ;
3 La syntaxe complète de l’élément (ainsi que de tous ceux que nous présentons par la suite) est donnée dans l’annexe B, page 279.
3.2. LES RÈGLES XSLT 123

2. name définit une règle nommée qui pourra être appelée directement par son nom avec xsl:call-
template ;

3. mode permet de définir des catégories de règles, à appeler dans des circonstances particulières ;

4. enfin priority donne une priorité explicite à la règle.

Tous les attributs sont optionnels, mais soit name, soit match doit être défini. Dans le premier cas la
règle sera appelée par xsl:call-template, dans le second cas, c’est au processeur de déterminer, en
fonction du nœud courant et du pattern (ainsi que de la résolution des conflits éventuels), si la règle doit être
appelée. Ces deux types de règles correspondent à deux styles de programmation différents. Le premier cas
(appel de règle) s’apparente plutôt à une programmation par appel de fonction, tandis qu’avec le second,
plus « déclaratif », on se contente de « déclarer » ce qu’on veut obtenir, à charge pour le processeur de faire
le choix de la règle appropriée.

Règles par défaut


XSLT définit un ensemble de règles par défaut qui sont appliquées quand aucune règle du programme n’est
sélectionnée. La première règle par défaut s’applique à la racine du document et à tous les éléments. Elle
se contente de déclencher un appel de règle pour tous les fils du nœud courant.

<xsl:template match="* | /">


<xsl:apply-templates/>
</xsl:template>

Rappelons qu’un appel à xsl:apply-templates sans attribut select est équivalent à la sélec-
tion de tous les fils du nœud courant. Cette règle est utilisée pour tous les xsl:apply-templates qui
ne trouvent pas de règle à déclencher, y compris quand un mode est indiqué.
La seconde règle par défaut s’applique aux nœuds de texte et aux attributs. Elle insère le contenu textuel
de ces nœuds dans le document résultat.

<xsl:template match="text() | @*">


<xsl:value-of select="."/>
</xsl:template>

Enfin la dernière règle par défaut s’applique aux commentaires et aux instructions de traitement. Le
comportement par défaut est de les ignorer. La règle ne fait donc rien :

<xsl:template match="processing-instruction() | comment()"/>

Voici le programme XSLT minimal : il ne contient aucune règle, à part les règles par défaut qui sont
implicites.

Exemple 35 Defaut.xsl : Un programme XSLT minimal

<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

</xsl:stylesheet>

L’application de ce programme à notre document CoursXML.xml donne le résultat suivant :

Exemple 36 Defaut.xml : Le résultat des règles par défaut


124 CHAPTER 3. XSLT

<?xml version="1.0" encoding="UTF-8"?>

Publication XSLT

Amann
Rigaux

Introduction
Documents XML
Programmation XSLT

Les règles par défaut se sont donc appliquées. Elles ont permis de parcourir tous les éléments du
document, en produisant le contenu des nœuds de type Text. Notez que les attributs ne sont pas sélectionnés
par les expressions XPath dans les xsl:apply-templates des règles par défaut, et que leur contenu
n’apparaît donc pas.

3.2.3 Déclenchement de règles avec xsl:apply-templates


L’élément xsl:apply-templates désigne un ensemble de nœuds avec une expression XPath, et de-
mande l’application d’une règle pour chaque nœud. L’expression est toujours évaluée en prenant comme
nœud contexte le nœud pour lequel la règle contenant xsl:apply-templates a été instanciée.
Cet élément a deux attributs, tous deux optionnels :

1. select contient l’expression XPath désignant les nœuds à traiter ;


2. mode est la catégorie des règles à considérer.

L’expression de l’attribut select doit toujours ramener un ensemble de nœuds. Sa valeur par défaut
est child::node(), autrement dit tous les fils du nœud courant, quel que soit leur type, à l’exception
comme d’habitude des attributs (voir chapitre 2).

Instanciation des règles


Pour chaque nœud de l’ensemble désigné par l’expression XPath, le processeur va rechercher la règle à
appliquer. Il n’y a pas de raison à priori pour que la même règle soit appliquée à tous les nœuds. Prenons
l’exemple du programme suivant, appliqué à notre exemple CoursXML.xml.

Exemple 37 ApplyTemplates.xsl : Exemple de xsl:apply-template


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<xsl:apply-templates select="//ENSEIGNANTS"/>
</xsl:template>

<xsl:template match="ENSEIGNANTS">
<xsl:comment>
Application de la règle ENSEIGNANTS
</xsl:comment>
<xsl:apply-templates/>
3.2. LES RÈGLES XSLT 125

</xsl:template>

<xsl:template match="NOM">
<xsl:value-of select="position()"/> : Noeud NOM
</xsl:template>

<xsl:template match="text()">
<xsl:value-of select="position()"/> : Noeud de texte
</xsl:template>

<xsl:template match="comment()">
<xsl:value-of select="position()"/> : Noeud de commentaire
</xsl:template>
</xsl:stylesheet>

Il contient plusieurs règles. La première déclenche un xsl:apply-templates pour tous les nœuds
de type ENSEIGNANTS. Il n’existe qu’un nœud de ce type, et une règle associée qui est instanciée.
Cette règle produit un commentaire dans le document résultat avec l’instruction xsl:comment, puis
déclenche à son tour un xsl:apply-templates sans donner de cible, ce qui revient à sélectionner
tous les fils du nœud T ENSEIGNANTS U . On obtient le résultat suivant :

Exemple 38 ApplyTemplates.xml : Résultat du programme précédent


<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Application de la règle ENSEIGNANTS
-->
1 : Noeud de texte
2 : Noeud de commentaire
3 : Noeud de texte
4 : Noeud NOM
5 : Noeud de texte
6 : Noeud NOM
7 : Noeud de texte

Que s’est-il passé ? On peut reconnaître l’exécution de la seconde règle au commentaire. Ensuite le
processeur a pris tous les nœuds fils de T ENSEIGNANTS U et a cherché la règle à instancier. On peut
constater qu’il y a sept nœuds, dont quatre sont des nœuds de texte constitués uniquement d’espace. Nous
avons vu que ces nœuds étaient présents dans l’arbre DOM, et ils ne sont pas éliminés par le processeur
XSLT, à moins de le demander explicitement avec un xsl:strip-space : voir page 278.
En général ces nœuds sont traités « silencieusement » par le processeur : la règle par défaut pour les
nœuds de type Text s’applique, elle consiste à insérer le contenu dans le résultat, mais comme ce contenu
est constitué d’espaces, cela passe en général inaperçu.
Ici il existe une règle spécifique pour les nœuds textes, qui affiche notamment leur position. C’est
cette règle que le processeur XSLT a instanciée. On peut faire la même remarque pour le nœud de type
Comment et les éléments de type NOM pour lesquels une règle spécifique existe dans notre programme.

Contexte d’instanciation d’une règle


Un élément xsl:apply-templates est associé à une expression XPath qui sélectionne un ensemble
de nœuds. Comme nous l’avons vu dans le chapitre 2, pour chaque nœud de cet ensemble, on connaît la
position avec la fonction position() et le nombre de nœuds avec la fonction last().
Ces informations servent de contexte à l’instanciation des différentes règles. Pour chaque règle, il existe
un nœud courant, celui qui a déterminé la sélection de la règle. On peut de plus faire référence à la position
ou à la taille du contexte : en l’occurrence, cela nous a permis de numéroter les nœuds avec position().
126 CHAPTER 3. XSLT

3.2.4 Sélection des règles


Regardons maintenant comment une règle est sélectionnée quand plusieurs possibilités existent. Pour
chaque nœud sélectionné par un xsl:apply-templates, le processeur va regarder toutes les règles
du programme, et tester le pattern comme indiqué précédemment (voir page 119) pour déterminer si le
nœud satisfait la règle.
Quand aucune règle n’est trouvée, c’est la règle par défaut qui est instanciée. Si une seule règle est
trouvée, elle s’applique, ce qui signifie bien qu’elle est prioritaire par rapport à la règle par défaut. Cette
même notion de priorité se généralise à la situation où plusieurs règles sont candidates. Le processeur doit
alors choisir la règle à instancier en fonction d’un système de priorités.
Un autre facteur intervenant dans le choix d’une règle est le mode. Enfin nous avons vu (page 115) que
l’importation de programme définit une préséance (à ne pas confondre avec la priorité).
Nous décrivons ci-dessous le rôle des attributs priority et mode de l’élément xsl:template,
avant de récapituler les principes de choix d’une règle. Le document XML utilisé pour nos exemples dans
cette section est une liste de films (trois seulement).
Exemple 39 ListeFilms.xml : Une liste de films
<?xml version="1.0" encoding="ISO-8859-1"?>
<FILMS>
<FILM>
<TITRE>Vertigo</TITRE>
<ANNEE>1958</ANNEE><GENRE>Drame</GENRE>
<MES>Alfred Hitchcock</MES>
<RESUME>Scottie Ferguson, ancien inspecteur de police,
est sujet au vertige depuis qu’il a vu mourir son
collègue. Elster, son ami, le charge de surveiller
sa femme, Madeleine, ayant des tendances
suicidaires. Amoureux de la jeune femme
Scottie ne remarque pas le piège qui se trame autour
de lui et dont il va être la victime...
</RESUME>
</FILM>
<FILM>
<TITRE>Alien</TITRE>
<ANNEE>1979</ANNEE><GENRE>Science-fiction</GENRE>
<MES>Ridley Scott</MES>
<RESUME>Près d’un vaisseau spatial échoué sur une
lointaine planète, des Terriens en mission découvrent
de bien étranges "oeufs". Ils en ramènent un à bord,
ignorant qu’ils viennent d’introduire parmi
eux un huitième passager particulièrement
féroce et meurtrier.
</RESUME>
</FILM>
<FILM>
<TITRE>Titanic</TITRE>
<ANNEE>1997</ANNEE><GENRE>Drame</GENRE>
<MES>James Cameron</MES>
<RESUME>Conduite par Brock Lovett, une expédition
américaine fouillant l’épave du Titanic remonte à la
surface le croquis d’une femme nue. Alertée par les
médias la dame en question, Rose DeWitt
Bukater, aujourd’hui centenaire, rejoint les lieux du
naufrage, d’où elle entreprend de conter le
récit de son fascinant, étrange et tragique voyage...
</RESUME>
</FILM>
</FILMS>
3.2. LES RÈGLES XSLT 127

Priorités
La priorité d’une règle peut être soit indiquée explicitement avec l’attribut priority, soit calculée im-
plicitement par le processeur.
Prenons tout d’abord le cas où on indique explicitement une priorité. Supposons que l’on veuille
recopier tout le document ListeFilms.xml, à l’exception du résumé des films. On peut envisager de définir
une règle pour tous les types de nœuds, en recopiant leur contenu, balises comprises, sauf dans le cas des
éléments de types RESUME pour lesquels on ne fait rien.
Une solution plus simple et plus générale consiste à utiliser l’instruction xsl:copy qui recopie un
nœud du document source vers le document résultat. Dans notre cas xsl:copy doit être utilisé pour tous
les nœuds, sauf pour T RESUME U . Deux règles suffisent :
S une règle pour les éléments de type RESUME, qui ne fait rien ;
S une règle pour tous les nœuds qui effectue la copie du nœud pour lequel elle est instanciée, et qui
déclenche un xsl:apply-templates pour les fils de ce nœud.

Ces deux règles seront sélectionnées pour un nœud de type RESUME. Afin d’indiquer que la première
est prioritaire, il suffit de donner à la seconde une priorité faible, par exemple -1. Voici le programme XSLT
qui copie tous les films sauf leur résumé.

Exemple 40 Priority.xsl : Utilisation de l’attribut priority


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="RESUME"/>

<xsl:template match="@*|node()" priority="-1">


<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

La troisième règle avec l’attribut match="@*|node()" et avec la priorité -1 s’applique à tous


les types de nœuds. Elle commence par copier le nœud courant, puis sélectionne avec xsl:apply-
templates tous ses fils, y compris les attributs. Pour chacun de ses fils la même règle s’applique récur-
sivement, jusqu’à ce que la totalité du document soit parcourue et recopiée.
Les éléments T RESUME U constituent la seule exception : la règle appelée en priorité alors est celle qui
est spécifique à ce type d’élément, et elle ne produit aucun résultat. On obtient donc le document suivant :

Exemple 41 Priority.xml : Résultat du programme Priority.xsl


<?xml version="1.0" encoding="ISO-8859-1"?>
<FILMS>
<FILM>
<TITRE>Vertigo</TITRE>
<ANNEE>1958</ANNEE><GENRE>Drame</GENRE>
<MES>Alfred Hitchcock</MES>
128 CHAPTER 3. XSLT

</FILM>
<FILM>
<TITRE>Alien</TITRE>
<ANNEE>1979</ANNEE><GENRE>Science-fiction</GENRE>
<MES>Ridley Scott</MES>

</FILM>
<FILM>
<TITRE>Titanic</TITRE>
<ANNEE>1997</ANNEE><GENRE>Drame</GENRE>
<MES>James Cameron</MES>

</FILM>
</FILMS>

Quand une priorité explicite n’est pas indiquée, le système en calcule une en se basant sur le pattern de
l’attribut match :

1. Tous les patterns constitués d’une seule étape XPath, avec un nom d’élément ou d’attribut et sans
prédicat ont une priorité égale à 0.
Exemple : FILM, @CODE.

2. Le pattern processing-instruction(’nom’) a lui aussi une priorité égale à 0.

3. Tous les patterns constitués d’une seule étape XPath, avec un nom d’élément ou d’attribut égal à
« * » et un espace de nom ont une priorité égale à -0,25.
Exemple : xbook:*.

4. Les filtres sans espace de nom et autres qu’un nom d’élément ou d’attribut ont une priorité égale à
-0,5.
Exemple : node(), processing-instruction(), *

Enfin tous les patterns qui n’appartiennent pas à une des catégories ci-dessus ont une priorité égale à
0,5. C’est le cas par exemple des patterns avec prédicat, ou des patterns constitués de plusieurs étapes.
Il reste un cas à considérer, celui d’un pattern constitué d’une union avec l’opérateur « | ». Par exemple :

<xsl:template match="SUJET|node()">
corps de la règle
</xsl:template>

Dans ce cas le processeur constitue simplement deux règles indépendantes, et calcule la priorité pour
chacune. On se retrouve donc avec :

<xsl:template match="SUJET">
corps de la règle
</xsl:template>
<xsl:template match="node()">
corps de la règle
</xsl:template>

La première règle a une priorité égale à 0, la seconde une priorité égale à -0,5.
Si on reprend l’exemple du programme Priority.xsl, page 127, on s’aperçoit maintenant qu’il était
inutile de donner une priorité puisque celles déterminées par défaut sont les suivantes :
S RESUME a une priorité de 0 ;
3.2. LES RÈGLES XSLT 129

S la dernière règle se divise en deux :


– @* a une priorité de -0,5 ;
– node() a une priorité de -0,5 ;

Donc la dernière règle est moins prioritaire, ce qui correspond à l’intuition qu’elle est moins « spécifique »,
autrement dit qu’elle s’applique à une plus grande variété de nœuds. C’est la même intuition qui mène à
affecter une priorité plus grande à un pattern comme FILM/TITRE (priorité 0,5) qu’au pattern TITRE
(priorité 0).

Modes
Les modes constituent la dernière manière de guider le processeur dans le choix d’une règle. L’attribut
mode est optionnel : en son absence la règle sera concernée par tout xsl:apply-templates qui
lui non plus n’utilise pas son attribut mode. Sinon le mode de la règle et le mode de xsl:apply-
templates doivent coïncider.
Les modes sont principalement utiles quand on souhaite placer la même information issue du document
source en plusieurs endroits du document résultat. Nous allons prendre un exemple qui suffira à illustrer
l’idée. Supposons que l’on veuille créer un document HTML avec une présentation de tous les films
présents dans ListeFilms.xml (voir page 126). La page HTML affichée dans le navigateur aura une taille
respectable. Si on veut consulter un film particulier, il faudra faire défiler la page dans la fenêtre.
Pour faciliter la tâche de l’utilisateur, on peut introduire une liste d’ancres HTML au début de la page.
La balise T A U peut être utilisée pour définir une position interne à un document en plaçant des « marques ».
Par exemple :

<a name=’Alien’/>

définit une position de nom Alien. On peut alors utiliser une ancre donnant directement accès à cette
position :

<a href=’#Alien’>Lien vers le film Alien</A>

Le programme XSLT qui suit effectue deux passages sur les nœuds de type FILM, avec deux rè-
gles utilisant le même pattern mais deux modes différents. Au cours du premier passage (règle avec
mode=’Ancres) on crée un tableau HTML avec une seule ligne contenant une ancre pour chaque film.
Le second passage crée une représentation HTML complète de chaque film. Les règles sont appelées avec
deux xsl:apply-templates, avec les modes correspondant.

<xsl:apply-templates select="FILM" mode ="Ancres"/>


<xsl:apply-templates select="FILM"/>

Voici le programme complet :

Exemple 42 Mode.xsl : Utilisation de l’attribut mode


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="html" encoding="ISO-8859-1"/>

<xsl:template match="FILMS">
<html>
<head><title>Liste des films</title></head>
<body bgcolor="white">
<center><table>
130 CHAPTER 3. XSLT

<xsl:apply-templates select="FILM"
mode ="Ancres"/>
</table></center>
<xsl:apply-templates select="FILM"/>
</body>
</html>
</xsl:template>

<xsl:template match="FILM" mode="Ancres">


<td><a href="#{TITRE}">
<xsl:value-of select="TITRE"/>
</a></td>
</xsl:template>

<xsl:template match="FILM">
<a name="{TITRE}"/>
<h1><xsl:value-of select="TITRE"/></h1>
<b><xsl:value-of select="TITRE"/>,</b>
<xsl:value-of select="GENRE"/>
<br/>
<b>Réalisateur</b> : <xsl:value-of select="MES"/>
<p>
<b>Résumé</b> : <xsl:value-of select="RESUME"/>
</p>
</xsl:template>

</xsl:stylesheet>

Notez la possibilité d’introduire des expressions XPath pour calculer la valeur de l’attribut d’un élément
littéral, comme dans :

<a name="{TITRE}"/>

Ce mécanisme est décrit dans le chapitre qui suit, page ?? (voir également dans la référence XSLT,
page 258). Le résultat de la transformation (ou plus exactement sa présentation avec Netscape) est donné
dans la figure 3.3. En cliquant sur les ancres placées au début du document, on se positionne directement
sur le film correspondant.

Algorithme de sélection d’une règle


Voici, en résumé, comment le processeur XSLT choisit une règle à instancier pour un nœud sélectionné par
xsl:apply-templates. Au départ, la liste des règles candidates est constituée de toutes celles qui ont
un attribut match.

1. On restreint la liste à toutes les règles qui ont le même mode que l’élément xsl:apply-templates,
ou pas d’attribut mode si xsl:apply-templates lui-même n’en a pas.

2. On teste le pattern de l’attribut match pour déterminer si le nœud satisfait la règle.

3. Si on a trouvé plusieurs règles, on ne garde que celle(s) qui a (ont) la plus grande préséance d’importation
(voir page 115).

4. S’il reste encore plusieurs règles, on prend celle qui a la plus grande priorité.

Si cet algorithme ne permet pas de départager deux règles, le processeur XSLT peut s’arrêter ou en
choisir une (en principe la dernière dans l’ordre du programme). Il y a clairement dans ce cas un prob-
lème de conception du programme. Si, au contraire, aucune règle n’est trouvée, alors la règle par défaut
s’applique (voir page 123).
3.2. LES RÈGLES XSLT 131

Figure 3.3: Affichage du résultat avec Netscape

3.2.5 Appel de règle avec xsl:call-template


Quand une règle utilise l’attribut name au lieu de l’attribut match, on peut l’instancier explicitement avec
un xsl:call-template. L’utilisation de xsl:call-template s’apparente aux fonctions dans un
langage de programmation classique. Comme les fonctions, la règle appelée doit permettre de factoriser
des instructions utilisées en plusieurs endroits du programme.
Reprenons l’exemple affichant les nœuds du document CoursXML.xml en les numérotant. Le pro-
gramme ApplyTemplates.xml (voir page 125) contenait une règle pour chaque type de nœud rencontré, et
toutes ces règles produisaient à peu près le même résultat : la position du nœud courant, et un texte.
Le programme ci-dessous remplace le corps de ces règles par un appel xsl:call-template à une
règle nommée Afficher qui se charge de produire le résultat.

Exemple 43 CallTemplate.xsl : Exemple de xsl:call-template


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<xsl:apply-templates select="//ENSEIGNANTS"/>
</xsl:template>

<xsl:template match="ENSEIGNANTS">
<xsl:comment>
Application de la règle ENSEIGNANTS
</xsl:comment>
<xsl:apply-templates/>
</xsl:template>
132 CHAPTER 3. XSLT

<xsl:template name="Afficher">
<xsl:value-of select="position()"/> : <xsl:value-of select="."/>
</xsl:template>

<xsl:template match="NOM">
<xsl:call-template name="Afficher"/>
</xsl:template>

<xsl:template match="text()">
<xsl:call-template name="Afficher"/>
</xsl:template>

<xsl:template match="comment()">
<xsl:call-template name="Afficher"/>
</xsl:template>

</xsl:stylesheet>

L’amélioration n’est pas encore complète, et nous verrons qu’il est possible de faire mieux en utilisant
xsl:for-each ou un passage de paramètre. Le progrès notable est qu’il devient maintenant possible
de modifier l’ensemble de la sortie du programme en ne touchant qu’au corps de la règle Afficher. Le
résultat du programme est donné ci-dessous.

Exemple 44 CallTemplate.xml : Résultat du programme précédent


<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Application de la règle ENSEIGNANTS -->
1 :
2 : Enseignant responsable
3 :
4 : Amann
5 :
6 : Rigaux
7 :

Il faut souligner qu’un appel avec xsl:call-template ne change pas le contexte : le nœud courant
(et donc son contenu textuel), sa position et la taille du contexte restent connus dans le corps de la règle
Afficher.
La comparaison entre xsl:call-template et un appel de fonction reste limitée. En particulier,
dans ce que nous avons vu jusqu’ici,
S une instanciation de règle ne « renvoie » pas de valeur ;
S une instanciation de règle ne prend pas d’argument autre que le nœud auquel elle s’applique ;

Nous verrons dans la section consacrée aux variables, page 138, comment stocker dans une structure
temporaire le texte produit par une règle au lieu de l’insérer directement dans le résultat.
En ce qui concerne la deuxième limitation, elle est en partie levée par la possibilité de passer des
paramètres aux règles.

3.2.6 Paramètres
L’exemple de xsl:call-template que nous avons donné précédemment offrait assez peu d’intérêt
puisqu’il n’était pas possible de varier le texte produit par Afficher en fonction du type de nœud. Nous
allons améliorer la règle en lui passant en paramètre le texte à afficher après la position du nœud courant.
Le passage de paramètres s’effectue en deux étapes. Tout d’abord on indique au niveau de la définition
de la règle, avec des éléments xsl:param, le nom du paramètre et sa valeur par défaut. La syntaxe est
3.2. LES RÈGLES XSLT 133

T xsl:param name=nom select=expression U


L’attribut nom est le nom du paramètre, et expression (optionnel) est une expression XPath qui,
convertie en chaîne de caractères, donne la valeur par défaut du paramètre.
Voici la nouvelle version de la règle Afficher, avec un paramètre nommé texte ayant pour valeur
par défaut string(inconnu).

<xsl:template name="Afficher">
<xsl:param name="texte" select="string(inconnu)"/>
<xsl:value-of select="position()"/> :
<xsl:value-of select="$texte"/>
</xsl:template>

Remarque : Attention aux chaînes de caractères constantes dans XPath. Si on avait mis :
<xsl:param name="texte" select="inconnu"/>
le processeur XSLT aurait évalué la valeur par défaut en recherchant un élément T inconnu U fils de
l’élément courant. La fonction string() lève l’ambiguïté. Une autre possibilité est d’encadrer la chaîne par
des apostrophes simples :
<xsl:param name="texte" select=" ’inconnu’ "/>
Bien entendu on peut inverser les guillemets et les apostrophes simples.

Maintenant on peut, avant d’appeler la règle, définir les paramètres avec xsl:with-param. Voici
par exemple l’appel à Afficher en donnant au préalable au paramètre la valeur « texte vide ».

<xsl:template match="text()">
<xsl:call-template name="Afficher">
<xsl:with-param name="texte"
select="string(’texte vide’)"/>
</xsl:call-template>
</xsl:template>

Le positionnement de xsl:with-param suit des règles précises :

1. il peut apparaître dans le contenu de l’élément xsl:call-template, comme ci-dessus ; c’est


d’ailleurs le seul contenu possible pour xsl:call-template ;
2. on peut aussi passer des paramètres à xsl:apply-templates, en les plaçant immédiatement
après la balise ouvrante de cet élément.

Le passage des paramètres avec XSLT est d’une grande souplesse. On peut passer à une règle des
paramètres qu’elle n’attend pas, ou au contraire ne pas lui passer de paramètre. Dans le premier cas le
paramètre est tout simplement ignoré. Dans le second cas la règle prend en compte la valeur par défaut du
paramètre, si cette valeur existe.
Il est possible d’utiliser xsl:param comme un élément de premier niveau. Dans ce cas, comme il
n’y a pas eu de déclenchement de règle avec xsl:with-param pour affecter une valeur au paramètre,
c’est au processeur de déterminer quelle est la valeur du paramètre. Il existe plusieurs possibilités, dont les
deux suivantes :

1. quand le processeur est invoqué depuis la ligne de commande, une option permet en général de définir
le paramètre : c’est par exemple l’option -PARAM avec le processeur XALAN (voir l’annexe A,
page 246) ;
2. quand le processeur est intégré à un serveur web (cas de Cocoon), les paramètres sont ceux du
protocole HTTP (variables GET ou POST).
134 CHAPTER 3. XSLT

3.3 Instructions de contrôle


Jusqu’à présent nous avons surtout considéré XSLT comme un langage permettant de « déclarer » des
actions à exécuter en fonction de certains événements (la rencontre d’un nœud dans le document source).
Ce mode de programmation est bien adapté au traitement d’une structure arborescente, et de d’autant plus
que ce traitement est orienté vers la production d’un autre document.
Certaines manipulations courantes en programmation (tests, boucles, utilisation de variables) seraient
cependant impossibles, ou très laborieuses si on devait se restreindre à l’utilisation des règles. XSLT
propose les structures classiques de test, d’itération et, dans une certaine mesure, d’utilisation de variables,
avec des particularités importantes. La plus notable concerne les variables : d’une part il n’est pas possible
de les modifier (il aurait peut-être été plus judicieux de parler de « constante »), et d’autre part une variable
est soit locale à une règle, et inconnue alors des autres règles, soit globale au programme et connue alors
de toutes les règles.
En pratique cela signifie que beaucoup de pratiques habituelles en programmation sont impossibles.
Par exemple :

1. on ne peut pas construire une boucle sur une variable de contrôle incrémentée à chaque étape ;
2. on ne peut pas affecter une valeur à une variable dans une règle, et utiliser cette variable dans une
autre règle sans la passer comme paramètre.

La dernière propriété est importante : elle implique que les règles sont indépendantes, et que l’ordre
dans le programme aussi bien que l’ordre d’exécution ne sont pas important. Cela laisse au programmeur
la possibilité de concevoir son programme par blocs indépendants, et cela laisse surtout au processeur la
possibilité d’optimiser l’ordre d’exécution des règles, voire de les exécuter en parallèle.
XSLT n’est pas nécessairement un langage que l’on doit utiliser pour une programmation « classique »
à base de boucles, tests et appels de fonctions intensifs. Ce style de programmation est possible, mais
avec une syntaxe qui peut paraître lourde, et l’utilisation de mécanisme assez éloignés du mode habituel de
raisonnement.
Nous présentons maintenant les éléments de XSLT correspondants aux tests, boucles et variables en
nous limitant à des cas simples. La section se conclut sur un exemple plus élaboré de construction d’un
programme XSLT.

3.3.1 Tests : xsl:if et xsl:choose


L’instruction de test la plus simple est xsl:if. L’élément a un attribut, test, dont la valeur doit être
une expression XPath. Cette expression est évaluée, puis convertie en booléen. Le contenu de l’élément
xsl:if est instancié si l’évaluation donne true.
L’exemple suivant montre l’utilisation de xsl:if pour ne garder dans le document ListeFilms.xml
(voir page 126) que les films qui sont parus avant 1970.
Exemple 45 If.xsl : Utilisation de xsl:if
<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="FILMS">
<xsl:apply-templates select="FILM"/>
</xsl:template>

<xsl:template match="FILM">
<xsl:if test="ANNEE &lt; 1970">
<xsl:copy-of select="."/>
3.3. INSTRUCTIONS DE CONTRÔLE 135

</xsl:if>
</xsl:template>

</xsl:stylesheet>

Ce programme utilise une instruction xsl:copy-of qui copie le nœud courant ainsi que tous ses
descendants (copie en profondeur) dans le document résultat. Noter que l’opérateur « T » ne peut être
utilisé directement dans le test et doit être remplacé par une référence à l’entité prédéfinie &lt;.
Il n’y a pas de else dans XSLT. S’il est nécessaire d’utiliser une instruction de branchement entre
plusieurs choix, on peut utiliser xsl:choose. La structure s’apparente à celle du switch dans les
langages dérivés du C (C++, Java, ...), avec deux éléments complémentaires :
S xsl:when est semblable à xsl:if, et permet d’exprimer un des choix ;
S xsl:otherwise est le choix par défaut, aucun des xsl:when n’a été instancié.

La structure du xsl:choose est donnée ci-dessous. Il doit y avoir au moins un xsl:when, mais
xsl:otherwise est optionnel.

<xsl:choose>
<xsl:when test=’expression1’>
Corps de règle 1
</xsl:when>
<xsl:when test=’expression2’>
Corps de règle 2
</xsl:when>
...
<xsl:otherwise>
Corps de règle par défaut
</xsl:otherwise>
</xsl:choose>

Le processeur évalue successivement les expressions des xsl:when, et instancie le premier pour
lequel cette évaluation donne true. Tout le reste est alors ignoré. L’ordre des xsl:when est donc
important, surtout si les choix ne sont pas exclusifs.
Le programme suivant classe (un peu arbitrairement...) les films en deux catégories : ceux qui sont
parus avant 1960 sont considérés comme anciens, les autres comme récents. Si on n’est ni dans un cas ni
dans l’autre, un message interrogatif est produit.

Exemple 46 Choose.xsl : Utilisation de xsl:choose


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="FILMS">
<xsl:apply-templates select="FILM"/>
</xsl:template>

<xsl:template match="FILM">
<xsl:choose>
<xsl:when test="ANNEE &lt; 1960">
"<xsl:value-of select="TITRE"/>" est ancien
</xsl:when>
<xsl:when test="ANNEE &gt;= 1960">
136 CHAPTER 3. XSLT

"<xsl:value-of select="TITRE"/>" est récent


</xsl:when>
<xsl:otherwise>
De quand date "<xsl:value-of select="TITRE"/>" ?
</xsl:otherwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet>

3.3.2 Boucles : xsl:for-each


L’instruction xsl:for-each est la seule structure explicite d’itération dans XSLT (l’autre possibilité
étant d’appeler récursivement une règle nommée, comme nous le verrions plus loin). Le while n’existe
pas puisqu’il suppose la possibilité de modifier, dans le corps de la boucle, la condition qui détermine
l’arrêt. Or, comme nous l’avons signalé, il n’existe pas dans XSLT de « variable » au sens courant du terme
(nom auquel on peut affecter une valeur). Dans ces conditions le while n’apporterait rien de plus que
xsl:for-each.
L’itération s’effectue toujours sur un ensemble de nœuds constitué par l’expression XPath de l’attribut
select. Elle consiste à prendre successivement comme nœud courant chaque nœud de l’ensemble, et à
instancier le contenu de l’élément xsl:for-each en prenant pour contexte :
1. ce nœud courant ;
2. la taille de l’ensemble (fonction last()) ;
3. la position du nœud courant dans l’ensemble (fonction position()).
Il s’agit des trois informations habituelles définissant un contexte XPath. Il faut bien noter que ce
contexte est local à xsl:for-each au sein d’une règle, et que le nœud courant redevient celui pour
lequel la règle a été instanciée dès que la boucle est terminée.
Prenons l’exemple suivant, basé sur le document CoursXML.xml (page 110). On veut parcourir toutes
les séances de cours, afficher pour chacune son numéro, le nombre total de séances et l’intitulé de la séance.
Le programme est basé sur xsl:for-each4 :

Exemple 47 ForEach.xsl : Utilisation de xsl:for-each


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<PROGRAMME>
<xsl:apply-templates select="//PROGRAMME"/>
</PROGRAMME>
</xsl:template>

<xsl:template match="PROGRAMME">
Programme <xsl:value-of
select="concat(position(), ’/’, last())"/> :

<SEANCES>
<xsl:for-each select="SEANCE">
Séance <xsl:value-of
4 La fonction concat() construit une chaîne de caractères en concaténant ses arguments.
3.3. INSTRUCTIONS DE CONTRÔLE 137

select="concat(position(), ’/’, last())"/> :


<xsl:value-of select="."/>
</xsl:for-each>
</SEANCES>

Valable pour l’année <xsl:value-of select="ANNEE"/>


</xsl:template>

</xsl:stylesheet>

On peut noter tout de suite qu’il aurait été possible d’obtenir exactement la même chose avec xsl:apply-
templates et une règle dédiée aux éléments de type SEANCE. La différence entre les deux approches
est essentiellement une question de style. D’un côté on peut considérer que le code est plus clair avec
xsl:for-each, et qu’il sera probablement plus efficace puisqu’il n’est pas nécessaire de recherche la
règle à instancier.
D’un autre côté on ne peut pas réutiliser une règle indépendante pour SEANCE. Un programme qui
n’utiliserait que xsl:for-each se priverait de quelques-uns des avantages de XSLT : sa relative déclar-
ativité (c’est le processeur qui cherche la règle à appliquer) et la réutilisabilité des règles dans des contextes
différents.
Voici le résultat du programme ForEach.xsl.

Exemple 48 ForEach.xml : Résultat de ForEach.xsl


<?xml version="1.0" encoding="ISO-8859-1"?>
<PROGRAMME>
Programme 1/1 :

<SEANCES>
Séance 1/2 : Documents XML
Séance 2/2 : Programmation XSLT
</SEANCES>

Valable pour l’année 2002


</PROGRAMME>

L’élément xsl:for-each est inclus dans le corps d’une règle qui a été instanciée pour le nœud
T PROGRAMME U du document. Ce nœud est donc le nœud courant de la règle. De plus il fait partie
d’un contexte constitué par l’expression XPath « //PROGRAMME » du xsl:apply-templates. Ce
contexte comprend tous les nœuds de type PROGRAMME du document. Il n’en existe qu’un, ce qui explique
que le fragment suivant :
Programme <xsl:value-of
select="concat(position(), ’/’, last())"/> :
donne le résultat
Programme 1/1
On passe ensuite au xsl:for-each qui instancie, pour chaque séance, le contenu suivant :

<xsl:value-of select="concat(position(), ’/’, last())"/> :


<xsl:value-of select="."/>

Ce contenu illustre bien le changement de nœud courant et de contexte effectué par xsl:for-each.
Le contexte est maintenant l’ensemble des nœuds T SEANCE U fils de T PROGRAMME U (il y en a deux), et
le nœud courant est, tour à tour, chacune de ces séances. On obtient donc le résultat :
Séance 1/2 : Documents XML
Séance 2/2 : Programmation XSLT
138 CHAPTER 3. XSLT

Après xsl:for-each, le contexte redevient celui de la règle, et le nœud courant est à nouveau
T PROGRAMME U . Le fragment :
Valable pour l’année <xsl:value-of select="ANNEE"/>
insère donc logiquement l’année 2002, contenu textuel du seul fils de T PROGRAMME U de type ANNEE.

3.3.3 Variables : xsl:variable


Une variable XSLT est un nom (donné par l’attribut name) associée à une valeur. Cette valeur peut être
définie de deux manières :
S par une expression XPath donnée dans l’attribut select ;
S par le contenu de l’élément.
Dans le premier cas le type de la variable est l’un des quatre types XPath (booléens, numériques,
chaînes et node-set). Dans le second cas la variable appartient à un type spécifique à XSLT, dit result tree
fragment : dans la version 1.0 de XSLT, une valeur de ce type correspond à une chaîne de caractères qui
représente la version sérialisé du fragment calculé. Ceci signifie surtout qu’il n’est pas possible d’extraire
des valeurs d’un fragment résultat en utilisant des axes XPath.
Voici quelques exemples de définition de variables :
S T xsl:variable name=’var1’ select=’12’/ U : définit une variable var1 avec une valeur
12 ;
S T xsl:variable name=’var2’ select=’/COURS/ENSEIGNANTS’/ U : définit une vari-
able var2 qui prend pour valeur les nœuds de type ENSEIGNANTS, petits-fils de la racine du doc-
ument ;
S Enfin la variable suivante est définie par son contenu :

<xsl:variable name=’var3’>
Ceci est un <mot-cle>contenu</mot-cle> de variable
</xsl:variable>

La valeur de la variable var2 est un ensemble de nœuds (node-set) rassemblé sous forme d’un
arbre temporaire qui peut être utilisée comme racine dans n’importe quelle expression XPath. Par ex-
emple, l’instruction <xsl:apply-templates select="$var2/*" transforme chacun des nœuds
dans cet ensemble.
Dans le dernier cas la valeur de var3 doit être assimilée à une chaîne de caractères, et pas à un node-
set. Il n’est pas permis par exemple d’écrire une expression comme $var3/mot-cle. Cette restriction
sur le traitement des fragments résultats a été supprimée dans le processeur Xalan et la version 1.1 (WD)
de XSLT.

Portée d’une variable


La portée d’une variable est la partie du programme dans lequel la variable est définie. On distingue deux
types de variables :
S Les variables globales sont définies par des éléments xsl:variable de premier niveau, fils de
l’élément T xsl:stylesheet U . Ces variables sont visibles dans tout le programme, même dans
des règles qui précèdent leur définition (rappelons que l’ordre des éléments de premier niveau n’est
pas significatif, sauf pour xsl:import).
S Les variables locales apparaissent dans un corps de règle. Une variable locale est visible dans
tous les frères droits (following-sibling) du nœud xsl:variable, ainsi que dans leurs
descendants.
3.3. INSTRUCTIONS DE CONTRÔLE 139

Une variable XSLT n’est pas modifiable et c’est donc une erreur que de définir deux xsl:variable
avec le même nom si leurs portées se chevauchent (la recommandation XSLT utilise le terme shadowing
pour ce phénomène) sauf – voici un mot qu’on entend souvent en étudiant la recommandation XSLT – si
S une des deux variables est une variable globale ;
S les deux variables sont globales mais n’ont pas la même préséance.
Les variables XSLT sont utiles, comme dans tout langage de programmation, pour stocker des valeurs
ou des résultats de calcul et éviter ainsi de répéter plusieurs fois les mêmes instructions. On peut aussi
s’en servir pour clarifier le code. Comme, en revanche, on ne peut pas affecter de nouvelles valeurs à une
variable, on ne peut pas les utiliser pour stocker des compteurs de boucles.
Une variable var peut être référencée après sa définition par $var, dans toute expression XPath. Il faut
bien souligner qu’il est possible de stocker dans une variable aussi bien des valeurs simples (un numérique
par exemple) que le résultat de l’exécution d’une ou plusieurs règles, ou d’appels à des xsl:call-
template. Tout ce qui est compris entre les balises ouvrante et fermante de xsl:variable constitue
la valeur de la variable et peut être arbitrairement complexe.
Voici deux premiers exemples simples d’utilisation de xsl:variable. Le premier reprend le pro-
gramme qui classait nos films en deux catégories. La seule modification est l’année qui est définie comme
une variable globale, ce qui permet de modifier la valeur en un seul endroit le jour venu.
Exemple 49 VarGlobale.xsl : Une variable globale
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:variable name="annee" select="1970"/>

<xsl:template match="FILMS">
<xsl:apply-templates select="FILM"/>
</xsl:template>

<xsl:template match="FILM">
<xsl:choose>
<xsl:when test="ANNEE &lt; $annee">
"<xsl:value-of select="TITRE"/>" est ancien
</xsl:when>
<xsl:when test="ANNEE &gt;= $annee">
"<xsl:value-of select="TITRE"/>" est récent
</xsl:when>
<xsl:otherwise>
De quand date "<xsl:value-of select="TITRE"/>" ?
</xsl:otherwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet>

Notez que l’on pourrait obtenir le même résultat en passant un paramètre à la règle. L’utilisation d’une
variable (globale) est plus générale qu’un paramètre puisqu’on peut l’utiliser dans plusieurs règles. Le
choix de l’un ou l’autre est donc surtout une question d’opportunité et de lisibilité du programme.
Le second exemple montre une variable locale utilisée pour stocker une phrase qui est ensuite réutilisée
plusieurs fois. Elle reprend le programme ForEach.xsl (voir page 136) affichant la liste des séances de
cours.
Exemple 50 VarLocale.xsl : Une variable locale
140 CHAPTER 3. XSLT

<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<PROGRAMME>
<xsl:apply-templates select="//PROGRAMME"/>
</PROGRAMME>
</xsl:template>

<xsl:template match="PROGRAMME">
Programme <xsl:value-of
select="concat(position(), ’/’, last())"/> :

<SEANCES>
<xsl:variable name="phrase">
(valable pour l’an <xsl:value-of select="ANNEE"/>)
</xsl:variable>

<xsl:for-each select="SEANCE">
Séance <xsl:value-of
select="concat(position(), ’/’, last())"/> :
<xsl:value-of select="concat(., $phrase)"/>
</xsl:for-each>
</SEANCES>

Valable pour l’année <xsl:value-of select="ANNEE"/>


</xsl:template>

</xsl:stylesheet>

La variable $phrase stocke, après évaluation de xsl:value-of, la chaîne de caractères :

(valable pour l’an 2002)

qui est ensuite réutilisée dans :

<xsl:value-of select="concat(., $phrase)"/>

La portée de la variable est limitée au contenu de l’élément T SEANCES U . Elle peut donc être référencée
dans le contenu du xsl:for-each qui est un frère droit, mais pas au-delà.
Il s’agit ici d’un exemple très simple d’une utilisation courante des variables : associer à un le résultat
d’un calcul. Les variables peuvent aussi être utilisées pour résoudre des problèmes plus complexes comme
des itérations par récursion sur des ensembles de nœuds (voir page 141).

3.3.4 Tri : xsl:sort


XSLT fournit un élément pour trier les nœuds sélectionnés par un xsl:apply-templates ou un
xsl:for-each. Par défaut, les nœuds sont triés sur leur position, et suit l’ordre du document pour
les forward-axes, ou l’ordre inverse pour les reverse-axes (voir page 103).
Le principal attribut de xsl:sort est select qui indique le critère (la clé) de tri. On peut indiquer
plusieurs xsl:sort successifs : le processeur effectue un premier tri avec la première clé, puis un second
tri sur les groupes qui n’ont pas été départagés par le premier tri, et ainsi de suite.
Voici un exemple de tri sur le document ListeFilms.xsl (page 126). On trie d’abord sur l’année de
parution du film, puis, pour les films parus la même année, sur le titre.
3.3. INSTRUCTIONS DE CONTRÔLE 141

Exemple 51 Sort.xsl : Exemple de tri


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="FILMS">
<FILMSTRIES>
<xsl:apply-templates select="FILM">
<xsl:sort select="ANNEE"/>
<xsl:sort select="TITRE"/>
</xsl:apply-templates>
</FILMSTRIES>
</xsl:template>

<xsl:template match="FILM">
<b>Année : </b> <xsl:value-of select="ANNEE"/>,
<xsl:value-of select="TITRE"/> réalisé
par <xsl:value-of select="MES"/>
</xsl:template>

</xsl:stylesheet>

On obtient le résultat suivant :


Exemple 52 Sort.xml : Résultat du tri
<?xml version="1.0" encoding="ISO-8859-1"?>
<FILMSTRIES>
<b>Année : </b>1958,
Vertigo réalisé par Alfred Hitchcock
<b>Année : </b>1979,
Alien réalisé par Ridley Scott
<b>Année : </b>1997,
Titanic réalisé par James Cameron
</FILMSTRIES>

L’expression XPath utilisée dans l’attribut select est évaluée en prenant successivement chaque
nœud de l’ensemble sélectionné par xsl:apply-templates comme nœud courant. Le tri est ensuite
effectué sur l’ensemble des valeurs obtenues. Dans l’exemple ci-dessus, chaque nœud est de type FILM,
et les critères de tri sont les fils T ANNEE U et T TITRE U de chaque film. On pourrait également utiliser
position().
Par défaut le processeur considère que le critère de tri est de type string, et les comparaisons se font
donc d’après l’ordre alphanumérique sur les chaînes de caractères (attention, dans ce cas « 10 » est plus
petit que « 2 » puisque la comparaison s’effectue de gauche à droite). On peut indiquer un attribut data-
type avec comme valeur number pour changer le mode de comparaison. Les quelques autres options de
xsl:sort sont présentées dans l’annexe B, page 277.

3.3.5 Itérations par récursion


Nous concluons cette présentation des instructions de contrôles de XSLT en présentant quelques techniques
avancées de programmation, et notamment l’exécution de boucles. Nous avons vu que la seule instruction
pour effectuer des boucles est xsl:for-each, et qu’elle est essentiellement destinée à parcourir un
ensemble de nœuds pour insérer du texte dans le document résultat.
En programmation « classique », on utilise couramment les boucles pour effectuer une tâche un nombre
fixé de fois, ou pour calculer une valeur. Il n’y a pas à priori de construction pour ce type de fonctionnalité
en XSLT :
142 CHAPTER 3. XSLT

1. boucle de 1 à b : xsl:for-each s’effectue autant de fois qu’il y a de nœuds dans l’ensemble à


traiter : on ne peut pas jouer sur ce nombre de nœuds puisque le document source n’est pas modifi-
able, et on ne peut pas se baser sur un compteur puisque les variables non plus ne sont pas modifi-
ables ;
2. calcul de valeur : typiquement on utilise une variable dans laquelle on stocke au fur et à mesure le
résultat du calcul ; pour les mêmes raisons que précédemment ça n’est pas possible avec XSLT.

Nous présentons ci-dessous deux techniques de programmation pour résoudre ces deux problèmes.
Elles s’appuient toutes deux sur un appel récursif à une règle nommée, et utilisent des variables XSLT.
Le premier exemple consiste à afficher un nombre fixé d’éléments contenus dans un node-set. On
va utiliser un paramètre représentant le numéro de l’élément courant à afficher, et passer ce paramètre à une
règle nommée AfficheElement en même temps que l’ensemble de nœuds. Cette règle procède alors
de la manière suivante :

1. si le nombre maximal à afficher est dépassé, elle ne fait rien ;


2. sinon elle affiche l’élément correspondant au numéro courant, et s’appelle récursivement en incré-
mentant ce numéro.

Voici la règle. Elle fonctionne pour tout ensemble de nœuds.


<xsl:template name="AfficheElement">
<xsl:param name="numero"/>
<xsl:param name="liste"/>
<xsl:param name="max"/>

<xsl:if test="$numero &lt;= $max">


Elément <xsl:value-of select="$numero"/> :
<xsl:value-of select="$liste[position()=$numero]"/>

<xsl:call-template name="AfficheElement">
<xsl:with-param name="numero" select="$numero + 1"/>
<xsl:with-param name="liste" select="$liste"/>
<xsl:with-param name="max" select="$max"/>
</xsl:call-template>
</xsl:if>

</xsl:template>
Il suffit de définir deux variables, $maxElements, et $liste, puis d’appeler cette règle en lui
passant les deux paramètres et un numéro initialisé à 1. Voici par exemple l’utilisation de cette règle pour
afficher deux films (le programme complet s’appelle BoucleFilms.xsl).

<xsl:template match="FILMS">

<xsl:variable name="maxFilms" select="2"/>


<xsl:variable name="listeFilms" select="/FILMS/FILM/TITRE"/>

<xsl:call-template name="AfficheElement">
<xsl:with-param name="numero" select="1"/>
<xsl:with-param name="liste" select="$listeFilms"/>
<xsl:with-param name="max" select="$maxFilms"/>
</xsl:call-template>

</xsl:template>
3.3. INSTRUCTIONS DE CONTRÔLE 143

Notez que la variable $listeFilms est un node-set avec tous les titres. Cette variable et $max-
Films sont locales à la règle, et doivent donc être passées en paramètre puisqu’elles ne sont pas visibles
dans la règle nommée AfficheElement.
Voici un deuxième exemple d’appel récursif qui consiste cette fois à effectuer un calcul en parcourant
une liste de nœuds. Pour simplifier la présentation, nous allons prendre l’exemple très simple d’une totali-
sation, bien qu’il existe une fonction prédéfinie (sum()) pour arriver au même résultat bien plus facilement.
Cet exemple doit donc surtout être considéré comme représentatif d’une technique générale.
Le document sur lequel nous allons travailler est une liste de films avec, pour chaque film, des notes
critiques.

Exemple 53 Notes.xml : Des notes sur les films


<?xml version="1.0" encoding="ISO-8859-1"?>
<FILMS>
<FILM>
<TITRE>Vertigo</TITRE>
<NOTES>
<NOTE>3</NOTE><NOTE>3</NOTE><NOTE>3</NOTE><NOTE>5</NOTE>
</NOTES>
</FILM>
<FILM>
<TITRE>Alien</TITRE>
<NOTES>
<NOTE>4</NOTE><NOTE>3</NOTE><NOTE>5</NOTE>
</NOTES>
</FILM>
<FILM>
<TITRE>Titanic</TITRE>
<NOTES>
<NOTE>2</NOTE><NOTE>2</NOTE><NOTE>4</NOTE><NOTE>1</NOTE>
</NOTES>
</FILM>
<FILM>
<TITRE>Sleepy Hollow</TITRE>
<NOTES>
<NOTE>2</NOTE><NOTE>4</NOTE><NOTE>4</NOTE>
</NOTES>
</FILM>
<FILM>
<TITRE>American Beauty</TITRE>
<NOTES>
<NOTE>5</NOTE><NOTE>4</NOTE><NOTE>4</NOTE>
</NOTES>
</FILM>
<FILM>
<TITRE>Impitoyable</TITRE>
<NOTES>
<NOTE>2</NOTE><NOTE>1</NOTE><NOTE>5</NOTE>
</NOTES>
</FILM>
</FILMS>

L’objectif est de calculer, pour chaque film, la moyenne des notes et de l’afficher dans un tableau
HTML. Pour cela on doit sélectionner, avec une expression XPath, la liste des notes pour chaque film. La
fonction count() va nous donner le nombre de notes, et on va parcourir la liste pour calculer le total des
notes. La division des deux nous donnera la moyenne.
Le principe à appliquer est celui d’un parcours récursif de la liste en additionnant, à chaque étape, le
premier élément de la liste avec la somme des éléments du reste de la liste. Le pseudo-code ci-dessous
144 CHAPTER 3. XSLT

montre le fonctionnement d’une telle fonction. On peut remarquer qu’il n’y a pas besoin de variable (et à
plus forte raison d’affectation).

fonction Somme (Liste l)


début
si (l n’est pas vide)
retourner l[1] + Somme (l[2..n])
sinon retourner 0
fin

Voyons comment réaliser cette fonction avec XSLT. On va, comme précédemment, utiliser un appel
récursif à une règle nommée. La différence principale est que cette fois l’appel doit « retourner » une
valeur, alors que dans notre premier exemple (programme BoucleFilms.xsl) la règle effectuait une tâche
habituelle d’insertion dans le document résultat.
La notion de « retour » de valeur n’existe pas en XSLT, mais on va utiliser à la place la possibilité de
stocker le fragment produit par une règle non pas dans le document résultat, mais dans une variable.
Voici la règle nommée. Elle suit de très près la structure de la fonction Somme() ci-dessus, avec beau-
coup plus de syntaxe, XSLT étant un langage assez bavard.

<xsl:template name="CalculTotal">
<xsl:param name="listeNotes"/>

<xsl:choose>
<xsl:when test="$listeNotes">
<xsl:variable name="note" select="$listeNotes[1]"/>

<xsl:variable name="autresNotes">
<xsl:call-template name="CalculTotal">
<xsl:with-param name="listeNotes"
select="$listeNotes[position() != 1]"/>
</xsl:call-template>
</xsl:variable>

<xsl:value-of select="$note + $autresNotes"/>


</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:template>

Dans le xsl:when, qui correspond au cas où la liste n’est pas vide, on crée une variable $note avec
la première note de la liste. Puis on crée une seconde variable qui va contenir le résultat de l’appel récursif
à la règle nommée CalculTotal, en lui passant le reste de la liste.
Cette règle contient un seul xsl:value-of qui insère dans le résultat le total des deux variables.
Cette insertion correspond au « retour » de cette règle, vue comme une fonction. Voici le programme
complet, le résultat étant donné dans la figure 3.4.

Exemple 54 BoucleNotes.xsl : Une boucle sur une liste


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="html" encoding="ISO-8859-1"/>

<xsl:template match="FILMS">
3.3. INSTRUCTIONS DE CONTRÔLE 145

<html>
<head><title>Statistiques</title></head>
<body bgcolor="white">
<center>
<h1>Moyenne des notes pour chaque film</h1>

<table border=’1’>
<xsl:apply-templates select="FILM"/>
</table>
</center>
</body>
</html>
</xsl:template>

<xsl:template match="FILM">
<xsl:variable name="total">
<xsl:call-template name="CalculTotal">
<xsl:with-param name="listeNotes"
select="NOTES/NOTE"/>
</xsl:call-template>
</xsl:variable>
<tr>
<td><b><xsl:value-of select="TITRE"/></b></td>
<td align="right">
<xsl:value-of select="$total div count(NOTES/NOTE)"/>
</td>
</tr>
</xsl:template>

<xsl:template name="CalculTotal">
<xsl:param name="listeNotes"/>

<xsl:choose>
<xsl:when test="$listeNotes">
<xsl:variable name="note" select="$listeNotes[1]"/>

<xsl:variable name="autresNotes">
<xsl:call-template name="CalculTotal">
<xsl:with-param name="listeNotes"
select="$listeNotes[position() != 1]"/>
</xsl:call-template>
</xsl:variable>

<xsl:value-of select="$note + $autresNotes"/>


</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet>

Cet exemple illustre la puissance de XSLT en tant que langage de programmation. Il reste que la
faiblesse du typage, combinée à une approche « fonctionnelle » de la programmation peuvent rapidement
rendre très laborieux le développement de programme XSLT effectuant des opérations complexes. Il faut
par exemple envisager de stocker des listes dans des chaînes de caractères avant de les traiter par des appels
récursifs. Ce type de programmation trouve rapidement ses limites en terme de maintenance et d’évolution.
Il est sans doute préférable de considérer avant tout XSLT (au moins pour la version 1.0) comme un langage
146 CHAPTER 3. XSLT

Figure 3.4: L’affichage du résultat avec Netscape

orienté vers la transformation de documents XML, et capable occasionnellement d’effectuer des tâches de
programmation classiques.

3.4 Évaluation d’un programme XSLT


Nous concluons ce chapitre en décrivant pas à pas l’évaluation d’un programme XSLT. L’objectif est de
récapituler une nouvelle fois les principaux concepts d’une transformation XSLT : nœud courant et nœud
contexte, instanciation de règle, production du résultat, etc.

Document
-

Element
COURS

Attr Element Element Element


CODE
TC234
ENSEIGNANTS SUJET PROGRAMME

Element Element Texte Element


NOM NOM - SEANCES
Publication XSLT

Texte Texte Element Element Element


- -
Rigaux SEANCE SEANCE ANNEE
Waller

Attr Texte Attr Texte Texte


ID - ID - -
2 Documents XML 3 Programmation XSLT 2002

Figure 3.5: Exemple de référence pour XSLT

Nous prenons l’exemple d’une transformation du document CoursXML.xml, page 110. La figure 3.5
illustre la représentation DOM de ce document. La transformation construit une page HTML. Voici le
3.4. ÉVALUATION D’UN PROGRAMME XSLT 147

programme.
Exemple 55 Recap.xsl : Récapitulatif de l’évaluation d’un programme XSLT
<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="html" encoding="ISO-8859-1"/>

<xsl:template match="/">
<html>
<head><title>
<xsl:value-of select="COURS/SUJET"/>
</title></head>
<body bgcolor="white">

<xsl:apply-templates/>

</body>
</html>
</xsl:template>

<xsl:template match="SUJET">
<h1><center><xsl:value-of select="."/></center></h1>
</xsl:template>

<xsl:template match="ENSEIGNANTS">
<h1>Enseignants</h1>
<ol>
<xsl:apply-templates select="NOM"/>
</ol>
</xsl:template>

<xsl:template match="PROGRAMME">
<h1>Programme</h1>
<ul>
<xsl:for-each select="SEANCE">
<xsl:call-template name="AfficheSeance"/>
</xsl:for-each>
</ul>
</xsl:template>

<xsl:template match="ENSEIGNANTS/NOM">
<li><xsl:value-of select="." /></li>
</xsl:template>

<xsl:template name="AfficheSeance">
<li> Séance <xsl:value-of select="concat (
position(), ’/’, last(), ’ : ’, .)"/>
</li>
</xsl:template>
</xsl:stylesheet>

Après l’analyse des deux documents, le processeur va commencer par créer le nœud racine du document
résultat (figure 3.6), et par se positionner sur la racine du document source qui devient le nœud courant.
De plus le processeur associe à chaque nœud courant une liste de nœud (le « contexte ») contenant le nœud
courant lui-même, avec une position donnée, et éventuellement d’autres nœuds.
148 CHAPTER 3. XSLT

Document
-

Figure 3.6: Début de l’évaluation

Prenant maintenant la liste des règles du programme, le processeur recherche celles qui sont applicables
au nœud racine du document, en appliquant l’algorithme présenté page 1265 .
La seule règle qui convient est la première. Elle est donc instanciée : son contenu est copié sous la
racine du document résultat, ce qui donne l’arbre provisoire de la figure 3.7.

Document
-

html

head body

title xsl:apply-templates

Attr
xsl:value-of select
COURS/SUJET

Figure 3.7: Après instanciation de la première règle

Cet arbre contient deux éléments dont l’espace de nom est xsl. Ils doivent donc être évalués par le
processeur et remplacés par le résultat obtenu. On voit bien dès ce stade que l’évaluation d’un programme
XSLT n’est pas un processus linéaire dans lequel les balises ouvrante et fermante des éléments sont pro-
duites séquentiellement. Un arbre est construit par instanciation de nœuds complets, et à ces nœuds sont
rattachés de nouveaux fils au fur et à mesure que les instructions XSLT restantes sont évaluées. Ici encore,
il vaut donc mieux raisonner, comme nous le faisons depuis le début de ce livre, sur une représentation
arborescente des documents que sur une version sérialisée avec balises.
Une particularité de ce type d’évaluation est que le processeur a le choix de la prochaine instruction
à évaluer. On voit bien sur la figure 3.7 que les deux instructions xsl:value-of et xsl:apply-
templates peuvent être évaluées séparément, dans un ordre quelconque, voire en parallèle. Il suffit que
le processeur conserve l’information sur le nœud courant et le contexte associé à chacune de ces instructions
pour pouvoir y revenir et les traiter à tout moment.
Si on choisit d’évaluer d’abord xsl:value-of, on obtient l’arbre temporaire de la figure 3.8. À partir
du nœud courant qui est la racine du document source, on a évalué l’expression XPath « /COURS/SUJET »,
et on a remplacé l’instruction XSLT par le résultat de cette évaluation, la chaîne « Programmation XSLT ».

Passons maintenant à l’instruction xsl:apply-templates. L’attribut select manque, donc


le processeur applique le choix par défaut qui consiste à sélectionner les fils du nœud courant, soit en
l’occurrence T COURS U , l’élément racine du document. C’est cet élément qui devient le nœud courant.
5 Il s’agit de l’algorithme de référence, mais bien entendu chaque processeur est libre d’implanter le sien pourvu que le résultat

soit le même.
3.4. ÉVALUATION D’UN PROGRAMME XSLT 149

Document
-

html

head body

title xsl:apply-templates

XSLT

Figure 3.8: Après évaluation de xsl:value-of

La recherche dans le programme d’une règle applicable à ce nœud échoue, donc le processeur choisit la
règle par défaut (voir page 123). Elle consiste à sélectionner les fils du nœud courant. On a donc maintenant
un ensemble de trois éléments, T SUJET U , T ENSEIGNANTS U et T PROGRAMME U .
Le processeur va prendre ces trois éléments tour à tour comme nœud courant, rechercher la règle pour
chacun, et l’instancier. Il existe trois règles distinctes dans le programme, ce qui donne l’arbre résultat
temporaire de la figure 3.9.

Document
-

html

head body

title h1 h1 h1

XSLT center ol ul

xsl:value-of xsl:apply-templates xsl:for-each

Attr Attr Attr


select select select xsl:call-template
. NOM SEANCE

Attr
name
AfficheSeance

Figure 3.9: Après évaluation de xsl:apply-templates

Le processeur continue à prendre dans l’arbre résultat en cours de constitution les éléments dont
l’espace de nom est xsl. Pour chacun de ces éléments il existe un nœud courant dans l’arbre source,
lui-même faisant partie d’un ensemble de nœuds. Pour l’élément xsl:value-of dans la figure 3.9 par
150 CHAPTER 3. XSLT

exemple, le nœud courant dans l’arbre source est T SUJET U , et l’ensemble de nœuds est constitué des
trois fils de T COURS U . À partir de la situation de la figure 3.9, le processeur va donc (en supposant que
les instructions sont traitées dans l’ordre du document) :
1. évaluer xsl:value-of, avec l’attribut select valant « . », le nœud courant étant T SUJET U : le
résultat est XSLT ;
2. évaluer l’expression NOM de l’attribut xsl:select du xsl:apply-templates, le nœud courant
étant T ENSEIGNANTS U : on obtient deux nœuds pour lesquels la seule règle qualifiée est celle dont
le pattern est « ENSEIGNANTS/NOM » ;
3. enfin l’expression SEANCE de l’attribut xsl:select du xsl:for-each est évaluée, ce qui
donne (le nœud courant étant T PROGRAMME U ) les deux éléments de type SEANCE du document
source.
La figure 3.10 montre la situation de l’arbre résultat intermédiaire après évaluation du xsl:for-
each. Il reste au processeur à évaluer deux appels xsl:call-template à la règle nommée Affich-
eSeance. En apparence ces deux appels sont identiques, mais ce qui les distingue (non représenté sur la
figure), c’est leur nœud courant.

Document
-

html

head body

title h1 h1 h1

XSLT center ol ul

XSLT li li xsl:call-template xsl:call-template

Attr Attr
Amann Rigaux name name
AfficheSeance AfficheSeance

Figure 3.10: Après évaluation du xsl:for-each

L’instruction xsl:for-each a pour effet de changer le nœud courant pour chaque instanciation de
son contenu (voir page 136). L’ensemble de nœuds, lui, est constitué par l’évaluation de l’expression du
xsl:for-each, et se trouve donc commun aux deux appels de règles.
Un appel à xsl:call-template ne change ni le nœud courant (une des deux séances), ni l’ensemble
des nœuds formant le contexte (les deux séances). L’instanciation de la règle nommée donnera donc le ré-
sultat final de la figure 3.11.

Il reste à sérialiser le document obtenu, ce qui donne le résultat ci-dessous6 .


6 Dans le cas d’un document HTML, certaines transformations peuvent intervenir, comme la transformation d’un c hr/ d en
c d
hr . Elles sont décrites dans le chapitre suivant.
3.4. ÉVALUATION D’UN PROGRAMME XSLT 151

Document
-

html

head body

title h1 h1 h1

XSLT center ol ul

XSLT li li li li

Séance 1/2 : Séance 2/2 :


Amann Rigaux
Documents XML Programmation XSLT

Figure 3.11: Le résultat final

Exemple 56 Recap.html : le document HTML sérialisé


<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Publication XSLT</title>
</head>
<body bgcolor="white">

<h1>
<center>Publication XSLT</center>
</h1>

<h1>Enseignants</h1>
<ol>
<li>Amann</li>
<li>Rigaux</li>
</ol>

<h1>Programme</h1>
<ul>
<li> S&eacute;ance 1/2 : Documents XML</li>
<li> S&eacute;ance 2/2 : Programmation XSLT</li>
</ul>

</body>
</html>

Cet exemple a montré, sur un cas simple mais représentatif, les principales caractéristiques de l’évaluation
d’un programme XSLT. Récapitulons les points les plus importants :

1. le processeur construit un arbre, et pas une version sérialisée du document ;


2. chaque instruction est placée dans le document résultat, puis évaluée ; elle reste toujours asso-
ciée à un nœud courant dans le document source, lui-même faisant partie d’un ensemble de de
152 CHAPTER 3. XSLT

nœuds : ces deux informations constituent le contexte d’évaluation des expressions XPath placées
dans l’instruction ;
3. on ne peut pas préjuger de l’ordre d’exécution des instructions d’un programme XSLT : le langage
lui-même est conçu pour que le résultat ne dépende pas de cet ordre.
Chapter 4

Production de documents XML

Sommaire
4.1 Définition de Types de Documents : DTD . . . . . . . . . . . . . . . . . . . . . . . . 154
4.1.1 Pourquoi définir une DTD ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
4.1.2 Entités . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
4.1.3 Éléments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
4.1.4 Attributs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
4.1.5 DTD et XML Schéma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
4.2 Site Web: HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
4.2.1 HTML et XHTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
4.2.2 DTD XHTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
4.2.3 Génération de pages HTML: xsl:output . . . . . . . . . . . . . . . . . . . 170
4.2.4 Transformation d’une page XML . . . . . . . . . . . . . . . . . . . . . . . . . 171
4.2.5 Création de liens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
4.2.6 XML/XSLT: une solution du problème des liens cassés . . . . . . . . . . . . . 175
4.2.7 Intégration de pages XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
4.3 Présentations multimédia: SMIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
4.3.1 SMIL par un exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
4.3.2 DTD SMIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
4.3.3 Génération de présentations SMIL . . . . . . . . . . . . . . . . . . . . . . . . 187
4.4 Traitement de texte dans XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
4.4.1 xsl:preserve-space et xsl:strip-space . . . . . . . . . . . . . . . 195
4.4.2 Génération de texte : xsl:text . . . . . . . . . . . . . . . . . . . . . . . . . 197
4.4.3 Sérialisation du résultat : xsl:output . . . . . . . . . . . . . . . . . . . . . 197
4.5 RSS et RDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Nous allons maintenant étudier l’utilisation de XSLT pour la traduction de documents XML dans dif-
férents formats standards de publication. Nous prenons comme motivation principale l’évolution d’un site
web à partir d’un ou plusieurs documents XML et de transformations XSLT, mais les techniques étudiées
s’appliquent bien entendu à un contexte plus général.
Notre site a pour ambition de diffuser le plus largement possible son contenu sur le Web. Il ne se con-
tente donc pas de pages HTML, mais propose également de nombreux autres formats adaptés à différents
médias, et souhaite se fraire connaître le plus précisément possible auprès des moteurs de recherches et
annuaires web.
Nous avons déjà donné dans l’introduction un aperçu du langage WML qui est un dialecte XML (nous
allons également préciser cette notion de dialecte) pour la création de documents (cartes) très simples
adaptés à l’affichage sur les petits écrans des téléphones mobiles. Nous ne revenons pas ici sur WML, la
présentation du chapitre 1 suffisant à comprendre ce langage très simple. En revanche nous présentons la

153
154 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

création de documents plus sophistiqués avec des images et des animations avec un autre dialecte XML
connu sous le nom de SMIL (Synchronised Multimedia Integration Language). SMIL permet de créer des
présentations animées qui intègrent du texte, des images du son et de la vidéo. Un aspect important de ce
langage est qu’il permet de synchroniser l’affichage des différents objets multimédia.
Pour augmenter sa visibilité sur le Web, le site peut produire un « sommaire » qui contient pour chaque
ressource web son titre, son URL et une description courte de son contenu. Ce sommaire est un document
RSS (RDF Site Summary) qui peut facilement être échangé (généralement ce document et beaucoup plus
compact que la ressource elle-même) avec d’autres applications sur le Web.
La caractéristique commune de tous ces formats (HTML, SMIL, WML, RSS) est qu’ils sont tous définis
sous forme d’une DTD (Document Type Definition) qui, d’une manière similaire à la langue Française
ou Allemande, définit un vocabulaire de noms d’éléments et d’attributs qui peuvent être combinés en
accord avec une grammaire. XML, de ce point de vue, est un « langage pour créer des langages » ou
« metalangage ». Nous commençons par expliquer cette notion de grammaire avant de prendre quelques
exemples pratiques pour illustrer son importance dans l’écriture de programmes de transformation.

4.1 Définition de Types de Documents : DTD


4.1.1 Pourquoi définir une DTD ?
La définition de DTD pour la description de documents XML offre plusieurs avantages, liés à la possibilité
d’un contrôle plus élevé dans la production du documents et des programmes qui exploitent ces documents :
S Production de documents : un éditeur XML peut se servir de la DTD pour faciliter l’édition d’un
document. Par exemple, connaissant la structure du document à produire, il peut proposer à chaque
moment les éléments et attributs qui peuvent être insérés à un endroit précis du document (édition
structurée). Il est également possible avant la sauvegarde du fichier XML de vérifier sa conformité
par rapport à sa DTD.
S Programmation XSLT : un auteur de programme XSLT se base sur la DTD du/des document(s) à
transformer et du/des documents à produire pour l’écriture et la vérification des règles XSLT.
S Échange de documents XML : dans un contexte où un « consommateur » d’information se déclare
prêt à recevoir ces informations au format XML, la DTD sert à décrire précisément les règles de
structuration des documents reçus ;
S Fragmentation de document XML : les entités qui constituent un document XML sont déclarées dans
sa DTD. Les définitions d’entités correspondent à une description physique de la structure du docu-
ment, qui est est indépendante de la notion de « dialecte » XML.

Les processeurs XSLT permettent généralement de choisir entre une analyse syntaxique (par rapport à
la syntaxe XML) ou une analyse validante (par rapport à une DTD) des documents à transformer.

4.1.2 Entités
Dans les chapitres précédents nous avons utilisé plusieurs fois des entités pour fragmenter physiquement
le contenu sérialisé d’un document XML en plusieurs fichiers ou inclure des caractères spéciaux comme
<, >, &, ’ et ". D’une manière plus générale, la notion d’entité permet de déconnecter la définition logique
d’un document XML sous forme d’arbre DOM de sa représentation physique sous forme de fichiers XML :
un document XML peut ainsi être représenté par un ensemble d’entités très divers comme :
S plusieurs fichiers XML, dites entités XML (parsed entities) ;
S un fichier DTD optionnel ;
S plusieurs fichiers image, son et vidéo, appelés entités non-XML (unparsed entities).
4.1. DÉFINITION DE TYPES DE DOCUMENTS : DTD 155

Parmi les entités XML, un fichier, appelé entité document, correspond à la racine du document XML
et contient, directement ou indirectement, les références vers tous les autres entités. Chacune des entités
XML peut contenir à son tour des références vers d’autres entités faisant partie du document (les entités
non-XML ne peuvent pas contenir de telles références).
On obtient ainsi un graphe de référencement avec toutes les entités participant à la constitution du doc-
ument XML (arbre DOM) final par un parseur. Cette constitution consiste essentiellement à remplacer les
références vers les entités par leur contenu. Pour éviter des arbres DOM de taille infinie, ce graphe de
référencement doit être acyclique : aucune entité ne doit se référencer elle-même directement ou indirecte-
ment.
Pour pouvoir « utiliser » ou référencer une entité elle doit être définie au préalable dans la DTD du
document. La seule exception à cette règle est la définition de la DTD elle-même, qui peut être stockée
dans une entité DTD séparée et qui est définie et utilisée dans l’entité document avec la clause <!DOCTYPE
...>.
La définition d’une entité consiste à associer un contenu (XML ou autre) à un nom d’entité. XML
distingue entre les entités internes dont le contenu est défini dans la DTD et les entités externes dont le
contenu est un fichier séparé.
Une définition d’entité interne associe directement un nom à une valeur sans passer par une indirection
à travers un fichier externe. Par exemple, l’entité suivante définit une entité Ucirc avec comme valeur
l’Unicode du symbole ’Û’.
<!ENTITY Ucirc "&#219;">
Dans la définition d’un entité externe, le nom de l’entité est associé à l’adresse d’un fichier (URL) qui
définit son contenu. Voici les formes de définition d’entités externes :
<!ENTITY "nom_entité" SYSTEM "url_entity">
<!ENTITY "nom_entité" PUBLIC "id_publique" "url_entity">
La deuxième définition utilise un identificateur public en plus de l’URL de l’entité et permet une iden-
tification plus formelle et surtout indépendante d’une adresse physique. Il est surtout appliqué à des docu-
ments « publics » qui sont catalogués et largement référencés par d’autres documents.
Par exemple, la DTD XHTML définit une entité externe qui contient les définitions d’entités spécifiques
à l’utilisation de caractères latin dans un document XML (le symbole % après la balise <!ENTITY indique
qu’il s’agit d’une entité paramètre qui pourra être référencé dans la DTD même : voir plus bas).
<!ENTITY % HTMLlat1 PUBLIC
"-//W3C//ENTITIES Latin 1 for XHTML//EN"
"xhtml-lat1.ent">
Dans le cas où l’URL xhtml-lat1.ent est inaccessible, un parseur « intelligent » peut se servir de
l’identificateur public pour trouver dans une liste d’URL (catalogue) une URL accessible (rien n’empêche
d’ailleurs le parseur d’avoir une copie locale de cette DTD pour améliorer les performances).

Entités paramètres Comme pour un document XML, il est possible de découper une DTD en plusieurs
entités (fichiers). Ces entités sont appelées des entités paramètres pour les distinguer des entités générales
qui sont utilisées dans le contenu d’un document XML. La définition d’une entité paramètre est caractérisée
par l’ajout du symbole %. Une référence vers une entité paramètre se compose du symbole % suivi par le
nom de l’entité et terminé par le symbole ;. Voici la définition et l’utilisation d’une entité paramètre externe
dans la DTD XHTML :
<!ENTITY % HTMLlat1 PUBLIC
"-//W3C//ENTITIES Latin 1 for XHTML//EN"
"xhtml-lat1.ent">
%HTMLlat1;
Les trois premières lignes définissent l’entité qui est référencée dans la quatrième ligne par son nom. Le
résultat est l’inclusion de la DTD "xhtml-lat1.ent" - qui définit des entités pour les caractères latin - dans la
DTD XHTML.
156 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

Entités non-XML et notations : Les entités non-XML comme les images et les fichiers son ont un statut
très particulier dans le monde XML. En réalité, ce type d’entité est une boîte noire qui ne peut pas être
analysée ou utilisée d’un manière « directe ». Pour pouvoir donner un minimum d’interprétation, XML
permet la spécification de formats d’entités non-XML sous forme de déclarations de notations (nous avons
mentionné dans la section consacrée à DOM page 64 l’existence d’une interface Notation) : une notation
associe un nom de format à un identificateur système ou public qui pourra être exploité pour l’interprétation
du contenu de l’entité. Généralement, cet identificateur définit une application qui peut se charger de
l’affichage ou du traitement des entités non-XML de ce format.
Par exemple, la définition de format suivante associe le format gif à une application xv :
<!NOTATION gif SYSTEM ’/usr/local/bin/xv’ >
Attention, le nom gif est choisi librement et indépendant du format de l’entité.
Pour définir une entité non-XML du format gif, on peut ensuite utiliser une syntaxe identique à celle
de la définition d’entité externe, étendue par le mot réservé NDATA, suivi du nom du format :
<!ENTITY logo SYSTEM "image.gif" NDATA gif >
Une entité non-XML ne peut pas être référencée dans le contenu d’un document XML, qui est obli-
gatoirement conforme à la syntaxe XML – ce qui ne serait très probablement plus le cas après l’inclusion
d’une image GIF dans le contenu même. La seul possibilité de référencer des entités est de définir des
attributs de type ENTITY ou ENTITIES qui peuvent ensuite prendre comme valeur un nom ou une liste
de noms d’entités non-XML.

4.1.3 Éléments
Une DTD définit le vocabulaire et la grammaire d’un « dialecte » XML. Le vocabulaire est essentiellement
constitué de noms d’éléments et d’attributs. La grammaire définit, pour chaque élément, ses fils et ses
attributs possibles.
La définition générale d’un élément dans une DTD est la suivante :
<!ELEMENT nom structure>

Contrainte : Il ne peut avoir qu’une seule définition pour chaque nom d’élément dans une DTD.

Prenons comme exemple la DTD XHTML qui décrit la dernière version de HTML (la version 4.0)
comme un dialecte XML (voir page 165 pour une description complète). La DTD complète peut être
téléchargée à l’URL http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd.
Voici la définition de l’élément racine d’un document HTML dans la DTD XHTML :
<!ELEMENT html (head, body)>
Le mot réservé <!ELEMENT est suivi du nom de l’élément à définir (html). La structure de l’élément
html est définie par (head, body).
Une DTD distingue cinq types de structures pour les éléments :
1. Si un élément est vide, on utilise le mot réservé EMPTY pour définir sa structure.
2. Si un élément ne peut contenir que du texte (des fils de type Text au sens DOM) on utilise le mot
réservé #PCDATA. Par exemple, l’élément T title U de XHTML ne peut contenir que du texte :

<!ELEMENT title (#PCDATA)>

3. Si élément ne peut contenir que des fils qui sont à leur tour des éléments, on spécifie les types des
éléments fils possibles pour cet élément, le nombre d’occurences pour chaque fils et, éventuellement,
l’ordre dans lequels ces fils doivent apparaître dans le document (rappelons qu’un document XML
correspond à un arbre ordonné). Cette spécification est appelée le modèle de contenu de l’élément.
4.1. DÉFINITION DE TYPES DE DOCUMENTS : DTD 157

4. Si un type d’élément peut avoir un contenu « mélangé », c’est-à-dire contenir des fils qui sont des
éléments mais également du texte, on spécifie les types des éléments qui peuvent être fils de cet
élément. Dans ce cas, on ne peut plus spécifier le nombre d’occurences pour chaque fils ou l’ordre
dans lequel ces fils doivent apparaître dans le document.
5. Il est également possible de ne définir aucune contrainte sur le contenu d’un élément en utilisant le
mot réservé ANY. Dans ce cas, le contenu de l’élément doit seulement être bien-formé, c’est-à-dire
essentiellement respecter l’imbrication des balises.

Modèles de Contenu
Le modèle de contenu d’un élément indique les types de ses fils, mais également le nombre d’occurrences
pour chaque type de fils. Si nécessaire, on peut également établir un ordre sur les occurrences des fils de
chaque type.
La définition de la balise T html U indique que l’élément racine de type html ne peut avoir que deux
types d’éléments comme fils : head et body. En plus, chaque type de fils ne doit apparaître qu’une seule
fois et dans l’ordre indiqué. En d’autres termes, l’élément racine d’un document XHTML est toujours de
la forme suivante :

<html>
<head>...</head>
<body>....</body>
</html>

Pour indiquer qu’un type d’élément peut apparaître zéro ou une fois on utilise le symbole ?. Par
exemple, la DTD suivante accepte les deux documents <A><C/></A> et <A><B/><C/></A> (B et C
sont définis comme éléments vides) :
<!ELEMENT A (B?,C) >
<!ELEMENT B EMPTY >
<!ELEMENT C EMPTY >
Il existe également des symboles pour indiquer qu’un type d’élément peut apparaître plusieurs fois. On
utilise le symbole * si un type de fils peut apparaître zéro, une ou plusieurs fois, et le symbole + s’il doit
apparaître au moins une fois. Par exemple, si on remplace la définition précédente de l’élément A par la
définition :
<!ELEMENT A (B*,C+)>
la DTD accepte, entre autre, tous les éléments de type A suivants :
<A><C/></A>
<A><C/><C/></A>
<A><B/><C/></A>
<A><B/><B/><C/></A>
En revanche, cette dernière définition n’accepte pas les éléments <A></A> et <A><C/><B/><C/></A>.
Dans le premier cas, par définition, un élément vide T C/ U doit apparaître au moins une fois, et dans le
deuxième cas, tous les éléments T B/ U doivent apparaître avant tous les éléments T C/ U .
On peut donner le choix entre deux types d’éléments en remplaàant la virgule entre les éléments par le
symbole | :
<!ELEMENT A (B|C)>
Dans ce cas, A peut contenir un seul fils qui est soit de type B ou de type C.
Finalement, on peut enlever la restriction sur l’ordre des fils : on voudrait par exemple accepter comme
fils pour l’élément T A U zéro ou plusieurs éléments de type T B U et T C U dans n’importe quel ordre. Pour
cela, on peut utiliser des parenthèses pour regrouper des éléments. La définition suivante indique que les
éléments de type A acceptent un élément de type B ou de type C zéro ou plusieurs fois :
158 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

<!ELEMENT A (B|C)*>
Tous les éléments de type A qui précèdent sont valides par rapport à cette définition, ainsi que les deux
éléments suivants :
<A><C/><C/><B/><C/><B/></A>
<A><B/><B/></A>
Ce parenthésage permet de définir des structures plus complexes. Par exemple, la structure d’un tableau
HTML est définie par l’expression suivante (nous ne donnons pas la structure des éléments qu’il contient) :

<!ELEMENT table
(caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
S les éléments caption, thead et tfoot sont optionnels ;
S l’élément caption est suivi par zéro ou plusieurs éléments de type col ou colgroup (il ne peut
pas avoir simultanément les deux types d’éléments) ;
S les éléments thead et tfoot, sont suivis par un ou plusieurs éléments de type tbody ou tr (il ne
peut pas avoir les deux types d’éléments)

Selon cette définition, un tableau HTML minimal a la forme suivante :


<table>
<tr>...</tr>
</table>
ou
<table>
<tbody>...</tbody>
</table>
Les éléments T tr U définissent des lignes du tableau. Pour créer un tableau complet avec des colonnes,
il faut également connaître la définition de l’élément de type tr :
<!ELEMENT tr (th|td)+>
On voit que ce T tr U a comme fils un ou plusieurs éléments de type th et/ou td dans n’importe quel
ordre. Chaque élément d’un de ces deux types définit une colonne dans le tableau. La différence entre th
et td est que, dans le premier cas (th), le contenu est en général affiché en gras (header).

Contenu mixte
Les éléments de type td et th peuvent avoir un contenu mixte, c’est-à-dire contenir des sous-éléments
mais également du texte. Voici un tableau complet exprimé en XHTML (les éléments T td U contiennent
du texte) :

Exemple 57 TableauSimple.html : Tableau XHTML


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Page XHTML avec un tableau simple</title>
</head>
<body>
4.1. DÉFINITION DE TYPES DE DOCUMENTS : DTD 159

<table border=’1’>
<tr><td>ligne <b>1</b>, colonne <b>1</b></td>
<td>ligne <b>1</b>, colonne <b>2</b></td>
</tr>
<tr><td>ligne <em>2</em>, colonne <em>1</em></td>
<td>ligne <em>2</em>, colonne <em>2</em></td>
</tr>
</table>
</body>
</html>

Le tableau a deux lignes, indiquées par les balises T tr U dont chacune a deux colonnes (balises
T td U ). La figure 4.1 montre l’affichage par de cette page par Netscape.

Figure 4.1: Affichage de TableauSimple.html.

Les éléments de type td et th peuvent contenir des sous-éléments de plusieurs dizaines de types
différents et une description détaillée dépasse le cadre de ce livre. Voici une définition très simplifiée du
type td :

<!ELEMENT td "(#PCDATA | table | p | b | em )*">

Cette dernière définition indique que les éléments de type td contiennent des sous-éléments de dif-
férents types mélangés avec du texte dans n’importe quel ordre. En fait, il n’est pas possible de spécifier
des contraintes plus fortes sur la structure d’un élément qui contient du texte mélangé avec des éléments.
Par exemple, il n’est pas possible de spécifier qu’un élément de type td contient d’abord du texte suivi
d’autres éléments comme dans l’exemple suivant :
<!-- Attention: La déclaration suivante n’est pas possible: -->
<!ELEMENT td "(#PCDATA, (table | p | b | em )*)">

Définition récursives
La définition d’un type d’élément e donné peut contenir des types d’éléments f qui utilisent déjà e dans
leur propre définition. Si on regarde la définition (partielle) de la structure des éléments de type td, on
voit qu’une colonne d’un tableau peut à nouveau contenir un tableau, autrement dit qu’on peut créer des
tableaux imbriqués. Voici un exemple (voir l’affichage 4.2)
,:

Exemple 58 TableauComplexe.html : Exemple d’un tableau imbriqué


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Page XHTML avec un tableau imbriqué</title>
160 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

</head>
<body>
<table border="1">
<tr> <!-- première ligne du tableau "extérieur" -->
<td> <!-- première colonne "extérieure" -->
<table border="1"> <!-- tableau "intérieur" -->
<tr><td>1</td><td>2</td></tr>
<tr><td>3</td><td>4</td></tr>
</table>
</td>
<td>a</td> <!-- deuxième colonne "extérieure" -->
</tr>
<tr> <!-- deuxième ligne du tableau "extérieur" -->
<td>b</td><td>c</td>
</tr>
</table>
</body>
</html>

Figure 4.2: Copie d’écran de l’affichage d’un tableau imbriqué

4.1.4 Attributs
Une DTD sert également à spécifier les attributs permis pour chacun de ses types d’élément. Par exemple,
dans le fichier TableauComplexe.html les éléments de type table contiennent chacun un attribut border,
dont la valeur est égale à 1 (les champs du tableau doivent être entourés d’un cadre dont la largeur est un
pixel). Cet attribut est défini dans la DTD XHTML de la manière suivante :

<!ATTLIST table border CDATA #IMPLIED>

Le mot réservé <!ATTLIST est suivi du nom de l’élément défini dans la DTD (table), du nom de
l’attribut à définir (border), des informations sur le type de l’attribut (CDATA) et son utilisation (#IMPLIED).
Le type CDATA indique que les valeurs de cet attribut peuvent être des chaînes de caractères composées de
tous les caractères sauf &, < et >. Le mot #IMPLIED signifie que cet attribut est optionnel.

Contrainte : Il ne peut avoir deux définitions d’attributs avec le même nom pour un élément. En revanche,
il est possible de définir plusieurs attributs avec le même nom (et du même type ou de types différents) dans
des éléments différents.

Dans la DTD XHTML, les éléments de type td et th (champs dans une ligne d’un tableau) partagent
exactement les mêmes attributs. Voici une version simplifiée :

<!ATTLIST td bgcolor CDATA #IMPLIED


4.1. DÉFINITION DE TYPES DE DOCUMENTS : DTD 161

rowspan CDATA "1"


colspan CDATA "1">
L’attribut optionnel bgcolor permet de définir la couleur de fond de la cellule. Les deux attributs (op-
tionnels) suivants spécifient respectivement la hauteur (en lignes) et la largeur (en colonnes) de la cellule.
Par défaut ces attributs prennent la valeur 1 : dans le cas d’un attribut optionnel avec valeur par défaut, le
mot réservé #IMPLIED est remplacé par la valeur par défaut.
Voici l’exemple d’un tableau plus complexe où les différents éléments ont des attributs (voir l’affichage
dans la figure 4.3).

Exemple 59 TableauAttrs.html : Tableau avec attributs


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>page xhtml avec un tableau complexe</title>
</head>
<body>
<table border="1">
<tr><th rowspan="2"/><th bgcolor="gray" colspan="2">R</th></tr>
<tr bgcolor="#aaaaaa"><th>A</th><th>B</th></tr>
<tr><th bgcolor="#aaaaaa">x</th><td>1</td><td>2</td></tr>
</table>
</body>
</html>

Figure 4.3: Affichage de TableauAttrs.html

La présence de certains attributs est parfois obligatoire dans la balise ouvrante d’un élément. Par ex-
emple, la balise T img U qui permet d’inclure des images dans un document HTML/XHTML doit toujours
contenir un attribut src avec l’URL d’une image à inclure et un attribut alt avec un texte d’explication
si l’image ne peut pas être affichée (l’attribut alt est optionnel dans HTML 4.0). Voici un extrait de la
définition des attributs spécifiés pour les éléments de type img dans la DTD XHTML :
<!ATTLIST img src CDATA #REQUIRED
alt CDATA #REQUIRED
height CDATA #IMPLIED
width CDATA #IMPLIED>
Les src et alt sont des attributs obligatoires. Les attributs height et width sont optionnels et
permettent de définir la hauteur et la largeur de l’image (en pixels ou en pourcentage d’espace disponible).
Les éléments de type img peuvent également contenir un attribut ismap dont la présence indique
si l’image contient des zones qui servent comme boutons pour des liens vers d’autres pages XHTML.
162 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

Dans HTML 4.0 il suffit d’inclure cet attribut dans la balise ouvrante sans définir une valeur. Ceci n’est
pas permis dans XHTML qui impose la définition d’une valeur pour chaque attribut. Pour cela, XHTML
définit ismap comme un attribut optionnel qui peut prendre comme seule valeur le mot ismap :

<!ATTLIST img ismap (ismap) #IMPLIED>

Des exemples de balises T img U ouvrantes valides et non-valides sont donnés dans le tableau 4.1.

Balise Valide ?
<img src="lo.gif" valide
alt="logo">
<img src="lo.gif" alt="logo" valide
width="100">
<img src="lo.gif" alt="logo" valide
ismap="ismap">
<img> invalide : les attributs src et alt man-
quent
<img src="lo.gif" alt="logo" invalide : "toto" n’est pas permis
ismap="toto" comme valeur de ismap

Table 4.1: Balises ouvrantes de type img

L’attribut ismap est un exemple trivial d’un attribut de type énumération : au lieu de spécifier une
seule valeur, il est également possible de spécifier un ensemble de valeurs possibles séparées par le symbole
« | ». Un exemple est l’attribut type associé aux éléments de type button ( boutons d’un formulaire
XHTML) :

<!ATTLIST button type (button|submit|reset) "submit">

Après #IMPLIED et #REQUIRED, un troisième type d’utilisation d’un attribut est défini par le mot
réservé #FIXED. IL est assez rare et permet de définir des attributs avec une valeur constante : la décla-
ration de l’attribut doit contenir une valeur par défaut et toutes les occurrences de cet attribut, optionnel,
doivent avoir la même valeur. L’attribut xmlns défini pour l’élément racine d’un document XHTML est
un exemple d’un attribut fixe :

<!ATTLIST html xmlns CDATA #FIXED ’http://www.w3.org/1999/xhtml’>

Cet attribut définit l’espace de nommage des éléments XHTML Et ne peut pas être changé. Des exem-
ples de balise T html U ouvrantes valides et non-valides sont donnés dans le tableau 4.2.

Balise Valide ?
<html> valide
<html xmlns="http://www.w3.org/1999/xhtml"> valide
<html xmlns="http://foo.bar/xhtml"> invalide : espace de noms
différent de la valeur fixée

Table 4.2: Balises ouvrantes d’éléments de type html

Types d’attributs
À part CDATA il existe neuf autres types d’attributs qui sont résumés dans le tableau 4.3.
4.1. DÉFINITION DE TYPES DE DOCUMENTS : DTD 163

Type d’Attribut Valeurs possibles


CDATA chaînes de caractères composée de tous les caractères
sauf &, < et >
(nom1|nom2|...) un nom symbolique (chaîne de caractères sans blancs)
dans l’ensemble {nom1, nom2, ...}
NMTOKEN nom symbolique
NMTOKENS liste de noms symboliques
ID nom symbolique: identificateur de l’élément dont la
balise contient l’attribut de ce type (voir page 163)
IDREF nom symbolique: référence vers un élément identifié par
un attribut de type ID (voir section 4.1.4
IDREFS liste de noms symboliques (séparés par des blancs) :
référence vers des éléments identifiés par des attributs de
type ID (voir page 163)
ENTITY nom symbolique : adresse d’une entité externe non-XML
(voir page 154)
ENTITIES liste de noms symboliques : adresses d’entités externes
non-XML (voir page 154)

Table 4.3: Types d’attributs et valeurs possibles

Identification d’éléments
Les attributs de type ID permettent d’identifier les éléments dans un document XML. XHTML définit un
attribut identificateur pour un grand nombre de types d’éléments. Par exemple, la définition de l’élément
table contient un attribut id :

<!ATTLIST table id ID>

Attention, il ne faut pas confondre le nom de l’attribut (id) avec son type (ID) : c’est uniquement le
type qui décide si un attribut permet d’identifier un élément dans un document XML. En d’autres termes,
pour connaître les attributs identificateurs d’un document XML, l’inspection de sa DTD est obligatoire.
Les contraintes imposées pour l’utilisation des attributs identificateurs sont les suivants :

1. On peut définir au maximum un attribut identificateur par type d’élément.

2. Il ne doit pas y avoir plusieurs éléments avec la même valeur pour un attribut déclaré comme ID dans
un même document XML. Il est important à noter que cette contrainte porte sur tous les éléments
d’un document XML indépendamment de leur type. Ainsi, même si deux éléments sont de types
différents, il ne doivent pas avoir le même identificateur (on dit que les identificateurs ne sont pas
typés).

Remarque : L’introduction d’attributs identificateurs est nouveau dans la « version » XHTML de HTML 4.0
qui avait une notion beaucoup plus faible d’identification, définie uniquement pour les éléments de type a
(ancres) identifiées par l’attribut name.

On n’est pas obligé de définir un identificateur pour chaque élément dans un document XML. D’une
manière générale, on ne définit des identificateurs que pour les éléments qui sont référencés par d’autres
éléments. Ce référencement est possible grâce à des attributs de type IDREF et IDREFS. Un exemple d’un
tel attribut est for défini pour les éléments de type label :

<!ATTLIST label for IDREF #IMPLIED>


164 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

Ce type d’élément permet de définir une légende pour d’autres éléments dans un formulaire comme
button, input ou select. Voici un exemple extrait de la recommandation XHTML :

<form action="..." method="post">


<table>
<tr>
<td><label for="fname">first name</label>
<td><input type="text" name="firstname" id="fname">
<tr>
<td><label for="lname">last name</label>
<td><input type="text" name="lastname" id="lname">
</table>
</form>
Ce formulaire (élément de type form) contient deux éléments de type input qui sont identifiés par un
attribut id de type ID. Les valeurs de ces deux attributs apparaissent comme références dans les attributs
for des éléments de type label.
L’utilisation d’attributs de type IDREF et IDREFS dans un document XML doit respecter la contrainte
suivante : pour chaque valeur (identificateur) d’un attribut de type IDREF et chaque valeur dans la liste des
valeurs d’un attribut de type IDREFS il doit exister un élément avec cet identificateur, c’est-à-dire avec un
attribut de type ID de valeur identique. Dans le domaine des bases de données relationnelle, on parle de
« contraintes d’integrité référentielle ».

4.1.5 DTD et XML Schéma


Concluons cette présentation des DTD par quelques remarques sur leurs limites :
S Une DTD n’est pas un document XML : ceci crée une séparation inutile entre la description de la
structure et le contenu d’un document qui ne peuvent pas être traités de manière uniforme. Par
exemple, il n’est pas possible d’inspecter une DTD dans un programme XSLT !
S L’ensemble des types proposés par une DTD est restreint : on ne peut utiliser qu’un seul type de
valeur atomique #PCDATA pour le contenu et une dizaine de types pour les attributs (CDATA, NM-
TOKEN, ID, IDREF, ....). Des types très courants dans les langages de programmation et la gestion
de données en général (entiers, flottants, dates) sont complètement absents.
S Il n’est pas possible de dire explicitement que deux types d’éléments ont la même structure : souvent
différents types de balise partagent une partie de leur structure (modèle de contenu). Un exemple
dans XHTML sont les balises T td U et T th U qui ont exactement le même modèle de contenu. Une
séparation entre les balises et leurs modèles de contenu donnerait plus de flexibilité et de modularité
dans la définition du langage (la DTD XHTML « simule » cette séparation avec l’utilisation d’entités
paramètres).
S Il n’est pas possible de spécifier des structures complexes sur des contenus mixtes : la structure d’un
élément qui peut avoir des fils de type Text ne peut pas être détaillée à un niveau suffisant (il est
seulement possible de spécifier les types des fils possibles, sans imposer une autre contrainte).

On a essayé de répondre à ces limites par la définition d’un langage de définition de « schémas XML »,
qui est une récente (mai 2001) recommandation W3C pour la définition de la structure de documents
XML. Un schéma XML est un document XML, il sépare la notion de balise de la structure d’un élément et
introduit une multitude de type atomiques (une cinquantaine) nouveaux pour la représentation de données.
De plus, la recommandation XML Schéma introduit des notions de modélisation objet comme l’héritage,
l’extension et la redéfinition de types.
XML Schéma est un pas vers une meilleure utilisation de XML pour l’échange d’informations, car il
permet une description plus détaillée et plus précise de la structure des données échangées. Néanmoins,
pour le moment et à cause de leur jeunesse, la richesse des schémas XML n’est pas encore exploitable
4.2. SITE WEB: HTML 165

pour la programmation XSLT. XML schéma est au niveau de la spécification formelle, et il n’existe pas
encore d’interface ou de modèle de programmation standard - analogue à DOM pour le couple XML/DTD
- permettant de développer des apllications.

4.2 Site Web: HTML


Nous passons maintenant à l’étude de quelques DTD importantes définissant des langages couramment
utilisés sur le web.

4.2.1 HTML et XHTML


HTML est un langage de balisage qui, contrairement à XML, fournit un ensemble fixe de balises avec
des significations précises qui permettent aux différents navigateurs HTML de présenter le contenu du
document d’une manière adaptée.
Comme toutes les langages informatiques qui doivent s’adapter à des nouveaux besoins, HTML a
évolué depuis sa première version publiée en 1991. En tout, entre 1991 et 1999 il y a eu quatre versions
succesives de HTML, numérotées de 1.0 à 4.0. Bien que les documents HTML actuels ressemblent dans
leur structure à des documents XML, il ne sont pas conformes à la recommandation XML. Ceci s’explique
en partie par le fait que HTML est apparu avant XML et s’est fondé sur le standard SGML. Ce dernier, qui
peut être considéré comme un précurseur de XML, permet plus de souplesse dans l’utilisation des balises
et des attributs. En contrepartie cette souplesse rend la tâche d’analyse syntaxique d’un document HTML
plus complexe.

Exemple 60 ExHTML4.html : Page HTML Version 4.0


<html>
<head>
<title>Exemple de Page HTML 4.0</title>
</head>
<BODY>
<P>Paragraphe 1
<br><img SRC="image.gif" width=30pt ismap>
<p>Paragraphe 2
</body>
</html>

Le fichier ExHTML4.html n’est pas conforme à XML pour plusieurs raisons :


S Dans SGML, les balises d’éléments vides ne doivent pas être fermées. Par exemple, la balise T br U
définit un élément vide qui correspond à un saut de ligne dans l’affichage. La représentation XML
d’un tel élément ( T br/ U ou T br U%T /br U ) n’est pas valide dans HTML 4.0.
S Quelques types d’éléments non-vides permettent aux auteurs d’omettre les balises fermantes. Par
exemple, les balises T P U et T p U ne sont pas obligatoirement fermées. Les règles pour la fermeture
implicite d’une balise non-fermée sont définies par le standard SGML.
S Dans HTML, les noms des balises et des attributs ne sont pas sensibles à la casse (case-sensitive).
Les balises T P U et T p U , qui correspondent à des débuts de paragraphe, sont considérées comme
équivalentes.
S Dans certains cas, il est possible de définir la valeur d’un attribut sans l’entourer par des apostrophes
simples ou des guillemets. C’est le cas par exemple pour la valeur de l’attribut width dans la balise
T img U .
S Enfin les attributs booléens peuvent être utilisés sans valeur. Par exemple, l’attribut ismap dans la
balise T img U n’a pas de valeur.
166 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

XHTML
Ces différences entre les « versions SGML » de HTML et XML on été identifiées et éliminées en 2000
dans la dernière version de HTML 4.0, conforme à la syntaxe XML, et appelée XHTML. Un avantage
important de cette évolution est la possibilité d’exploiter les documents XHTML (HTML-4.0) par tous les
outils XML actuels. En particulier, il devient possible de produire et même de transformer des documents
XHTML avec XSLT. Voici la version XHTML de la page HTML ExHTML4.html :
Exemple 61 ExXHTML.xml : Page XHTML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Exemple de Page XHTML</title>
</head>
<body>
<p>Paragraphe 1</p>
<p><img src="image.gif" alt="une image" width="3Opt"
ismap="ismap"/>
</p>
</body>
</html>
Si on compare le contenu des éléments de type html dans les fichiers ExHTML4.html et ExXHTML.xml,
on constate que le deuxième fichier respecte les contraintes imposées par la syntaxe XML :
S toutes les balises d’éléments (vides et non-vides) sont fermées ;
S les noms des balises et des attributs sont tous écrits en minuscules ;
S tous les attributs ont une valeur entourée par des guillemets ou des apostrophes simples.

4.2.2 DTD XHTML


Cette section est consacrée à la structure générale d’un document XHTML. Une description complète
de toutes les balises HTML/XHTML dépasserait largement le cadre de ce livre : nous vous renvoyons à
l’ouvrage HTML et XHTML, la Référence, de Chuck Musciano & Bill Kennedy, paru aux Éditions o’Reilly.
Notre but est essentiellement de donner une classification des différentes balises dans la DTD XHTML par
rapport à leur utilisation. Nous ne décrivons pas par exemple les parties de HTML 4.0 qui sont couvertes
par la recommandation XML, comme par exemple le problème de l’encodage et l’affichage des caractères.

Types de Base
En plus des différents types d’attributs définis dans la recommandation XML (CDATA, ID, IDREF, NMTO-
KEN, . . . ), XHTML spécifie quelques dizaines de types d’attributs supplémentaires avec des significations
spécifiques. Tous ces types d’attributs sont définis comme entités paramètres référencées dans la définition
d’un attribut de type correspondant. Par exemple, pour distinguer les chaînes de caractères qui correspon-
dent à des URI (Uniform Resource Identifier), la DTD définit une entité URI :
<!ENTITY % URI "CDATA">
<!-- a Uniform Resource Identifier, see [RFC2396] -->
Une DTD ne permet pas d’imposer les contraintes syntaxiques spécifiques aux URI et la DTD donne
uniquement une référence vers le document de spécification correspondant (RFC2396) dans un commen-
taire. Cet entité est ensuite référencée dans la définition d’un attribut qui accepte une URI comme valeur.
Par exemple, l’attribut href des éléments de type a prend comme valeur l’URI de la ressource qui corre-
spond à la destination d’un lien HTML :
4.2. SITE WEB: HTML 167

<!ATTLIST a href %URI; #IMPLIED


Voici la définition de quelques autres types de base dans la DTD XHTML :
<!ENTITY % Number "CDATA">
<!-- one or more digits -->
<!ENTITY % Text "CDATA">
<!-- used for titles etc. -->
<!ENTITY % Length "CDATA">
<!-- nn for pixels or nn% for percentage length -->
<!ENTITY % Color "CDATA">
<!-- There are also 16 widely known color names with their sRGB values:
Black = #000000 Green = #008000
Silver = #C0C0C0 Lime = #00FF00
Gray = #808080 Olive = #808000
White = #FFFFFF Yellow = #FFFF00
Maroon = #800000 Navy = #000080
Red = #FF0000 Blue = #0000FF
Purple = #800080 Teal = #008080
Fuchsia= #FF00FF Aqua = #00FFFF
-->
Nous verrons plus loin quelques attributs qui utilisent ces différents types.

Structure générale d’un document XHTML


Le fichier ExXHTML.xml, page 166 donne la structure générale d’un document XHTML. Il commence par
une déclaration XML, optionnelle, mais utile pour le processeur. Les trois lignes suivantes définissent la
DTD du document :
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
La première ligne indique que l’élément racine du document est de type html. Les deux lignes suiv-
antes définissent l’identificateur public et l’adresse physique de la DTD XHTML qui doit être respectée par
le document. Cette DTD est stockée dans le fichier xhtml1-transitional.dtd. L’élément racine
T html U y est défini de la manière suivante :
<!ELEMENT html (head, body)>
<!ATTLIST html
%i18n;
xmlns %URI; #FIXED ’http://www.w3.org/1999/xhtml’>
Les attributs définis dans l’entité paramètre i18n permettent d’indiquer le code de la langue utilisée dans
le contenu du document. L’attribut xmlns défini l’espace de noms de HTML qui ne peut pas être changé
(c’est un attribut fixé).
Les éléments de type head et body contiennent respectivement l’en-tête et le contenu du document
XHTML. Ils sont définis comme suit (nous ne donnons pas les attributs de ces éléments) :
<!ELEMENT head (%head.misc;,
((title, %head.misc;, (base, %head.misc;)?) |
(base, %head.misc;, (title, %head.misc;))))>
<!ELEMENT body %Flow;>
Élément entête head : On voit que les éléments de type head doivent avoir exactement un sous-élément
de type title, un sous-élément optionnel de type base et des sous-éléments définis par l’entité
paramètre head.misc :
168 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

<!ENTITY % head.misc "(script|style|meta|link|object|isindex)*">

À part title, le type meta est le plus utilisé dans l’entête d’un document HTML. Ces éléments
sont vides et permettent de donner des informations supplémentaires sur le contenu du document
sous forme de valeurs d’attributs :

<!ELEMENT META EMPTY>


<!ATTLIST META
%i18n;
http-equiv NAME #IMPLIED
name NAME #IMPLIED
content CDATA #REQUIRED
scheme CDATA #IMPLIED
>

Les deux attributs name et content peuvent être utilisés librement pour donner des informations
« meta » sur le contenu du document. Par exemple, la balise T name U permet d’indiquer l’auteur
d’un document et quelques mots-clés qui peuvent être exploités pour l’indexation par un moteur de
recherche :

<META name="author"
content="L’épée de Bois"/>
<META name="keywords" lang="en-us"
content="movie theatre, cinema, paris"/>
<META name="keywords" lang="fr"
content="cinéma, film, paris"/>

Élément contenu body : Les éléments de type body ont un contenu mixte (du texte mélangé avec d’autres
éléments) défini par l’entité Flow :

<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">

On peut distinguer entre les éléments « container » (spécifiés par l’entité block) qui acceptent des
sous-éléments, les éléments « feuilles » (spécifiés par l’entité inline) qui n’acceptent que du texte
et ceux qui peuvent être « container » et « feuilles ».

Le fichier ExXHTMLCompl.html contient les balises les plus courantes dans une page XHTML (HTML),
à l’exception des tableaux (voir page 154), et des formulaires. Nous laissons également de côté la construc-
tion de pages avec cadres (frames).

Exemple 62 ExXHTMLCompl.html : Page HTML typique.


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"../DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Exemple de Page XHTML</title>
</head>
<body>
<center>
<h1>Header 1 (centré)</h1>
</center>
<h2>Header 2</h2>
<p>Paragraphe 1</p>
4.2. SITE WEB: HTML 169

<p>Paragraphe 2:
Ligne1<br/>Ligne2<hr/>Ligne3
</p>
<p>Paragraphe 3:
<pre>
Texte
formatté
</pre>
Texte <b>gras</b>, <i>italique</i> et <b><i>italique et gras</i></b>,
<font size="-2" color="blue">bleu et petit</font>
</p>
<p>Paragraphe 4:
Une liste
<ul>
<li>Une image:
<img src="Vertigo.gif" alt="une image" width="30" align="bottom"/>
</li>
<li>Une autre liste:
<ol><li>item 1</li><li>item 2</li></ol>
</ul>
<a href="Vertigo.xml">Lien</a> vers la page Vertigo.xml
</p>
</body>
</html>

La figure 4.4 montre l’affichage de ce fichier avec un navigateur XHTML. En occurrence il s’agit de la
version 0.9.2 du navigateur Mozilla, lui-même basé sur Netscape. Tous les navigateurs actuels ne sont pas
capables d’afficher du XHTML.

Formattage de texte HTML


Le texte de cette page est mis en forme de la façon suivante :
g le texte dans la balise h center i est centré ;
g séparation de paragraphes et de lignes:

– la balise h p i est utilisée pour définir quatre paragraphes – les auteurs de pages HTML remar-
querons que ces balise sont fermées.
– les balises h br i et h hr i séparent deux lignes (la deuxième balise ajoute un séparateur sous
forme d’un trait entre les deux lignes) : les fins de lignes dans le texte n’ont pas d’influence sur
sa présentation.
g pendant l’affichage, les espaces sont généralement transformés en un seul caractère blanc. Les
seules exceptions sont les espaces dans le contenu de la balise h pre i qui ne sont pas modifiés. Si
on regarde la définition des attributs de cet élément :

<!ATTLIST pre
%attrs;
xml:space (preserve) #FIXED ’preserve’>

on peut observer qu’il définit un attribut xml:space dont l’unique valeur doit être égale à pre-
serve.
g taille de police : le texte entre les h h1 i et h h2 i a une taille supérieure au texte normal : HTML
définit six niveaux d’agrandissement avec six types de balises ( h h1 i , h h2 ijh h3 i , h h4 i ,
h h5 i , h h6 i ) où la balise h h1 i correspond à l’agrandissement le plus important.
170 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

Figure 4.4: Copie d’écran de ExXHTMLCompl.html

g style de police : les balises h em i et h b i transforment le texte qu’ils contiennent en italique et en


gras. Il est évidemment possible de combiner les deux.
g couleur de police : La balise h font i permet, entre autre, le changement de la couleur et de la taille
du texte qu’elle contient.
Il contient également deux listes, une image et un lien :
g HTML permet de construire des listes non-numérotées définies par les éléments h ul i et les listes
numérotés représentées par les balises h ol i . Les éléments dans une liste sont représentés par les
balises h li i qui sont des éléments « container ».
g Les images sont incluses en utilisant la balise h img i ;
g Les liens entre pages HTML et entre une page HTML et un autre type de ressource sont définis
en utilisant la h a i : les liens sont uni-directionnel – il peuvent être traversés seulement dans une
direction – et mono-cible – il n’est pas possible de spécifier plusieurs ressources cibles pour un lien.
Nous montrerons d’autres exemples dans la suite.

4.2.3 Génération de pages HTML: xsl:output


Tous les navigateurs HTML actuels n’ont pas encore adopté le standard XHTML et il faudra continuer
encore pendant un certain temps de produire des documents HTML conformes aux versions antérieures
4.2. SITE WEB: HTML 171

(l’expérience montre que les logiciels qui sont distribués à un très grand public, ce qui est le cas pour les
navigateurs Web qui sont utilisés par tous les Internautes, se renouvellent lentement). Toutefois, la création
d’un document HTML version 4.0 ou antérieure à partir d’un document XML n’est pas si évidente avec
une feuille de style XSLT. Rappelons qu’un programme XSLT est lui-même un document XML qui doit
respecter les contraintes syntaxiques du langage. Ainsi, la règle suivante, qui remplace les éléments de type
LOGO par un élément HTML vide n’est pas correcte :

<xsl:template match=’LOGO’>
<br><img SRC="image.gif" width=30pt ismap>
</xsl:template>

Inversement, la règle suivante est correcte mais ne produit pas une balise conforme à HTML 4.0 (les
balise h br i et h img i définissent des éléments vides et ne doivent pas être fermés) :

<xsl:template match=’LOGO’>
<br /><img src="image.gif" alt="Affiche du Film" width="3Opt"
ismap="ismap"/>
</xsl:template>

Pour résoudre ce dilemme, XSLT définit l’instruction xsl:output qui permet de spécifier un for-
mattage à posteriori du résultat de la transformation. La méthode qui nous intéresse ici est html, qui traduit
le résultat XHTML en document HTML. Ainsi, en ajoutant l’instruction xsl:output method="html"/>
au début de la feuille de style contenant la deuxième règle, les éléments de type LOGO sont remplacés par
la balise h IMG src=’logo-small.gif’ i .

4.2.4 Transformation d’une page XML


Voyons maintenant comment on peut utiliser XSLT pour publier des informations contenues dans des
documents XML sous forme d’un site HTML. Entre autres avantages d’une manipulation des documents
XML à la place de documents HTML, nous allons montrer que XSLT permet d’éviter des redondances
dans les contenus de documents, et de traiter le problème des liens cassés.
Reprenons l’exemple des films et des cinémas de l’introduction pour décrire plus en détail la génération
d’un site Web/HTML. Le premier fichier XML est Vertigo.xml, donné page 24. Le programme Film.xsl,
page 25 transforme ce document en page HTML. Voici une règle très simple de transformation pour le
film :

<xsl:template match="FILM">
<h1><xsl:value-of select="TITRE"/></h1>
<xsl:value-of select="GENRE"/>,
<xsl:value-of select="PAYS"/>,
<xsl:value-of select="ANNEE"/>, de
<xsl:value-of select="AUTEUR"/>
</hr>
<xsl:value-of select="RESUME"/>
</xsl:template>

On peut observer que cette règle affiche la valeur de tous les fils de l’élément FILM. Une application
à d’autres éléments du même type, sous-entend qu’on connaît pour tous les films leur titre, leur auteur,
l’année, le genre, le pays et un résumé. En d’autres terme, l’auteur de cet règle suppose qu’elle s’applique
uniquement à des films qui sont valides par rapport à la DTD Film.dtd suivante :
Exemple 63 Film.dtd : DTD pour les films

<!ELEMENT FILM (TITRE, AUTEUR, ANNEE, GENRE, PAYS, RESUME) >


<!ATTLIST FILM FILMID ID #REQUIRED>
<!ELEMENT TITRE (#PCDATA) >
172 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

<!ELEMENT AUTEUR (#PCDATA) >


<!ELEMENT ANNEE (#PCDATA) >
<!ELEMENT GENRE (#PCDATA) >
<!ELEMENT PAYS (#PCDATA) >
<!ELEMENT RESUME (#PCDATA) >
On voit, par ce premier exemple, que même si les DTD ne peuvent pas être exploitées directement par des
programmes XSLT, elles facilitent la programmation en fournissant une description précise des données
à transformer. En d’autres termes, une DTD peut servir comme système de typage complémentaire pour
le langage XSLT : en utilisant un parseur validant, on vérifie alors la validité d’un document avant sa
transformation.

Remarque : Le langage XSLT est très complexe et il n’est pas possible de vérifier pour un programme
XSLT quelconque qu’il transforme tous les document valides par rapport à une DTD vers des documents
d’une autre DTD.

Voici un autre document qui décrit une salle de cinéma :


Exemple 64 Salle1.xml : Salle de cinéma
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet href="SalleRefOut.xsl" type="text/xsl"?>
<?cocoon-process type="xslt"?>
<SALLE NO=’1’ PLACES=’320’ FILMREF=’2’>
<SEANCES>
<SEANCE>15:00</SEANCE>
<SEANCE>18:00</SEANCE>
<SEANCE>21:00</SEANCE>
</SEANCES>
<REMARQUE>Réservation conseillée</REMARQUE>
</SALLE>
L’élément h SALLE i contient trois attributs :
1. NO : numéro de la salle ;
2. PLACES : capacité de la salle en nombre de places ;
3. FILMREF : référence vers le film projeté.
Ces trois attributs sont également définis dans une DTD :
Exemple 65 Salle.dtd : DTD pour les salles de cinémas
<!ELEMENT SALLE (SEANCES, REMARQUE?)>
<!ATTLIST SALLE NO ID #REQUIRED
PLACES CDATA #IMPLIED
FILMREF NMTOKEN #REQUIRED >
<!ELEMENT SEANCES (SEANCE)*>
<!ELEMENT SEANCE (#PCDATA)>
<!ELEMENT REMARQUE (#PCDATA)>
On peut voir que l’attribut NO est l’identificateur de la salle.

Remarque : Bien que la référence vers le film contienne l’identificateur d’un élément de type FILM,
elle n’est pas définie comme attribut de type IDREF. Une telle définition aurait comme conséquence
l’obligation de la présence des films dans le même document (ce qui n’est pas le cas). Nous allons revenir
sur cette question plus loin.

Dans cette DTD, on peut également voir la présence d’éléments optionnels (REMARQUE) et d’éléments
répétés (SEANCE). Prenons une première règle de transformation définie pour les éléments de type SALLE
et SEANCE :
4.2. SITE WEB: HTML 173

<xsl:template match="SALLE">
<h2>Salle No <xsl:value-of select="@NO"/></h2>
<h3>Séances</h3>
<ol>
<xsl:apply-template select="SEANCES/SEANCE" />
</ol>
<xsl:for-each select="REMARQUE">
Remarque: <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>

<xsl:template match="SEANCE">
<li><xsl:value-of select="."/></li>
</xsl:template>

Cette règle crée une liste de type ol qui contient le résultat de la transformation des éléments de type
SEANCE : la règle correspondante n’affiche que l’heure de la séance. Pour faire cette transformation, on
aurait également pu construire une boucle xsl:for-each sur toutes les séances, comme pour l’affichage
de la remarque (si elle est présente).
Si on compare à nouveau ce programme avec la DTD des salles (Salle.dtd), on constate que ces deux
« boucles » (rappelons que l’application d’une règle par xsl:template peut toujours être traduite par
une boucle xsl:for-each) correspondent exactement aux éléments répétés (les séances) et à l’élément
optionnel (la remarque).

4.2.5 Création de liens


Nous avons vu comment créer des pages HTML pour les séances et pour les films. Maintenant nous
voudrions relier ces pages par des liens pour créer un réseau hypertexte liant ces pages.
Voici un premier exemple simple de création de liens. Un fichier MesFilms.xml présente pour chaque
film son identificateur, son titre mais également l’URL de la ressource qui contient plus d’information :
Exemple 66 MesFilms.xml : La liste des films

Cette page peut être transformée très facilement en une page HTML qui contient des liens vers les ressources
de tous les films et ceci grâce à l’attribut HREF. Nous montrons uniquement la règle de transformation des
éléments de type FILM :

<xsl:template match="FILM">
<tr><td>
<a href=’{@HREF}’><xsl:value-of select="TITRE"/></a>
</td></tr>
</xsl:template>

Chaque élément h FILM i est traduit en une ligne dans un tableau. Par exemple, la traduction du
premier élément donne le fragment HTML suivant comme résultat :

<tr>
<td><a href="Vertigo.xml">Vertigo</a></td>
</tr>

Le résultat de la transformation complète du fichier MesFilms.xml est montré dans la figure 4.5.
Maintenant nous voudrions créer ce type de lien entre la page HTML qui correspond à une salle et
les pages HTML qui correspondent aux films projetés dans cette salle. C’est un peu plus compliqué,
car les pages XML concernant les salles ne contiennent que des références vers des films, mais n’ont
pas l’information concernant les ressources : il n’est pas possible de déduire le nom de la ressource, par
exemple Vertigo.xml à partir de la référence du film dans Salle1.xml.
174 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

Figure 4.5: Affichage de la liste des films

Pour pouvoir créer ces liens, on est obligé d’accéder en même temps au fichier Salle1.xml et au fichier
MesFilms.xml dans le programme de transformation. C’est possible en utilisant la fonction document() du
langage XPath, qui permet de choisir une ressource comme nouvelle racine pour l’évaluation des étapes
dans une expression XPath. Voici un exemple d’utilisation de cette fonction dans la règle de transformation
d’éléments de type SALLE qui se trouvent dans le document Salle1.xml (ou n’importe quel autre document
satisfaisant la DTD Salle.dtd) :

<xsl:template match="SALLE">
<h2>Salle No <xsl:value-of select="@NO"/></h2>
Film:
<xsl:variable name="filmref" select=’@FILMREF’ />
<xsl:variable name="film"
select="document(’MesFilms.xml’)/LISTEFILM/FILM[@FILMREF=$filmref]" />
<xsl:element name=’a’>
<xsl:attribute name=’href’>
<xsl:value-of select=’$film/@HREF’/>
</xsl:attribute>
<xsl:value-of select="$film/TITRE"/>
</xsl:element>
</xsl:template>

Cette règle définit deux variables. La première, filmref, contient la référence du film dont on cherche le
titre et la ressource. La deuxième trouve ce film dans le document MesFilms.xml par une expression XPath
qui :
g utilise le document MesFilms.xml comme racine ;
g trouve tous les éléments de type FILM dans ce document ;
g filtre parmi ces éléments ceux qui ont un attribut FILMREF dont la valeur est identique à la valeur
de la variable filmref.

Cet élément – il n’y en a qu’un si on définit l’attribut FILMREF comme un identificateur d’éléments
dans le document MesFilms.xml – est ensuite utilisé pour construire un élément de type a qui contient :
g un attribut href dont la valeur est la ressource du film : $film/@HREF ;
g le titre du film : $film/TITRE.
4.2. SITE WEB: HTML 175

4.2.6 XML/XSLT: une solution du problème des liens cassés


Un problème connu dans la création et la maintenance d’un hypertexte de pages HTML est le problème des
liens cassés (dangling links) : tous les internautes ont déjà fait l’expérience du message 404 PAGE NOT
FOUND (ou un message équivalent) quand ils ont voulu suivre un lien dans une page HTML. Ce message
indique que la ressource cible du lien ne peut pas être trouvée sur le serveur web interrogé. Généralement,
le serveur propose soit d’aller à la page d’accueil du serveur, soit d’utiliser le bouton Back (ou Retour) pour
revenir à la page d’origine.
Ce problème apparaît à cause de l’absence d’un contrôle pendant la création de liens qui référencent
directement des ressources physiques. Dans l’exemple précédent, nous avons vu une autre façon de gérer
ce type de lien. Au lieu de référencer les ressources directement par leur URL, nous avons utilisé un fichier
intermédiaire qui implante une sorte de dictionnaire traduisant des adresses logiques (généralement des
identificateurs d’éléments) en adresses physiques. Le fichier MesFilms.xsl correspond à un tel dictionnaire :
il indique pour chaque élément de type FILM dans quel fichier XML on peut le trouver.
Afin de profiter de ce dictionnaire, on peut ensuite créer un programme XSLT qui traduit les références
logiques en adresses de ressources physiques. Voici une règle XSLT qui permet de faire cette résolution :

<xsl:template name="createLinkFilm">
<xsl:param name="filmref" select="inconnu"/>
<xsl:variable name="film"
select="document(’MesFilms.xml’)/LISTEFILM/FILM[@FILMREF=$filmref]" />
<xsl:element name=’a’>
<xsl:attribute name=’href’>
<xsl:value-of select=’$film/@HREF’/>
</xsl:attribute>
<xsl:value-of select="$film/TITRE"/>
</xsl:element>
</xsl:template>

Cette règle prend un identificateur de film comme paramètre et crée un lien vers la ressource correspon-
dante.
Il est possible que cette ressource n’existe pas pour tous les films, c’est-à-dire qu’il n’existe pas
d’élément de type FILM dans le dictionnaire pour la référence donnée. Dans ce cas, on peut définir la
règle suivante, qui retourne la valeur 1 si la ressource existe, et la valeur 0 si elle n’existe pas :

<xsl:template name="testFilm">
<xsl:param name="filmref" select="inconnu"/>
<xsl:choose>
<xsl:when
test="document(’MesFilms.xml’)/LISTEFILM/FILM[@FILMREF=$filmref]">
<xsl:text>1</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>0</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

En utilisant ces deux règles, on peut redéfinir la règle pour les salles de cinéma de la façon suivante :

<xsl:template match="SALLE">
<h2>Salle No <xsl:value-of select="@NO"/></h2>
<xsl:variable name="exists">
<xsl:call-template name="testFilm">
<xsl:with-param name="filmref" select="@FILMREF"/>
176 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

</xsl:call-template>
</xsl:variable>
<xsl:if test="$exists=1">
<h3>Film:
<xsl:call-template name="createLinkFilm">
<xsl:with-param name="filmref" select="@FILMREF"/>
</xsl:call-template>
</h3>
</xsl:if>
</xsl:template>

4.2.7 Intégration de pages XML


Avant de terminer cette section, nous voudrions donner un exemple d’un autre aspect important dans
l’utilisation de XML pour sur la publication web. Cet aspect sera traité plus en détail dans le chapitre 6
consacré aux échanges de données.
Nous avons vu comment on peut créer des liens hypertextes entre des pages XML/HTML en utilisant
des références logiques entre éléments, ainsi que la fonction document() de XPath. Cette création de liens
implante un certain type d’intégration de données. Si nous regardons de plus prêt, nous avons utilisé la
fonction document() pour « mélanger » des données provenant de différents documents : dans l’affichage
d’un lien vers un film, nous avons extrait le titre du film d’un autre document. Nous aurions également pu
importer le résumé des films ou n’importe quelle autre information en utilisant le même mécanisme sous
la seule contrainte qu’il existe un « lien logique » entre les ressources qui puisse être traduit en adresse
physique.
Une autre façon d’intégrer des ressources est l’utilisation des entités XML. Ainsi la résolution des liens
revient au parseur XML qui doit remplacer des références d’entités par leur contenu. Voici un exemple
d’un document qui décrit le cinéma Épée de Bois, et relie cette information aux séances dans ce cinéma :
Exemple 67 EpeeCompl.xml : Cinéma Épée de Bois
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet href="Cinema.xsl" type="text/xsl"?>
<?cocoon-process type="xslt"?>
<!DOCTYPE CINEMA SYSTEM "Cinema.dtd" [
<!ENTITY salle1 SYSTEM "Salle1.xml">
<!ENTITY salle2 SYSTEM "Salle2.xml">
]>
<CINEMA>
<NOM>Epée de bois</NOM>
<ADRESSE>100, rue Mouffetard</ADRESSE>
<METRO>Censier-Daubenton</METRO>
&salle1;
&salle2;
</CINEMA>

La déclaration de DTD contient une référence vers un fichier externe (Cinema.dtd) et la déclaration de
deux entités externes salle1 et salle2 qui correspondent aux éléments de type SALLE décrivant les
deux salles de cinémas, leurs séances et les films projetés. La DTD contient elle-même une référence vers
la DTD des salles :
Exemple 68 Cinema.dtd : DTD pour les cinémas
<!ELEMENT CINEMA (NOM, ADRESSE, METRO, (SALLE)*) >
<!ELEMENT NOM (#PCDATA) >
<!ELEMENT ADRESSE (#PCDATA) >
<!ELEMENT METRO (#PCDATA) >
<!ENTITY % salle-dtd SYSTEM ’Salle.dtd’>
%salle-dtd;
4.3. PRÉSENTATIONS MULTIMÉDIA: SMIL 177

On voit, par cet exemple, comment on peut composer en même temps des documents XML et la
description de leurs structure en utilisant les entités. Cette composition peut même être propagée au
niveau du traitement des données – les programmes XSLT – en utilisant les instructions xsl:import
ou xsl:include décrites dans le chapitre 3 page 115. Voici un programme de transformation de ciné-
mas qui réutilise les règles définies dans le fichier Salle.xsl :
Exemple 69 Cinema.xsl : DTD pour les cinémas
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:import href="Salle.xsl"/>
<xsl:output method="html" encoding="iso-8859-1"/>

<xsl:template match="/">
<html>
<head><title>Programme de <xsl:value-of select="CINEMA/NOM"/></title>
</head>
<body>
<xsl:apply-templates select="CINEMA"/>
</body>
</html>
</xsl:template>

<xsl:template match="CINEMA">
<h1><i><xsl:value-of select="NOM"/> </i> </h1><hr/>
<xsl:value-of select="ADRESSE"/>,
<i>Métro: </i> <xsl:value-of select="METRO"/>
<hr/>

<xsl:apply-templates select="SALLE"/>

</xsl:template>
</xsl:stylesheet>

4.3 Présentations multimédia: SMIL


SMIL est une recommandation W3C et un acronyme pour Synchronised Multimedia Integration Language.
Son nom est prononcé comme le mot anglais smile, qui peut être traduit en Français par « sourire » ou
« souriez ! ».
Comme son nom indique, SMIL est un langage d’intégration et de synchronisation d’objets multimé-
dia. Il permet de créer à partir d’objets numériques (texte, sons, image, vidéo) de nouveaux documents
multimédia qui intègrent ces objets dans l’espace et le temps. On peut ainsi spécifier pour chaque objet
non seulement sa position exacte dans le document, mais également son comportement par rapport aux
autres objets et aux paramètres du média d’affichage (taux de transfert des données, langue de préférence,
préférences utilisateur, etc).
Pour le moment, les navigateurs web standard comme Netscape ou Internet Explorer on besoin d’une
application externe capable d’interpréter les balises SMIL correctement. Parmi ces applications nous pou-
vons citer RealPlayer (version gratuite disponible) de RealNetworks (TM), ainsi que le produit GRiNS
qui fournit un environnement de création de documents SMIL, et l’applet gratuite SOJA 1.0 Cherbourg de
Helio.

4.3.1 SMIL par un exemple


Comme XHTML et WML, un document SMIL est un document XML. Nous décrivons la version 1.0
de SMIL (au moment de la rédaction de ce document, la version 2.0 de SMIL est encore au stade de la
178 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

proposition).
Le fichier ExSimple.smil est un document multimédia intégrant trois composants :
1. un fichier audio Sound.wav qui dure 2.1 secondes ;
2. l’affiche française du film Vertigo stockée dans le fichier Vertigo.png de 170x240 pixels ;
3. et un fichier texte TexteVertigo.txt.
Exemple 70 ExSimple.smil : Un fichier SMIL simple
<smil>
<head>
k
<meta name="title" content="Exemple simple d’un fichier SMIL" />
<meta name="author" content=" c 2001 Sallesenligne.com" />
<layout>
<root-layout width="450" height="600" />
<region id="reg_img_grand" width="400" height="300" left="25" top="25" fit="meet" />
<region id="reg_img_petit" width="200" height="125" left="125" top="75" fit="meet" />
<region id="reg_texte" width="350" height="325" left="50" top="250" />
</layout>
</head>
<body>
<seq>
<par endsync="first" id="page1" >
<audio src="Sound.wav" />
<a href="#page2" >
<img src="Vertigo.png" region="reg_img_grand" />
</a>
</par>
<par id="page2" dur="30s" >
<text src="Vertigo-Resume.txt" region="reg_texte" />
<img src="Vertigo.png" region="reg_img_petit" />
</par>
</seq>
</body>
</smil>

Structure générale d’un document SMIL


La structure générale d’un document SMIL ressemble à la structure d’un document XHTML avec un en-
tête et un corps représentés respectivement par les balises h head i et h body i . Comme dans XHTML,
l’en-tête h head i permet de spécifier des informations sur le document sous forme d’éléments de type
meta, mais il sert surtout à spécifier les paramètres « visuels » du document multimédia par un élément
de type root-layout et à découper l’espace d’affichage en plusieurs régions rectangulaires par des
éléments de type region) :
g La fenêtre a une taille de 450x600 pixels spécifiée par les attributs width et height dans l’élément
de type root-layout.
g Les dimensions de la région reg_img_grand sont de 400x300 pixels et cette région est décalé
de 25 points vers la droite (left) et de 25 points vers le bas (top). La valeur de l’attribut fit
indique que la taille du composant affiché dans cette région doit être adaptée à la taille de la région
sans déformation, c’est-à-dire en conservant le rapport largeur/longueur du composant.
g La région reg_img_petit a une taille de 200x125 pixels et est déplacée de 125 pixels vers la
droite et de 75 pixels vers le bas.
g La région reg_texte a une taille de 350x325 pixels et est déplacée de 50 pixels vers la droite et
de 250 pixels vers le bas.
4.3. PRÉSENTATIONS MULTIMÉDIA: SMIL 179

reg_img_grand
reg_img_petit

600 pixels
reg_texte

450 pixels

Figure 4.6: Placement des régions dans le document ExSimple.smil

La figure 4.6 illustre le placement de ces différentes régions dans le document.


L’élément de type body spécifie ensuite le contenu proprement dit, c’est-à-dire les différents com-
posants, leur placement dans les régions d’affichage et leur synchronisation dans le temps. Les composants
sont représentés par des éléments de « placement » de type audio, img et text. Ces types d’éléments
correspondent aux différents types de médias utilisés dans un document multimédia. SMIL définit en tout
sept types de médias (tableau 4.4).

Média Utilisation
text composant textuel
image image statique
audio composant sonore
video séquence vidéo
textstream texte à déroulement automatique
animation composant animation
ref composant d’un autre type

Table 4.4: Les différents types de média SMIL

Positionnement des composants


De même qu’une image dans un document XHTML n’est pas incluse dans le document mais référencée
par un élément de type img, chaque élément de placement ne contient pas le contenu du composant,
mais des références sous forme d’attributs src. Néanmoins, la comparaison s’arrête là : contrairement
à un élément de type img dans HTML, qui indique par sa position même le placement de l’image dans
le document, un élément de placement dans SMIL spécifie explicitement le placement par une référence
vers une région définie dans l’en-tête du document. Par exemple, l’image Vertigo.png est placée une
première fois dans la région reg_img_grand et une deuxième fois dans la région reg_img_petit.
180 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

Le texte TexteVertigo.txt est placé dans la région reg_texte et le fichier audio Sound.wav n’a
pas de placement spatial (la version 2.0 propose la possibilité de contrôler le volume pendant l’écoute d’un
fichier audio mais nous n’avons pas trouvé d’indication sur la possibilité de contrôler le volume sur les
différents haut-parleurs dans un environnement multi-phonique).
L’arbre DOM du contenu (élément racine) du document est donné dans la figure 4.7.

Element
seq

Element
par

Attr Attr Element Element Element


id
page1
endsync
audio a par
first

Attr Attr Element Attr Attr Element Element


href href id dur
Sound.wav #page2
img page2 30s
text img

Attr Attr Attr


href href href
Vertigo.png Vertigo-Resume.txt Vertigo.png

Figure 4.7: Arbre DOM avec éléments SMIL

Le positionnement temporel des composants du document est décrit en utilisant une combinaison de
quatre modèles de synchronisation proposés par SMIL :
1. Synchronisation par composition : deux types d’éléments de « synchronisation » permettent de re-
grouper différents composants en séquences (seq) et en « groupes parallèles » (par) qui se traduisent
respectivement par un affichage séquentiel ou parallèle des composants.
Par exemple, le fichier ExSimple.smil définit deux groupes parallèles (éléments de type par avec
les identificateurs page1 et page2). Le premier groupe (page1) joue le son dans le fichier
Sound.wav et affiche en même temps l’image Vertigo.png. Le groupe page2 affiche en
même temps l’image et le texte dans le fichier TexteVertigo.txt.
La combinaison répétée d’éléments de synchronisation permet de constituer des composants multi-
média de plus en plus complexes : le sous-élément seq définit une séquence qui affiche d’abord le
groupe page1 suivi du groupe page2.
2. Synchronisation par événement interne : le déroulement temporel de l’affichage de différents com-
posants est contrôlé par des événements internes comme par exemple le début ou la fin de l’affichage
d’un autre composant. Ce type de synchronisation est implanté sous forme de plusieurs attributs qui
peuvent être utilisés dans les éléments de placement et les éléments de synchronisation.
Par exemple, l’attribut endsync dans le groupe parallèle page1 du document ExSimple.smil syn-
chronise la fin de l’affichage de ce groupe par la fin de son premier sous-élément (l’affichage de la
page 1 dure aussi longtemps que le son dans le fichier Sound.wav).
4.3. PRÉSENTATIONS MULTIMÉDIA: SMIL 181

3. Synchronisation par horloge : une horloge permet de spécifier le début, la fin et la durée de l’affichage
d’un objet. Par exemple, la durée de la deuxième page est fixée à 10 secondes par l’attribut dur.
4. Synchronisation par l’utilisateur : l’utilisateur peut également intervenir dans le déroulement d’un
document SMIL. Cette intervention correspond à l’activation d’un lien hypertexte vers un composant
du même document ou d’une autre ressource Web. Cette ressource peut évidemment être aussi un
document SMIL.
Dans le document ExSimple.smil, l’élément de type a crée un lien entre l’image affichée et le groupe
page2. En « cliquant » sur l’image, l’utilisateur peut passer à la deuxième page avant la fin du son
stocké dans le fichier Sound.wav.
La combinaison de ces quatre modèles de synchronisation permet de spécifier des documents multimé-
dia très complexes. Avant de créer un document SMIL, il est donc conseillé de spécifier un ou plusieurs
scénarios d’affichage. S SMIL n’est peut-être pas le meilleur langage pour faire une telle spécification, nos
quelques expériences avec ce langage nous ont montré que les éléments de synchronisation seq et par
fournissent une façon relativement simple et déclarative de création de document multimédia.
Dans la suite, nous donnons un petit résumé de la DTD SMIL et montrons comment on peut exploiter
un ou plusieurs documents XML pour la création de documents SMIL.

4.3.2 DTD SMIL


L’élément racine d’un document SMIL est de type smil et contient une en-tête de type head optionnel et
un corps de type body également optionnel :
<!ELEMENT smil (head?,body?)>
Voici le plus petit document multimédia SMIL :
<smil/>

Entête : Mise-en-page
L’entête contient zéro ou plusieurs éléments h meta i et au moins un élément de type layout ou de type
switch :
<!ELEMENT head (meta*,((layout|switch), meta*))?>
Les éléments meta sont définis et utilisés de la même manière que les éléments du même type dans
HTML.

Balise h layout i : Cette balise permet de faire la mise en page de la présentation SMIL. La DTD
SMIL n’est pas très explicite sur le contenu un élément de ce type :
<!ELEMENT layout ANY>
On peut dire sans trop s’aventurer qu’un élément de type layout contient généralement un élément
de type root-layout, qui permet de spécifier la mise en page globale de la fenêtre de présentation, et
un ou plusieurs éléments de type region. Tous ces éléments sont vides et utilisent des attributs pour
spécifier les propriétés de la fenêtre et des différentes région qu’elle contient.
Parmi ces attributs, on trouve les attributs height, width et background-color qui sont rassem-
blés par une entité générale nommé viewport-attrs :

<!ENTITY % viewport-attrs "


height CDATA #IMPLIED
width CDATA #IMPLIED
background-color CDATA #IMPLIED
">
182 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

Ainsi la balise h root-layout i est définie de la manière suivante (pour simplifier la présentation
nous ne présentons qu’une partie des attributs définis dans la DTD SMIL) :
<!ELEMENT root-layout EMPTY>
<!ATTLIST root-layout %viewport-attrs; >
Par exemple l’élément suivant définit d’une manière conforme à la DTD SMIL une fenêtre de présen-
tation de 300x400 pixels :
<root-layout width="300" height="400"/>
Les éléments h region i , qui sont également vides, permettent de définir la dimension et la position
de différentes régions dans la fenêtre de présentation :
<!ELEMENT region EMPTY>
<!ATTLIST region
id ID #IMPLIED
%viewport-attrs;
left CDATA "0"
top CDATA "0"
z-index CDATA "0"
fit (hidden|fill|meet|scroll|slice) "hidden"
>
On voit que chaque région peut être identifiée par un attribut id, ce qui sera utile pour relier plus tard
un ou plusieurs composants à une région. La dimension d’une région est spécifiée par les mêmes attributs
que la dimension de la fenêtre de présentation. La position d’une région est caractérisée par trois attributs
qui correspondent aux trois dimensions d’affichage :
1. l’attribut left permet de spécifier le nombre de pixels entre la région et le bord gauche de la fenêtre.
Il peut également spécifier un décalage en pourcentage de la largeur de la fenêtre.
2. l’attribut top permet de spécifier le nombre de pixels entre la région et le bord supérieur de la
fenêtre. Il est possible également de spécifier un décalage en pourcentage de la largeur de la fenêtre.
3. l’attribut z-index définit la « troisième » dimension. Quand deux objets sont affiché dans deux
régions qui se recouvrent, il faut décider lequel des deux objets sera complètement visible et lequel
sera partiellement couvert par l’autre. Ce conflit est résolu de la manière suivante :
g si les deux régions ont une valeur identique pour l’attribut z-index, ce sera l’objet dont
l’affichage a été déclenché le dernier qui aura la priorité. Quand les deux objets sont affichés en
même temps, c’est le dernier dans l’ordre du document SMIL qui sera affiché complètement.
g sinon c’est la région avec la valeur supérieure pour l’attribut z-index qui recouvrera l’autre
région.
Exemples :
g La dimension de la région reg_texte1 est de 300x50 pixels, elle est déplacée de 50 pixels vers la
droite et 120 pixels vers le bas.
<region id="reg_texte1"
width="200" height="50"
left="50" top="120"
z-index="1"/>
g La région reg_img_grand fait 300x400 pixels et le contenu affiché sera redimensionné sans dé-
formation. Cette région se trouve « en dessous » de la région précédente (z-index est égal à 0 par
défaut).
<region id="reg_img_grand"
width="300" height="400"
fit="meet"/>
4.3. PRÉSENTATIONS MULTIMÉDIA: SMIL 183

Élément h body i : contenu


Le contenu d’une page SMIL est spécifié par le contenu de l’élément h body i .
<!ELEMENT body (audio|video|text|img|animation|textstream|ref|
par|seq|
a|
switch)*>
La DTD définit le contenu d’un document par une séquence de onze types de fils différents qui peuvent
être regroupés en quatre groupes :
1. les éléments de positionnement: h audio i , h video i , h text i , h img i , h animation i ,
h textstream i , h ref i ;
2. les éléments de synchronisation h seq i et h par i ;
3. les liens hypertextes: h ai ;
4. les éléments de choix de qualité de service par rapport aux paramètres système du réseau et du client :
h switch i
Voici la définition plus détaillée de ces différents éléments.

Éléments de positionnement
Le rôle principal des éléments de positionnement est de placer le contenu des différents composants du
document dans les différentes régions spécifiées dans l’en-tête et de décrire leur comportement pendant le
« déroulement » du document.
Les attributs des éléments de positionnements sont définis dans l’entité suivante :
<!ENTITY % mo-attributes "
id ID #IMPLIED
region IDREF #IMPLIED
src CDATA #IMPLIED
dur CDATA #IMPLIED
repeat CDATA ’1’
fill (remove|freeze) ’remove’
begin CDATA #IMPLIED
end CDATA #IMPLIED
">
g src : spécifie la ressource (le contenu) à afficher dans cet élément de placement (un ressource peut
être affichée à différentes endroit en même temps) ;
g id : permet d’identifier l’élément de positionnement ;
g region : spécifie la région où le contenu sera affiché ;
g repeat : le nombre de répétitions de l’affichage (par exemple pour un fichier audio, qui peut être
joué en boucle) ;
g fill : le mode de remplissage de la région quand l’affichage de la ressource est terminée . La valeur
par défaut est remove, ce qui signifie que la région efface le contenu et reprend sa couleur de fond.
La valeur freeze indique que le contenu reste affiché (par exemple la dernière image dans une
vidéo ou une séquence d’images statiques).
g dur : la durée d’affichage ;
g begin : le début d’affichage ;
184 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

g end : la fin d’affichage.

Exemple 71 g Le fichier texte Alien-Info.txt est affiché dans la région reg_texte2 pendant
5 secondes :

<text src="Alien-Info.txt" region="reg\_texte2" dur="5s"/>


g L’extrait video du film est affiché dans la région reg_video1 par un élément de placement clip
de type video. La dernière image restera figée sur l’écran après la fin de l’extrait :

<video id="clip" src="Alien-Clip.mov" region="reg\_video1" fill="freeze"/>


g Le résumé du film sera affiché dans la region reg_texte3 au début de la vidéo présentée par
l’élément de placement avec l’identificateur clip :

<text src="Alien-Resume.txt" region="reg\_texte3" begin="id(clip)(begin)"/>

L’affichage des composants qui correspondent à un média continu (audio, animation, textstream, vidéo)
peut être contrôlé par deux attributs supplémentaires qui permettent de choisir un intervalle dans le contenu
du composant à afficher :
<!ENTITY % clip-attrs "
clip-begin CDATA #IMPLIED
clip-end CDATA #IMPLIED
">

Exemple 72 L’extrait affiché du clip Alien-Clip.mov commence 5 secondes après le début :


<video src="Alien-Clip.mov" region="reg\_video1" clip-begin="5s"
fill="freeze"/>
On peut également observer que l’attribut fill est égal à freeze, ce qui signifie que la dernière image
du clip restera affichée après la fin.

Éléments de synchronisation
Les balises h par i et h seq i ont le même modèle de contenu que l’élément h body i , mais permettent
l’utilisation d’attributs supplémentaires pour la synchronisation :
<!ATTLIST par id ID #IMPLIED
endsync CDATA "last"
dur CDATA #IMPLIED
repeat CDATA "1"
region IDREF #IMPLIED
begin CDATA #IMPLIED
end CDATA #IMPLIED
>
La signification de ces attributs est la suivante :
g endsync : cet attribut peut prendre comme valeur les chaînes first et last ou un identificateur
d’un élément fils du groupe ce qui indique respectivement que le groupe se termine à la fin du premier
fils, du dernier ou de celui référencé. Cela correspond à une synchronisation par événement.
g dur : spécifie la durée du groupe en temps réel (en heures, minutes et/ou secondes). Cela correspond
à une synchronisation par horloge ;
g repeat : indique combien de fois le groupe doit être affiché (boucle) ;
4.3. PRÉSENTATIONS MULTIMÉDIA: SMIL 185

g region : indique la région d’affichage ;


g begin et ends : indique le début et la fin de l’affichage. Ces valeurs peuvent être indiquées en
durée réelle par rapport au début du parent (synchronisation par horloge) ou par une expression
id(ref)(begin) ou id(ref)(end) où ref correspond à un autre élément du contenu (syn-
chronisation par événement).

Exemple 73 Le groupe parallèle de deux éléments h audio i et h img i se termine à la fin de l’affichage
du premier élément (l’image sera affichée pour la durée de l’extrait sonore dans Sound.wav) :

<par endsync="first">
<audio src="Sound.wav"/>
<img src="Alien.png" region="reg_img_grand"/>
</par>

Element
par

Attr Element Element


endsync
first
audio img

Attr Attr Attr


src src region
Sound.wav Alien.png reg_img_grand

Figure 4.8: Arbre DOM avec éléments SMIL

Exemple 74 Voici un exemple un peu plus compliqué :

<seq>
<par endsync="first">
<audio src="Sound.wav"/>
<a href="#page2">
<img src="Vertigo.png" region="reg_img_grand"/>
</a>
</par>
<par id="page2">
<text src="Vertigo-Title.txt" region="reg_texte1" fill="freeze"/>
<text src="Vertigo-Info.txt" region="reg_texte2"/>
<text src="Vertigo-Resume.txt" region="reg_texte3" begin="2s"/>
<seq>
<img src="IMG/Vertigo1.png" region="reg_img_petit" dur="5s"/>
<img src="IMG/Vertigo2.png" region="reg_img_petit" dur="5s"/>
</seq>
</par>
</seq>
186 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

Element
seq

Element Element
par par

Attr Element Element Attr Element Element Element Element


endsync
audio a id
page2
text text text seq
first

Attr Element Element Element


href
#page2
img img img

Figure 4.9: Arbre DOM avec éléments SMIL

Cet extrait définit une séquence de deux groupes parallèles. Le premier groupe affiche – pour la durée
du sons dans le fichier Sound.wav l’image Vertigo.png, tandis que le deuxième affiche trois fichiers
de texte en même temps qu’une séquence d’images.
La figure 4.10 montre trois copies d’écran dans l’ordre chronologique du déroulement de cette séquence.
On peut remarquer que le titre Vertigo-Title.txt est resté affiché à la fin à cause de l’attribut fill
qui est égal à freeze dans son élément de placement.

Figure 4.10: Déroulement d’une séquence SMIL

Paramètres d’environnement: h switch i


La balise h switch i permet de prendre en compte les paramètres du réseau et du client d’affichage.

Exemple 75 Par exemple, l’élément h switch i suivant prend en compte la taille de l’écran pour choisir
entre trois versions à différentes résolutions d’une même image ;
4.3. PRÉSENTATIONS MULTIMÉDIA: SMIL 187

<switch>
<par system-screen-size="640x480">
<img src="img_faible.gif" region="reg_img" />
</par>
<par system-screen-size="800x600">
<img src="img_moyen.gif" region="reg_img" />
</par>
<par system-screen-size="1024x768">
<img src="img_haut.gif" region="reg_img" />
</par>
<text src="sorry.txt" region="reg_text_msg" />
</switch>

Si aucun paramètre peut être satisfait, le texte sorry.txt sera affiché.

SMIL fournit une multitude d’autres mécanismes pour la création de documents multimédia. Il est
possible de créer et de sélectionner des sous-régions et intervalles temporels sur/pendant lesquels des liens
vers d’autres ressources sont actifs. On peut également définir différents liens sur différentes régions d’une
image, ou des liens qui sont accessibles seulement pendant un certain temps.

4.3.3 Génération de présentations SMIL


Comme nous l’avons déjà souligné, l’intérêt du couple XML/XSLT est la possibilité de publier le contenu
dans un document XML sous différentes formes. Pourquoi pas créer alors une présentation SMIL à partir
du contenu d’un document XML.
À priori cette tâche semble similaire à la génération de pages HTML décrite dans la section 4.2. Si on
y regarde de plus près, on remarque quelques différences importantes entre SMIL et HTML :
g Un SMIL est ne contient pas les données affichées à l’écran, mais sert comme cadre de présentation
pour des données qui se trouvent dans d’autres ressources. Dans ce sens, il est préférable d’utiliser
le terme présentation SMIL à la place de document. Un document XML n’est alors pas simplement
transformé en un autre document conforme à la DTD SMIL, mais doit fournir les composants qui
seront affichés par la présentation SMIL.
g Une présentation SMIL inclut généralement des composants qui ne sont pas dans un format XML et
le document XML ne correspond généralement qu’à une partie des composants de la présentation.

Pour illustrer ces différents aspects, nous allons montrer comment on peut générer une présentation
SMIL à partir des documents XML sur les films projetés par le cinéma L’Épée de Bois. Un document sur
le film Sleepy Hollow est le fichier 76 ;

Exemple 76 SleepyHollow.xml : Fichier XML pour le film Sleepy Hollow

<?xml version="1.0" encoding="ISO-8859-1"?>


<FILM FILMID=’3’>
<TITRE>Sleepy Hollow</TITRE>
<AUTEUR>Tim Burton</AUTEUR>
<ANNEE>1999</ANNEE>
<GENRE>Fantastique</GENRE>
<PAYS>Etats Unis</PAYS>
<RESUME>

Nouvelle Angleterre, 1799. A Sleepy Hollow, plusieurs cadavres


sont retrouvés décapités. La rumeur attribue ces meurtres à un
cavalier lui-même sans tête. Mais le fin limier new-yorkais
Ichabod Crane ne croit pas en ses aberrations. Tombé sous le
charme de la vénéneuse Katrina, il mène son enquête au coeur
188 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

des sortilèges de Sleepy Hollow..


</RESUME>
</FILM>

Voici la présentation SMIL que nous voudrions créer :

Exemple 77 SleepyHollow.smil : Fichier SMIL pour la présentation du film Sleepy Hollow

<?xml version="1.0" encoding="utf-8"?>


<smil>
<head>
<meta name="title" content="Presentation SMIL du film Sleepy HÃ c llow"/>
k
<meta name="author" content="(c) 2001 Sallesenligne.com"/>
<layout>
<root-layout width="300" height="400"/>
<region id="reg_img_grand" width="300" height="400" fit="meet"/>
<region id="reg_img_petit" width="150" left="80" height="100" top="10"/>
<region id="reg_texte1" width="200" left="50" height="50" top="120" fit="meet"/>
<region id="reg_texte2" width="200" left="50" height="50" top="180"/>
<region id="reg_texte3" width="250" left="25" height="150" top="240"/>
</layout>
</head>
<body>
<par>
<text src="Sleepy-Title.txt" region="reg_texte1" fill="freeze"/>
<text src="Sleepy-Info.txt" region="reg_texte2"/>
<text src="Sleepy-Resume.txt" region="reg_texte3" begin="2s"/>
<seq>
<img src="IMG/mmedia_photo.png" region="reg_img_petit" dur="5s"/>
<img src="IMG/2_1tn.png" region="reg_img_petit" dur="5s"/>
<img src="IMG/2_2tn.png" region="reg_img_petit" dur="5s"/>
<img src="IMG/2_3tn.png" region="reg_img_petit" dur="5s"/>
</seq>
</par>
</body>
</smil>

Cette présentation contient trois composants de type Text :


g Sleepy-Title.txt contient le tire du film ;
g Sleepy-Info.txt contient l’auteur, l’année, le genre et le pays ;
g Sleepy-Resume.txt contient le résumé du film.

Ces trois contenus textuels sont affichés dans trois régions différentes en même temps qu’une séquence
de quatre images. Avant de voir comment ce document et tous ces composants ont été générés, regardons
de plus près le contenu de chaque fichier texte.
Voici le fichier qui contient le titre du film :

Exemple 78 Sleepy-Title.txt : Fichier avec le titre du film

<window type="marquee" height="50" width="200" bgcolor="black">


<font size="50" face="Garamond" color="red">Sleepy Hollow</font>
</window>

Ce fichier ne contient pas uniquement le titre, mais est lui-même un fichier XML. Le format utilisé
dans ce fichier s’appelle RealText et est proposé par la société RealNetworks.
4.3. PRÉSENTATIONS MULTIMÉDIA: SMIL 189

Remarque : SMIL ne spécifie pas le format du contenu textuel des fichiers et le format RealText est un
format spécifiquement défini pour une gamme de produits d’une société.

Comm HTML, les fichiers RealText permettent de spécifier la présentation du texte en utilisant des
balises. Parmi les balises les plus importantes, nous pouvons citer :
g h window i : cette balise permet, entre autre, de spécifier le type d’affichage utilisé (attribut type),
les dimensions de la fenêtre de texte (la taille de cette fenêtre doit être inférieure ou égale à aux
dimensions de la région SMIL dans laquelle elle est affiché), la couleur du fond et des liens, etc...
g h font i : permet de spécifier des caractéristiques de la police utilisée pour le texte qu’elle contient
(couleur, taille, etc.).
g h ai : permet de créer des liens vers d’autres ressources, comme l’élément du même type en HTML.
D’autres balises, reprises de la DTD XHTML, comme h center i , h br i et h p i permettent de
mettre en page le texte.
Les balises dans le fichier 78 spécifient que le titre du film est affiché dans une fenêtre de 200x50 pixels,
le texte est affiché centré, en rouge avec une police Garamond et une taille de 50 pixels.
Le titre est affiché dans une fenêtre de type marquee, ce qui signifie que le texte se déroule horizon-
talement de droite à gauche. RealText distingue entre cinq type d’affichage d’un texte :
g generic : affichage générique sans paramètres prédéfinis ;
g marquee : le texte se déroule horizontalement (de droite à gauche par défaut) et est positionné au
milieu de la fenêtre ;
g tickertape : le texte se déroule verticalement (de droite à gauche par défaut) et est positionné en haut
ou en bas de la fenêtre ;
g scrollingnews : le texte se déroule verticalement (du bas vers le haut par défaut) ;
g teleprompter : le texte est affiché comme dans l’affichage générique mais le nouveau texte « pousse »
l’ancien vers le haut.

Voici le fichier RealText pour l’affichage des informations sur le film :


Exemple 79 Sleepy-Info.txt : Information sur le film Vertigo

<window type="marquee" height="50" width="200" bgcolor="black" link="blue">


<font color="white">
de Tim Burton, Fantastique, Etats Unis, 1999, <a href="http://www.sallesenligne.com/films/Slee
low</a>
</font>
</window>

Les informations se déroulent également de droite à gauche. Il contient également un lien vers le fichier Sleepy-
Hollow.xml (on aurait pu évidement choisir n’importe quel URL comme cible de ce lien).
Le résumé se déroule verticalement (scrollingnews) dans une fenêtre de 250x100 pixels en jaune sur un
fond noir :
Exemple 80 Vertigo-Resume.txt : Résumé du film Vertigo

<window type="scrollingnews" height="100" width="250" bgcolor="black">


<font color="yellow">
190 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

Scottie Ferguson, ancien inspecteur de police, est sujet au


vertige depuis qu’il a vu mourir son collègue. Elster, son ami,
le charge de surveiller sa femme, Madeleine, ayant des
tendances suicidaires. Amoureux de la jeune femme Scottie ne
remarque pas le piège qui se trame autour de lui et dont il va
être la victime...

</font>
</window>

Figure 4.11: Copie d’écran de la présentation SleepyHollow.smil

Génération de composants RealText


La génération de ces différents composants RealText n’a plus de secret pour les programmeurs XSLT
expérimentés que nous sommes maintenant.
Voici la première règle pour la génération du fichier Sleepy-Title.txt ;

<xsl:template match="FILM">
<window type="marquee" height="50" width="200" bgcolor="black">
<font size="50" face="Garamond" color="red">
<xsl:value-of select="TITRE"/>
</font>
4.3. PRÉSENTATIONS MULTIMÉDIA: SMIL 191

</window>
</xsl:template>
Cet règle, qui s’applique aux éléments de type FILM, crée les balises RealTime pour le formattage du
texte et insère le titre du film. Il suffit de créer une feuille de style complète avec cette règle et le résultat
de la transformation XSLT pourra être mis dans le fichier Sleepy-Title.txt.
La règle suivante affiche les informations sur le film :
<xsl:template match="FILM">
<window type="marquee" height="50" width="200" bgcolor="black" link="blue">
<font color="white">
de <xsl:value-of select="AUTEUR"/>,
<xsl:value-of select="GENRE"/>,
<xsl:value-of select="PAYS"/>,
<xsl:value-of select="ANNEE"/>
</font>
</window>
</xsl:template>
Cette règle est correcte mais ne génère pas exactement le contenu du fichier Sleepy-Info.xml plus haut.
Voici le texte qu’elle génère :

<window type="marquee" height="50" width="200" bgcolor="black" link="blue">


<font color="white">
de Tim Burton,
Fantastique,
Etats Unis,
1999
</font>
</window>

Au lieu d’écrire toutes les informations dans une seule ligne, chaque « champ » commence par une nouvelle
ligne. Nous avons vu que ceci n’est pas génant dans l’affichage d’une page HTML par un navigateur qui
remplace tous les espaces par un seul caractère. RealPlayer ne fait pas la même chose : pendant l’affichage
de ce texte les différents champs seront séparés par des espaces plus longs qu’un seul caractère, ce qui n’est
pas un résultat souhaitable. Il existe deux solutions à ce problème :
1. La première est d’écrire la règle de la manière suivante :

<xsl:template match="FILM">
<window type="marquee" height="50" width="200" bgcolor="black" link="blue">
<font color="white">
de <xsl:value-of select="AUTEUR"/>, <xsl:value-of select="GENRE"/>,
<xsl:value-of select="PAYS"/>, <xsl:value-of select="ANNEE"/>
</font>
</window>
</xsl:template>

On a réduit les espaces blancs en faveur de la lisibilité du programme XSLT.


2. La deuxième est d’exploiter le fait que XSLT supprime tous les noeuds de type Text qui ne contien-
nent qu’un espace blanc. Ainsi, en séparant les virgules après chaque champs de l’espace blanc qui
suit, ces espaces seront supprimés. Pour cela, on utilise l’instruction xsl:text :

<xsl:template match="FILM">
<window type="marquee" height="50" width="200" bgcolor="black" link="blue">
192 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

<font color="white">
de <xsl:value-of select="AUTEUR"/><xsl:text>, </xsl:text>
<xsl:value-of select="GENRE"/><xsl:text>, </xsl:text>
<xsl:value-of select="PAYS"/><xsl:text>, </xsl:text>
<xsl:value-of select="ANNEE"/><xsl:text>, </xsl:text>
</font>
</window>
</xsl:template>

Maintenant les espaces qui se trouvent entre les éléments h xsl:text i et h xsl:value i seront
supprimés pendant la sérialisation de l’arbre résultat. Nous allons détailler l’instruction h xsl:text i
dans la section 4.4.2.
Finalement, la dernière règle est la suivante :
<xsl:template match="FILM">
<window type="scrollingnews" height="100" width="250" bgcolor="black">
<font color="yellow">
<xsl:value-of select="RESUME"/>
</font>
</window>
</xsl:template>
En prenant en compte toutes les remarques précédentes, on peut supposer que cette règle est correcte.
Le seul problème est que le résumé contient des caractères latins utilisant le codage ISO-8859-1 et que
le texte généré contient également ce codage. Pour pas avoir des caractères illisibles nous sommes obligés
de définir le codage en utilisant l’instruction xsl:output :

<xsl:output method="xml" encoding="ISO-8859-1" />

Éclatement d’un document XML


Bien que nous ayons supposé que chaque fichier RealText est généré par un programme XSLT différent, on
peut définir également un seul programme avec des paramètres qui permettent de choisir la transformation
souhaitée. Néanmoins, on est obligé de faire pour chaque fichier une demande de transformation, car la
version 1.0 de XSLT ne permet de produire qu’un seul document par transformation.
Ceci n’est pas un problème dans un environnement où on peut créer des scripts ou programmes simples
pour automatiser ce processus, mais ça le devient rapidement. La version 1.1 de XSLT et la plupart des
processeurs XSLT actuels (qui sont conformes à la version 1.0) proposent des extensions pour pouvoir créer
plusieurs documents par une seule demande de transformation. Cette extension s’appelle xsl:document
(page 266), saxon:output dans le processeur Saxon et xalan:rewrite dans le processeur Xalan.
Ainsi il est possible de définir des règles dont résultat n’est pas inclus dans l’arbre (et le document) pro-
duit par la feuille de style mais stocké dans des fichiers différents. Voici un exemple basé sur le processeur
XSLT Saxon. La règle crée deux fichiers RealText {$prefix}Titre.txt et {$prefix}Info.txt
où $prefix est un paramètre de règle :
<xsl:template name="genTitreInfo">
<xsl:param name="prefix" value="unknown.txt"/>
<saxon:output file="{$prefix}Titre.txt" omit-xml-declaration="yes" >
<window type="marquee" height="50" width="200" bgcolor="black">
<font size="50" face="Garamond" color="red">
<xsl:value-of select="TITRE"/>
</font>
</window>
</saxon:output>
<saxon:output file="{$prefix}Info.txt" omit-xml-declaration="yes" >
4.3. PRÉSENTATIONS MULTIMÉDIA: SMIL 193

<window type="marquee" height="50" width="200"


bgcolor="black" link="blue" indent="no">
<font color="white">
de <xsl:value-of select="AUTEUR"/><xsl:text>, </xsl:text>
<xsl:value-of select="GENRE"/><xsl:text>, </xsl:text>
<xsl:value-of select="PAYS"/><xsl:text>, </xsl:text>
<xsl:value-of select="ANNEE"/><xsl:text>, </xsl:text>
</font>
</window>
</saxon:output>
</xsl:template>

Les attributs de l’instruction saxon:output sont essentiellement les mêmes que les attributs de l’élément
du premier niveau xsl:output.

Génération du fichier SMIL

Après avoir généré les différents composants RealText à partir du contenu du document XML Sleepy-
Hollow.xml, nous voulons maintenant créer le fichier SMIL final qui est composé de quatre autres
composants images qui n’ont pas de relation directe avec le document XML déjà transformé. Afin de
pouvoir utiliser le même programme pour la transformation d’autres fichiers XML sur les films, il n’est
pas possible de spécifier ces ressources images explicitement dans le programmes sous forme d’éléments
littéraux.
Une meilleure solution est de définir un document XML qui contient les paramètres manquants pour
la génération de la présentation finale. Voici un exemple d’un tel document de « paramètres » qui indique
pour chaque film les ressources disponibles :

Exemple 81 ParamsSMIL.xml : Paramètres pour la génération de la présentation

<?xml version="1.0" encoding="ISO-8859-1"?>


<SMILPARAMS>
<PARAM FILMREF="1" PREFIX="Vertigo-" RESOURCE="Vertigo.xml">
<PHOTOS>
<PHOTO HREF="IMG/Vertigo1.png"/>
<PHOTO HREF="IMG/Vertigo2.png"/>
</PHOTOS>
</PARAM>
<PARAM FILMREF="2" PREFIX="Alien-" RESOURCE="Alien.xml" />
<PARAM FILMREF="3" PREFIX="Sleepy-"
RESOURCE="http://www.sallesenligne.com/films/SleepyHollow.xml">
<PHOTOS>
<PHOTO HREF="IMG/mmedia_photo.png"/>
<PHOTO HREF="IMG/2_1tn.png"/>
<PHOTO HREF="IMG/2_2tn.png"/>
<PHOTO HREF="IMG/2_3tn.png"/>
</PHOTOS>
</PARAM>
</SMILPARAMS>

Le film Sleepy Hollow correspond au troisième film (FILMREF=3) et donne pour ce film un préfixe
pour les noms de fichiers RealText qui seront générés par les règles précédent, une URL pour une ressource
Web à référencer dans la présentation (lien dans le fichier Sleepy-Info.txt) et quatre URL pour récupérer
des photos sur le film. Voici le programme XSL pour la génération du document SMIL :

Exemple 82 GenSMIL.xsl : Feuille de style pour la génération du document SMIL


194 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

<?xml version="1.0" encoding="ISO-8859-1"?>


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>

<xsl:output method="xml" indent="yes" media-type="text/smil"/>

<xsl:template match="/">
<smil>
<head>
<meta name="title" content="Presentation SMIL du film {FILM/TITRE}"/>
<meta name="author" content="(c) 2001 Sallesenligne.com" />
<layout>
<root-layout width="300" height="400" />
<region id="reg_img_grand"
width="300" height="400" fit="meet" />
<region id="reg_img_petit"
width="150" left="80" height="100" top="10" />
<region id="reg_texte1"
width="200" left="50" height="50" top="120" fit="meet"/>
<region id="reg_texte2"
width="200" left="50" height="50" top="180" />
<region id="reg_texte3"
width="250" left="25" height="150" top="240" />
</layout>
</head>
<body>
<xsl:apply-templates select="FILM"/>
</body>
</smil>
</xsl:template>

<xsl:template match="FILM">
<xsl:variable name="filmid" select="@FILMID" />
<xsl:variable name="filmparams">
<xsl:copy-of select="document(’ParamsSMIL.xml’)/SMILPARAMS/PARAM[@FILMREF=$filmid]" />
</xsl:variable>
<par>
<text src="{$filmparams/PARAM/@PREFIX}Title.txt" region="reg_texte1" fill="freeze"/>
<text src="{$filmparams/PARAM/@PREFIX}Info.txt" region="reg_texte2" />
<text src="{$filmparams/PARAM/@PREFIX}Resume.txt" region="reg_texte3" begin="2s"/>
<seq>
<xsl:apply-templates select="$filmparams/PARAM/PHOTOS/PHOTO"/>
</seq>
</par>
</xsl:template>

<xsl:template match="PHOTO">
<img src="{@HREF}" region="reg_img_petit" dur="5s" />
</xsl:template>
</xsl:stylesheet>
g La règle <xsl:template match="/"> génère l’entête du document et applique ensuite la
transformation pour l’élément h FILM i .
g La règle <xsl:template match="FILM"> définit une variable $filmid qui contient l’identificateur
du film et qui est utilisée dans une expression XPath comme valeur de sélection pour trouver l’élément
de type PARAM dans le document ParamsSMI.xml correspondant au film. Une copie de cet élément
4.4. TRAITEMENT DE TEXTE DANS XSLT 195

est ensuite passée comme valeur à une deuxième variable $filmparams. Cette variable est ensuite
utilisée comme racine dans plusieurs expressions XPath pour extraire les paramètres correspondant.
Le résultat de cette règle correspond exactement au contenu de l’élément de type body dans le
fichier SleepyHollow.smil.

Le fichier ParamsSMIL.xml illustre bien l’utilisation de XML comme « format universel » pour la
représentation et l’intégration de données : à partir de ressources XML et non-XML on définit un doc-
ument XML de référence qui relient toutes ces ressources. Ce fichier peut ensuite être utilisé de différentes
manières pour créer des nouvelles ressources comme par exemple un document SMIL.
Dans le jargon de recommandation XLink du W3C, ces références entre les ressources sont appelées
des liens externe par opposition aux liens internes qui sont définis dans le contenu des ressources même :
le Web actuel est basé sur le deuxième type de liens implanté par les éléments h a i de XHTML.

4.4 Traitement de texte dans XSLT


Nous allons présenter plus en détail les éléments de premier niveau et les instructions XSLT pour le traite-
ment des noeuds de type Texte qui apparaissent dans le document à transformer, mais également dans les
programmes XSLT. Le terme traitement comprend plusieurs fonctions qui interviennent pendant la trans-
formation d’un document et qui sont illustrées dans la figure 3.1 (page 110 du chapitre 3) :
g analyse du document source et du programme XSLT par le parseur XML : cette phase a été décrite
dans la section 2.3 ;
g génération de l’arbre XPath du document source : nous avons vu page 81 que XPath et donc XSLT
connaît seulement un sous-ensemble des types DOM et que les noeuds de type CDataSection sont
tous transformés en noeuds de type Text ;
g suppression éventuelle de noeuds de texte « blancs » : l’arbre XPath du document source contient
généralement un grand nombre de noeuds de type Text qui ont comme valeur un espaces (un ex-
emple a été étudié dans la section 2.3). La plupart de ces espaces sont non-significatifs et servent
uniquement pour le formattage du document sérialisé. Mais ce qui est plus important est que ces
espaces ne sont pas toujours neutres par rapport au format du document à produire. Par exemple
nous avons vu que pour la production d’un document HTML, on peut souvent ignorer la présence
d’espaces dans le document source. Par contre, dans d’autres cas, ils sont un effet indésirable et
doivent être supprimés.
XSL permet de contrôler le traitement d’espaces dans le document source par deux éléments de
premier niveau, xsl:desc-preserve et xsl:desc-strip, qui seront décrits plus loin.
g transformation du document : la phase de transformation de l’arbre XPath permet uniquement de
créer des noeuds de type Text en mélangeant des noeuds de type Text :
– obtenus comme résultat d’une expression XSLT ;
– contenux dans le corps des règles XSLT ;
g sérialisation du document : après la transformation on obtient un arbre XPath qui est ensuite sérialisé
pour obtenir un document XML qui peut être stocké dans un fichier ou échangé avec une autre
application. Cette phase de sérialisation peut être contrôle par l’élément xsl:output décrit plus
loin.

4.4.1 xsl:preserve-space et xsl:strip-space


Ces deux éléments XSLT de premier niveau permettent de contrôler la suppression des espaces blancs
dans le document source avant de commencer la transformation. Le niveau de contrôle est le type de
l’élément qui contient le noeud d’espace : il est possible de décider pour tous les éléments d’un type s’il
faut supprimer (xsl:strip-space) ou préserver (xsl:preserve-space) les fils d’espace. Les
196 CHAPTER 4. PRODUCTION DE DOCUMENTS XML

types d’éléments sont spécifiés sous forme d’une liste de noms de balises ou en utilisant le symbole ’*’
pour tous les types d’élément.
Par exemple, l’expression
<xsl:strip-space name="A C"/>
signifie que tous les fils espaces d’éléments de type A et B doivent être supprimés, tandis que l’expression
suivante choisit les fils de tous les éléments :
<xsl:strip-space name="*"/>
Voici un document XML avec des espaces (ces espaces sont uniquement composés de séquences du
caractère « » rendu visible par le symbole « _ ») :
<A>_<B>__<C>_<D>__</D><D>a_</D>_b_</C></B>_c</A>
L’arbre XPath est montré dans la figure 4.12. Les noeuds supprimés par la première expression sont
mis en évidence par un fond gris, tandis que les éléments supprimés en plus par la deuxième expression
sont rayés.

Element
A

Text Element Text


- -
#x20 B #x20 c

Text Element
-
#x20 #x20 C

Text Element Element Text


- -
#x20 D D #x20 b #x20

Text Text
- -
#x20 #x20 a #x20

Figure 4.12: Arbre XPath

On voit que seulement les noeuds qui ne contiennent que des caractères blancs sont supprimés.
L’élément xsl:preserve-space a l’effet inverse de l’élément xsl:strip-space, c’est-à-dire
que les fils d’espace blanc sont préservés. Ainsi il est possible de spécifier que le fils de tous les éléments
sauf les éléments h D i doivent être supprimés :
<xsl:strip-space name="*"/>
<xsl:preserve-space name="D"/>
Les conflits possibles qui peuvent être créés par une utilisation simultanée de ces deux éléments sont
résolus de la même manière que les conflits de règles XSLT (chapitre 3).
4.5. RSS ET RDF 197

Attribut xml:space
Les deux éléments de niveau précédent permettent un contrôle du traitement des espaces blanc au niveau
du type d’élément. Un contrôle plus fin est possible dans le contenu même du document à transformer.
Chaque élément XML peut avoir un attribut prédéfini xml:space qui décide si les fils d’espace blanc
doivent être supprimés ou pas. Nous avons déjà illustré l’utilisation de cet attribut dans la balise h pre i
de la DTD XHTML.
L’attribut xml:space peut prendre deux valeurs : default ou preserve. La première valeur in-
dique que c’est l’application – dans notre cas le programme XSLT – qui doit décider. La valeur preserve
ne signifie pas seulement que les fils d’espaces blanc de l’élément mais que tous les descendants d’espace
blanc doivent être préservés jusqu’à l’indication contraire par la valeur default.
En résumé, le processus de décision d’une suppresion des espaces est le suivant. Un élément peut être
supprimé s’il est sélectionné par une expression xsl:strip-space (après résolution des conflits) et si
l’une des deux contraintes suivantes est satisfaite :
g il n’a pas d’élément ancêtre avec un attribut xml:space ou
g l’élément ancêtre avec un attribut xml:space le plus près a comme valeur pour cet attribut la valeur
default.
Exemple 83 Voici un document XML :
<A xml:space="preserve">
<B xml:space="default">
<C> </C>
</B>
<B>
<C> </C>
</B>
</A>
et une expression xsl:strip-space :
<xsl:strip-space elements="B C">
Cette expression demande la suppression de tous les fils de type B et de type C. L’attribut xml:space de
l’élément A indique que les fils d’espace blancs doivent être préservés pour tous les éléments descendants
de cet élément. Cette contrainte est à son tour effacée pour le premier élément de type B et tous ces
descendants. Ainsi, le document précédent peut être considéré comme équivalent au document suivant :
<A>
<B><C/></B>
<B>
<C> </C>
</B>
</A>

4.4.2 Génération de texte : xsl:text


TODO

4.4.3 Sérialisation du résultat : xsl:output


TODO

4.5 RSS et RDF


Va dans le chapitre « Échange et Integration » : c’est à ça que ça sert... ;
198 CHAPTER 4. PRODUCTION DE DOCUMENTS XML
Chapter 5

Production de documents papier

Sommaire

199
200 CHAPTER 5. PRODUCTION DE DOCUMENTS PAPIER
Chapter 6

Échange et intégration

Sommaire

201
202 CHAPTER 6. ÉCHANGE ET INTÉGRATION
Chapter 7

Publication de bases de données

Sommaire
7.1 Bases de données et XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
7.1.1 Quelques rappels sur les BD relationnelles . . . . . . . . . . . . . . . . . . . . 204
7.1.2 Documents orientés « texte » et documents orientés « données » . . . . . . . . . 207
7.1.3 Transformation d’une base de données en XML . . . . . . . . . . . . . . . . . 209
7.1.4 Création de la DTD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
7.2 Architectures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
7.2.1 Une classe Java d’exportation XML . . . . . . . . . . . . . . . . . . . . . . . . 218
7.2.2 Architecture Servlet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
7.2.3 Utilisation des Java Server Pages . . . . . . . . . . . . . . . . . . . . . . . . . 225
7.3 XML dynamique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
7.3.1 XSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
7.3.2 XSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
7.4 Perspectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

Ce chapitre est consacré à la publication de documents incluant des informations issues d’une base de
données. Dans le domaine des sites web, il est désormais classique de construire les pages en intégrant à
du texte fixe des données extraites dynamiquement de la base (la majorité des sites web professionnels sont
d’aileurs gérés de cette manière). Les langages les plus utilisés dans ce type d’application sont ASP, PHP
ou les Java Server Pages (JSP). Tous consistent à placer dans du HTML des instructions qui se connectent
à la base, effectuent des requêtes et mettent en forment le résultat à l’aide de balises HTML.
La justification d’une gestion des données séparée de leur affichage dans une page web est claire :
HTML n’est pas un langage permettant la modélisation, le stockage et l’interrogation de données, et une in-
formation placée « en dur » dans une page HTML ne peut être récupérée pour un usage autre que l’affichage
dans un navigateur.
Est-ce encore vrai dans le cas de XML ? Ce chapitre va essayer de répondre à cette question ou du
moins de fournir des éléments d’appréciation. Nous commençons par partir du postulat que la majeure
partie des informations restent à l’heure actuelle stockées dans des bases de données, et qu’elles doivent en
être extraites au format XML soit pour publier tout ou partie de la base, soit pour intégrer des fragments à
d’autres types de contenus.
La première question posée est alors d’engendrer une représentation XML d’une base de données
relationnelle. La seconde est relative aux architectures logicielles qui permettent de combiner des com-
posants aussi divers qu’une base de données, un module de conversion vers XML, un processeur XSLT
et un serveur de publication web. Nous décrivons une (petite) classe Java effectuant des conversions et
montrons comme l’intégrer dans plusieurs architectures : programme batch, servlet, et JSP. Nous prenons
ensuite deux exemples très différents d’environnements qui fournissent des outils permettant la publication
de base de données :

203
204 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

1. Cocoon, un environnement de publication complet incluant XSP, une adaptation des JSP pour pro-
duire dynamiquement du XML ;

2. XSQL, un outil Oracle qui traduit automatiquement le résultat d’une requête SQL en XML, et permet
l’intégration avec XSLT.

Pour conclure le chapitre nous reprenons la question de fond posée ci-dessus : a-t-on besoin d’utiliser
une base de données en association avec XML ? Ne pourrait-on pas utiliser XML comme format de base
de données et effectuer directement l’interrogation sur des données XML, évitant ainsi des conversions
parfois coûteuses ? Nous reprenons les principales fonctionnalités d’un système de gestion de base de
données, discutons des limitations d’une représentation XML dans un tel cadre et présentons brièvement
des techniques émergentes (schémas, langages d’interrogation) qui visent à palier ces limites.

7.1 Bases de données et XML


Plaçons-nous pour l’instant dans la situation où des informations stockées dans une base de données doivent
être converties en document(s) XML. Nous effectuons un rappel des principales caractéristiques du modèle
relationnel avant de décrire le processus de conversion.

7.1.1 Quelques rappels sur les BD relationnelles


Prenons l’exemple (très simplifié) de la base de données d’un organisme de voyage. Cet organisme propose
des séjours (sportifs, culturels, etc) se déroulant dans des stations de vacances. Chaque station propose un
ensemble d’activités (ski, voile, tourisme). Enfin l’organisme souhaite gérer une liste des clients (avec le
solde de leur compte !) et des séjours auxquels ils ont participé avec leurs dates de début et de fin.
La première chose à faire est d’établir un schéma décrivant comment les informations nécessaires vont
être stockées dans la base. La conception d’un schéma relationnel n’entre pas dans le cadre de ce livre.
Il suffira de dire qu’il est constitué d’un ensemble de schémas de tables (ou relation), chaque table étant
décrite par un ensemble d’attributs. Voici une représentation concise du schéma pour notre agence de
voyages.
g Station (nomStation, capacité, lieu, région, tarif)
g Activité (nomStation, libellé, prix)
g Client (id, nom, prénom, ville, région, solde)
g Séjour (idClient, station, début, nbPlaces)

On trouve donc quatre tables, chacune ayant un nom distinct. Elles correspondent respectivement à la
description des stations, des activités proposées dans chaque station, des clients et des séjours effectués par
les clients dans les stations. Pour chaque table on a donné la liste des attributs, sans entrer pour l’instant
dans le détail des types de données. Parmi ces attributs certains présentent une importance particulière.
La clé primaire est le (ou les) attribut(s) dont la valeur va permettre d’identifier de manière unique une
ligne dans la table. Les clés primaires sont représentées en gras. Pour le schéma ci-dessus, cela signifie
qu’il ne peut pas y avoir deux stations avec le même nom. Le choix des clés relève de choix de conception
(souvent assez délicats) que nous ne commenterons pas ici. Pour la table Client, on a visiblement considéré
que le nom n’était pas suffisant pour identifier une ligne de la table, et on a créé un attribut artificiel id
pour numéroter les clients au fur et à mesure de leur insertion.
Certaines clés peuvent être constituées de plusieurs attributs. Chaque ligne de la table Activité par
exemple est identifiée par le nom de la station, et le libellé de l’activité. Il peut donc y avoir plusieurs
activités de libellés différents dans une même station, et plusieurs activités de mêmes libellés dans des
stations différentes. Enfin la table Séjour est identifiée par trois attributs : un client peut revenir plusieurs
fois dans la même station, mais pas à la même date.
7.1. BASES DE DONNÉES ET XML 205

id nom prénom ville région solde


10 Fogg Phileas Londres Europe 12465
20 Pascal Blaise Paris Europe 6763
30 Kerouac Jack New York Amérique 9812
La table Client
idClient station début nbPlaces
10 Passac 2001-07-01 2
30 Santalba 2001-08-14 5
20 Santalba 2001-08-03 4
30 Passac 2001-08-15 3
30 Venusa 2001-08-03 3
20 Venusa 2001-08-03 6
30 Farniente 2002-06-24 5
10 Farniente 2002-09-05 3
La table Séjour

Figure 7.1: Les clients et leurs séjours

Une clé étrangère est un (ou plusieurs) attribut(s) dans une table l dont la valeur fait référence à une
valeur de clé primaire dans une table m . Prenons l’exemple des tables de la figure 7.1. L’attribut idClient
dans la table Séjour contient une valeur de clé de la table Client. De même l’attribut station contient une
valeur de clé de la table Station. Les clés étrangères constituent des références entre tables, avec deux
objectifs :
g définir des contraintes d’intégrité référentielle : on ne devrait pas par exemple pouvoir référencer
dans la table Séjour un client qui n’existe pas dans la table Client ;
g permettre, par des opérations dites de jointure, le regroupement de données réparties dans plusieurs
tables : à partir de la première ligne de la table Séjour, on sait par exemple que le client s’appelle
Phileas Fogg en prenant idClient et en recherchant la ligne correspondante dans la table Client.

Les clés primaire et étrangère sont les caractéristiques essentielles d’un schéma, et définissent les prin-
cipales contraintes liant les tables. D’autres contraintes, internes à chaque table, peuvent être exprimées.
Prenons par exemple la figure 7.2. On a :

1. des contraintes de types : certains attributs sont numériques, d’autres alphanumériques, avec ou sans
décimale, etc ;
2. des contraintes d’existence : la capacité de la station Santalba, ou le tarif de la plongée à Venusa,
sont inconnus, mais tous les autres attributs ont une valeur ;

3. des contraintes d’appartenance à un ensemble énuméré : on pourrait par exemple définir une codifi-
cation des régions (« Antilles », « Europe », « Amérique », « Asie », etc).

Toutes ces contraintes sont exprimables avec le langage SQL (ou plus exactement la partie de la norme
SQL ANSI relative à la définition de données). Ainsi on peut déclarer que certains attributs doivent toujours
être connus (contrainte NOT NULL), qu’il sont des instances de types SQL, ou que leur valeur appartient
à une liste fixée.
Le script ci-dessous contient les commandes de création du schéma de la base. Notez l’absence ou non
de la contrainte NOT NULL selon qu’un attribut doit être connu ou non, et la combinaison des PRIMARY
KEY et FOREIGN KEY pour décrire les liens entre les tables. Ce script est conforme à la norme, et devrait
être accepté par tout SGBD relationnel digne de ce nom (nous l’avons testé avec MySQL et ORACLE).

Exemple 84 Schema.sql : Création du schéma de la base


206 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

nomStation capacité lieu région tarif


Venusa 350 Guadeloupe Antilles 1200
Farniente 200 Sicile Europe 1500
Santalba Martinique Antilles 2000
Passac 400 Alpes Europe 1000
La table Station
nomStation libellé prix
Venusa Voile 150
Venusa Plongée
Farniente Plongée 130
Passac Ski 200
Passac Piscine 20
Santalba Kayac 50
La table Activité

Figure 7.2: Les stations et leurs activités

#
# Schéma de la base ’Agence de voyages"
#

CREATE TABLE Station (nomStation VARCHAR (30) NOT NULL,


capacite INTEGER,
lieu VARCHAR (30) NOT NULL,
region VARCHAR (30) NOT NULL,
tarif DECIMAL (10,2),
PRIMARY KEY (nomStation),
CONSTRAINT nom_region
CHECK (region IN (’Antilles’, ’Europe’,
’Amérique’, ’Asie’,’Afrique’))
);

CREATE TABLE Activite (nomStation VARCHAR (30) NOT NULL,


libelle VARCHAR (30) NOT NULL,
prix DECIMAL (10,2),
PRIMARY KEY (nomStation, libelle),
FOREIGN KEY (nomStation) REFERENCES Station
);

CREATE TABLE Client (id INTEGER NOT NULL,


nom VARCHAR (30) NOT NULL,
prenom VARCHAR (30) NOT NULL,
ville VARCHAR (30) NOT NULL,
region VARCHAR (30) NOT NULL,
solde DECIMAL (10,2) NOT NULL,
PRIMARY KEY (id)
);

CREATE TABLE Sejour (idClient INTEGER NOT NULL,


station VARCHAR (30) NOT NULL,
debut DATE NOT NULL,
nbPlaces INTEGER NOT NULL,
PRIMARY KEY (idClient, station, debut),
FOREIGN KEY (idClient) REFERENCES Client,
FOREIGN KEY (station) REFERENCES Station);
7.1. BASES DE DONNÉES ET XML 207

Parlons maintenant du contenu d’une table. Il peut être vu comme un tableau constitué de colonnes,
une pour chaque attribut de la table, et de lignes, une pour chaque entité stockée dans la table. Dans le
modèle relationnel, l’ordre des lignes ou des colonnes n’est pas significatif. En pratique, cela signifie que
la requête suivante :
SELECT nomStation, lieu, région
FROM Station
WHERE capacité > 100
donnera le même résultat quel que soit le réagencement des lignes et des colonnes de Station.
En résumé, voici les aspects du modèle relationnel qui nous importent pour la conversion des données
vers XML :

1. la base est décrite par un schéma séparé (physiquement) des données ;


2. le schéma est constitué de descriptions de tables (ou relations) ;

3. les caractéristiques d’une table sont :


(a) son nom ;
(b) le nom de ses attributs (ou colonnes) ;
(c) le ou les attribut(s) formant la clé primaire ;
(d) une ou plusieurs clés étrangères, chacune constituée d’un ou plusieurs attributs ;
(e) le type de chaque attribut, et la contrainte NOT NULL ;
(f) les contraintes d’appartenance à un ensemble énuméré.
4. l’ordre des lignes ou des colonnes d’une table n’est pas significatif.

Voyons maintenant comment un schéma relationnel trouve son équivalent en XML.

7.1.2 Documents orientés « texte » et documents orientés « données »


L’exportation de bases de données donne des documents XML assez particuliers. Au départ, XML est un
dérivé de SGML destiné à faciliter l’échange et la représentation de documents numériques (documentation
technique, livres, maquettes, etc). De tels documents sont caractérisés par l’absence de typage (tout est vu
comme une chaîne de caractères), une forte présence de texte descriptif, et une structure très souple. Par
contraste, une base de données est très structurée, décrit l’information avec une granularité très fine, et type
cette information.
Voici une représentation possible en XML de la table Station. La racine du document est de type
Station. On trouve ensuite un élément pour chaque ligne, et dans cet élément autant d’éléments qu’il y
a d’attributs.

Exemple 85 Station.xml : Une représentation XML de la table Station


<?xml version=’1.0’ encoding=’ISO-8859-1?>

<Stations>

<Station>
<nomStation>Venusa</nomStation>
<capacite>350</capacite>
<lieu>Guadeloupe</lieu>
<region>Antilles</region>
<tarif>1200.00</tarif>
</Station>
<Station>
208 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

<nomStation>Farniente</nomStation>
<capacite>200</capacite>
<lieu>Seychelles</lieu>
<region>Océan Indien</region>
<tarif>1500.00</tarif>
</Station>
<Station>
<nomStation>Santalba</nomStation>
<capacite>null</capacite>
<lieu>Martinique</lieu>
<region>Antilles</region>
<tarif>1200.00</tarif>
</Station>
<Station>
<nomStation>Passac</nomStation>
<capacite>400</capacite>
<lieu>Alpes</lieu>
<region>Europe</region>
<tarif>1000.00</tarif>
</Station>

</Stations>

La structure obtenue est extrêmement régulière : l’arbre XML est équilibré (exactement trois niveaux
pour toutes les branches de l’arbre). De plus le contenu de chaque élément peut être précisément typé.
Il existe d’autres différences plus subtiles que celles liées à la forme entre la représentation XML et la
représentation relationnelle. La principale est que l’ordre des lignes n’est pas significatif pour une table,
alors que l’ordre des éléments l’est pour un document XML. En pratique, si toute requête SQL donne le
même résultat quel que soit l’ordre des lignes, le résultat d’un programme appliqué au document XML (par
exemple une transformation XSLT) peut dépendre de l’ordre des éléments.
Un système de gestion de base de données est libre de réorganiser le stockage des lignes d’une table, par
exemple pour optimiser les accès. Cela signifie que rien ne peut garantir que deux exportations successives
vont présenter les données dans le même ordre. Il est important de garder en tête cette particularité quand
on manipule des données XML issues d’une base de données.
Une autre différence est que la description des données (le schéma) est intégrée aux données en XML,
alors que le schéma est représenté une seule fois, et séparé des données dans un SGBD. Le document XML
est beaucoup plus redondant (et donc volumineux) que le stockage relationnel. De plus la description des
données XML est moins riche et précise que celle d’un schéma relationnel. En particulier il n’y a pas de
notion de type, et peu de contraintes sur le contenu. Nous verrons un peu plus loin comment engendrer une
DTD qui traduit (en partie) les spécifications du schéma relationnel.
Un document orienté « texte » est beaucoup moins structuré, et contient en général beaucoup de de-
scriptifs de longueurs très variables. Voici par exemple un document représentant l’avant-propos de ce
livre. Il s’agit d’un flot de texte dans lequel les balises marquent les expressions importantes, les énuméra-
tions, etc. La notion de type n’est pas importante. En revanche l’ordre est essentiel, et on ne peut pas le
changer sans changer la signification du document.

Exemple 86 AvantPropos.xml : Un document orienté « texte »

On ne peut pas considérer qu’il existe une séparation stricte entre les documents orientés « texte » et les
documents orientés « données ». Dans de nombreux cas le contenu d’un système d’information sera mixte,
et rassemblera des informations de nature et de provenance différentes. Voici un document présentant une
promotion pour notre agence de voyage. On y trouve un descriptif libre placé sous la responsabilité de
l’initiateur de la promotion, et des informations issues de la base de données.

Exemple 87 Promotion.xml : Un document mixte


7.1. BASES DE DONNÉES ET XML 209

<?xml version="1.0" encoding="ISO-8859-1"?>

<Promotion auteur="Jules">
<Description>
Nous proposons une réduction de <Reduction>25</Reduction>
pourcent, restreinte à la période du
<Periode> <Debut>Septembre 2001</Debut>
au <Fin>Octobre 2001</Fin> </Periode> pour tous
les séjours dans certaines stations de vacances.
L’automne est une saison <Important>merveilleuse</Important>
pour reprendre des forces à la montagne. Vous pourrez
profiter du calme,
d’une nature aux couleurs chatoyantes, et d’un contact
privilégié avec l’autochtone. <Important>Attention
le nombde de places offertes est limité.</Important>
</Description>

<Station>
<nomStation>Passac</nomStation>
<capacite>400</capacite>
<lieu>Alpes</lieu>
<region>Europe</region>
<tarif>1000.00</tarif>
<Activite>
<libelle>Ski</libelle>
<prix>200.00</prix>
</Activite>
<Activite>
<libelle>Piscine</libelle>
<prix>20.00</prix>
</Station>
</Promotion>

Toute la question dans ce cas est de définir le système qui va permettre d’intégrer le plus facilement
possible les deux types d’informations. On peut penser à stocker le document « texte » XML dans la base
de données, ce qui est tout à fait possible mais rend beaucoup plus difficile l’accès et la mise à jour pour un
utilisateur. À l’inverse on peut fournir des moyens simples (si possible..) d’inclure dynamiquement dans un
document XML des extraits d’une base de données. Nous montrerons dans la suite de ce chapitre un exem-
ple relativement simple mais complet d’une réalisation d’un document XML dynamique, et l’enchaînement
de la génération du document avec l’application d’un programme XSLT.

7.1.3 Transformation d’une base de données en XML


Nous étudions maintenant de manière systématique la transformation de tout ou partie d’une base de don-
nées relationnelle en document XML.

Éléments ou attributs ?
La première solution, immédiate, consiste à conserver la structure « plate » de la base relationnelle, et à
transcrire chaque table par un élément ayant le nom de la table ou un dérivé (par exemple h Stations i ).
Cet élément contient lui-même un élément pour chaque ligne, ayant pour nom un autre dérivé du nom de la
table (par exemplr « Station », sans « s », enfin chaque attribut de la table est représenté par un élément,
constituant ainsi un troisième niveau dans l’arbre.
Il existe (au moins) une autre possibilité. Au lieu de représenter les attributs de la table par des éléments,
on peut les représenter par des attributs XML de l’élément représentant la ligne. Voici ce que cela donnerait
pour la table Station.
210 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

Exemple 88 StationAttrs.xml : Réprésentation de Station avec des attributs


<?xml version=’1.0’ encoding=’ISO-8859-1?>

<Stations>

<Station nomStation=’Venusa’
capacite=’350’
lieu=’Guadeloupe’
region=’Antilles’
tarif=’1200.00’
/>
<Station nomStation=’Farniente’
capacite=’200’
lieu=’Seychelles’
region=’Océan Indien’
tarif=’1500.00’
/>
<Station nomStation=’Santalba’
capacite=’null’
lieu=’Martinique’
region=’Antilles’
tarif=’1200.00’
/>
<Station nomStation=’Passac’
capacite=’400’
lieu=’Alpes’
region=’Europe’
tarif=’1000.00’
/>

</Stations>

Cette méthode présente quelques avantages. Tout d’abord elle est assez proche, conceptuellement, de
la représentation relationnelle. Chaque ligne d’une table devient un élément XML, chaque attribut de la
ligne devient un attribut XML de l’élément. La structure est plus fidèlement retranscrite, et notamment le
fait qu’une ligne d’une table forme un tout, manipulé solidairement par les langages. En SQL par exemple,
on n’accède jamais à un attribut sans être d’abord passé par la ligne de la table.
Techniquement, l’absence d’ordre (significatif) sur les attributs XML correspond à l’absence d’ordre
significatif sur les colonnes d’une table. On s’affranchit donc en partie des problèmes potentiels évoqués
précédemment. Du point de vue du typage, l’utilisation des attributs permet également d’être plus précis
et plus proche de la représentation relationnelle :
g on ne peut pas avoir deux fois le même attribut pour un élément, de même qu’on ne peut pas avoir
deux colonnes avec le même nom dans une table (notez que ce n’est pas vrai si on représente les
colonnes par des éléments XML) ;
g on peut indiquer, dans un DTD, la liste des valeurs que prend un attribut, ce qui renforce un peu les
contrôles sur le document.
Enfin l’utilisation des attributs aboutit à un document moins volumineux. Nous utiliserons donc plutôt
cette méthode de conversion par la suite, bien qu’il soit juste de souligner que la représentation des colonnes
par des éléments a aussi ses défenseurs. Comme pour beaucoup d’autres problèmes sans solution tranchée,
le choix dépend en fait beaucoup de l’application et de l’utilisation qui est faite des informations.

Représentation des associations entre tables


Passons maintenant à la représentation XML des liens entre les tables. En relationnel, nous avons vu que
les liens sont définis par une correspondance entre la clé primaire dans une table, et une clé étrangère
7.1. BASES DE DONNÉES ET XML 211

dans une autre table. L’opération (relationnelle) qui va ensuite s’appuyer sur cette correspondance pour
rapprocher les lignes de deux tables est la jointure. Dans la figure 7.2, page 206, on voit par exemple
que les tables Station et Activité sont indépendantes l’une de l’autre (elles peuvent être stockées en des
endroits différents), mais que l’on peut, par calcul, reconstituer l’association en prenant, pour chaque ligne
décrivant une station, les lignes de Activité ayant le nom de la station.
En d’autres termes, la condition nécessaire et suffisante pour qu’il soit possible de reconstituer l’information
est l’existence d’un critère de rapprochement. Il est tout à fait possible d’appliquer le même principe en
XML. Voici par exemple un document où figurent des éléments de type Station et de type Activite
(nous n’avons gardé que deux stations pour simplifier). Ces éléments sont indépendants les uns des autres
(ici cela signifie que des informations apparentées ne sont pas liées dans la structure hiérarchique du docu-
ment), mais on a conservé le critère de rapprochement.

Exemple 89 StationActivite.xml : Stations et activités

<?xml version=’1.0’ encoding=’ISO-8859-1?>

<Stations>

<Station nomStation=’Venusa’
capacite=’350’
lieu=’Guadeloupe’
region=’Antilles’
tarif=’1200.00’
/>

<Station nomStation=’Farniente’
capacite=’200’
lieu=’Seychelles’
region=’Océan Indien’
tarif=’1500.00’
/>

<Activite nomStation=’Venusa’
libelle=’Voile’
prix=’150.00’
/>

<Activite nomStation=’Venusa’
libelle=’Plongee’
/>

<Activite nomStation=’Farniente’
libelle=’Plongée’
prix=’130.00’
/>

</Stations>

Maintenant, comme dans le cas du relationnel, il est possible de déterminer par calcul, la correspon-
dance entre une activité et une station. Supposons que l’on exécute un programme XSLT. Si le nœud
courant est de type Station, il est possible de sélectionner toutes les activités avec l’expression XPath :

/Activite[@nomStation=current()/@nomStation]

De même, si le nœud courant est de type Activite, voici l’expression XPath qui désigne la station :

/Station[@nomStation=current()/@nomStation]
212 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

Cette recherche s’apparente à la jointure de SQL, même si on procède assez différemment ici : il faut
d’abord se positionner sur un nœud, puis exprimer avec XPath le chemin qui mène aux nœuds associés.
Cette représentation est possible, mais elle n’est pas naturelle en XML et mène à quelques difficultés.
Elle n’est pas naturelle parce qu’une activité est toujours dans une et une seule station : il est donc inutile de
la représenter séparément. Elle présente des difficultés parce qu’il va être beaucoup coûteux de parcourir
des chemins compliqués dans l’arbre pour relier des nœuds.
La bonne représentation dans ce cas consiste à imbriquer les éléments de type Activite dans l’élément
de type Station. On peut du même coup s’épargner la peine de conserver le nom de la station dans
les éléments h Activite i puisque la correspondance Station/Activité est maintenant représentée par la
structure, et pas par un lien de navigation basé sur des valeurs communes. Voici ce que cela donne.

Exemple 90 StationImbriquee.xml : Représentation avec imbrication


<?xml version=’1.0’ encoding=’ISO-8859-1?>

<Stations>

<Station nomStation=’Venusa’
capacite=’350’
lieu=’Guadeloupe’
region=’Antilles’
tarif=’1200.00’>

<Activite libelle=’Voile’ prix=’150.00’/>


<Activite libelle=’Plongee’/>
</Station>

<Station nomStation=’Farniente’
capacite=’200’
lieu=’Seychelles’
region=’Océan Indien’
tarif=’1500.00’>

<Activite libelle=’Plongée’ prix=’130.00’/>


</Station>

</Stations>

Cette représentation est bien meilleure. Il est maintenant possible, pour un nœud courant de type
Station, d’accéder à toutes les activités avec l’expression XPath Activite. Inversement l’expression
« .. » donne la station pour une activité. Ces expressions s’évaluent très efficacement puisque les infor-
mations apparentées sont localisées dans la même partie de l’arbre XML. Notons au passage qu’il n’est
pas possible d’utiliser d’imbrication dans le relationnel classique (les SGBD « relationnel/objet » récents
savent le faire). Tout y est représenté « à plat », ce qui mène à multiplier le nombre des tables, souvent
inutilement.
La méthode ci-dessus ne pose pas de problème dans le cas où l’un des éléments (ici h Activite i )
est lié à un et un seul autre (ici h Station i ). On parle d’association de un à plusieurs en modélisation
base de données.
En revanche, dans le cas d’associations « plusieurs à plusieurs », l’imbrication ne va pas de soi. Prenons
par exemple l’association entre les stations et les clients. Pour une station il peut y avoir plusieurs clients,
et réciproquement. Dans le schéma relationnel on a créé une table intermédiaire Séjour pour représenter
cette association.
Il n’est pas évident de choisir l’ordre d’imbrication des éléments. Tout dépend de l’ordre de navigation
qui va être employé. Si on suppose par exemple que les accès se feront par les stations, on peut choisir
l’imbrication représentée dans l’exemple suivant (toujours en nous limitant à deux stations) :

Exemple 91 StationSejour.xml : Les stations et leurs séjours imbriqués, avec les clients à part
7.1. BASES DE DONNÉES ET XML 213

<?xml version=’1.0’ encoding=’ISO-8859-1?>

<Stations>

<Station nomStation=’Venusa’
capacite=’350’
lieu=’Guadeloupe’
region=’Antilles’
tarif=’1200.00’>

<Sejour idClient=’30’
debut=’2001-08-03’
nbPlaces=’3’/>

<Sejour idClient=’20’
debut=’2001-08-03’
nbPlaces=’6’/>
</Station>

<Station nomStation=’Farniente’
capacite=’200’
lieu=’Seychelles’
region=’Océan Indien’
tarif=’1500.00’>

<Sejour idClient=’30’
debut=’2002-06-24’
nbPlaces=’5’/>

<Sejour idClient=’10’
debut=’2002-09-05’
nbPlaces=’3’/>
</Station>

<Client id=’10’
nom=’Fogg’
prenom=’Phileas’
ville=’Londres’
region=’Europe’
solde=’12465.00’
/>
<Client id=’20’
nom=’Pascal’
prenom=’Blaise’
ville=’Paris’
region=’Europe’
solde=’6763.00’
/>
<Client id=’30’
nom=’Kerouac’
prenom=’Jack’
ville=’New York’
region=’Amérique’
solde=’9812.00’
/>

</Stations>

Un séjour est lié à une seule station, donc on a appliqué la méthode d’imbrication. Il est très facile,
214 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

si le nœud courant est de type Station, d’accéder aux séjours de la station avec l’expression XPath
textttSejour. Le problème se pose maintenant pour les clients qui ont été laissés à part. Si, étant sur un
nœud client, on recherche tous les séjours d’un client, l’expression correspondante est :

/Station/Sejour[@idClient=current()/id]

En introduisant une hiérarchie Station/Séjour, on a donc privilégié un chemin d’accès aux données. Dès
que, travaillant sur l’information relatives aux stations et à leurs séjours, on voudra obtenir celle relative
aux clients, il faudra suivre des liens de navigation et accéder à une partie éloignée de l’arbre, ce qui est
difficile à exprimer, et difficile à évaluer pour le processeur.
On peut compléter la hiérarchie en y introduisant les clients, ce qui permet de supprimer le lien de
navigation basé sur l’identifiant du client. On obtient alors le document suivant.

Exemple 92 StationSejourClient.xml : Stations, séjours et clients

<?xml version=’1.0’ encoding=’ISO-8859-1?>

<Stations>

<Station nomStation=’Venusa’
capacite=’350’
lieu=’Guadeloupe’
region=’Antilles’
tarif=’1200.00’>

<Sejour debut=’2001-08-03’
nbPlaces=’3’>
<Client id=’30’ nom=’Kerouac’ prenom=’Jack’
ville=’New York’ region=’Amérique’ solde=’9812.00’/>
</Sejour>

<Sejour debut=’2001-08-03’
nbPlaces=’6’>
<Client id=’20’ nom=’Pascal’ prenom=’Blaise’
ville=’Paris’ region=’Europe’ solde=’6763.00’/>
</Sejour>
</Station>

<Station nomStation=’Farniente’
capacite=’200’
lieu=’Seychelles’
region=’Océan Indien’
tarif=’1500.00’>

<Sejour debut=’2002-06-24’
nbPlaces=’5’>
<Client id=’30’ nom=’Kerouac’ prenom=’Jack’
ville=’New York’ region=’Amérique’ solde=’9812.00’/>
</Sejour>

<Sejour debut=’2002-09-05’
nbPlaces=’3’>
<Client id=’10’ nom=’Fogg’ prenom=’Phileas’
ville=’Londres’ region=’Europe’ solde=’12465.00’/>
</Sejour>
</Station>

</Stations>
7.1. BASES DE DONNÉES ET XML 215

Cette fois, en supposant que le point d’accès soit toujours une station, on a toutes les informations
situées dans le même sous-arbre, ce qui va permettre d’y accéder efficacement et simplement. On voit en
revanche que si on souhaite prendre comme point d’accès un client, les informations utiles sont réparties
un peu partout dans l’arbre, et que leur reconstitution sera plus difficile.
Une autre conséquence de la structure hiérarchique propre aux documents XML est qu’il est difficile
d’éviter la redondance d’information. Le client Jack Kerouac, avec toutes ses caractéristiques, apparaît
par exemple plusieurs fois dans le document StationSejourClient.xml. Si ce document ne sert que pour une
publication de données, ou plus généralement pour des recherches d’information, alors le seul inconvénient
est la taille plus importante du document par rapport à celui obtenu en mettant un seul exemplaire de chaque
élément, et en les associant par des liens.
La base de données que nous utilisons dans nos exemple est très simple. Il est clair que pour des bases
réalistes présentant quelques dizaines de tables, la conception d’un schéma XML d’exportation doit faire
des compromis entre l’imbrication des données et la conservation des correspondances clé primaire/clé
étrangère sous forme de lien de navigation dans le document XML. Tout dépend alors des besoins de
l’application, de la partie de la base qu’il faut exporter, et des chemins d’accès privilégiés aux informations
qui seront utilisés dans l’exploitation du document.

7.1.4 Création de la DTD


Quand on crée un outil exportant une base de données (ou une partie d’une base de données) dans un
document XML, on peut, en plus du document répresentant le contenu de la base, créer la DTD. L’intérêt
est de pouvoir fournir aux utilisateurs une description de la structure qui ne dépende pas d’une instance
particulière de la base. La création d’une DTD permet également de reconstituer en partie les contraintes
du schéma relationnel,
Nous continuons à prendre l’exemple de notre base « Agence de voyages », en supposant les choix
suivants :

1. les colonnes sont représentées par des attributs XML ;


2. le chemin d’accès principal est la station ;
3. pour chaque station on trouve, imbriqués, les séjours de la station, et dans chaque séjour les clients
qui ont séjourné dans la station ;
4. pour les besoins de la présentation, on va supposer que les activités de la station sont représentés par
des éléments indépendants, avec un lien de navigation.

Un exemple de document conforme à ce schéma est StationSejourClient.xml, page 214, auquel on


pourrait ajouter des éléments h Activite i comme fils de l’élément racine.

Racine du document
Les documents auront un élément racine de type Stations, constitué de 0 ou plusieurs éléments de type
Station.

<!ELEMENT Stations (Station*)>

Description de la table Station


Rappelons le schéma relationnel de la table Station. Nous allons essayer de nous y conformer dans la DTD.

CREATE TABLE Station (nomStation VARCHAR (30) NOT NULL,


capacite INTEGER,
lieu VARCHAR (30) NOT NULL,
region VARCHAR (30) NOT NULL,
tarif DECIMAL (10,2),
216 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

PRIMARY KEY (nomStation),


CONSTRAINT nom_region
CHECK (region IN (’Antilles’, ’Europe’,
’Amérique’, ’Asie’,’Afrique’))
);

Chaque colonne de la table devient un attribut de l’élément. Nous ne pouvons pas reproduire le type,
donc tous sont déclarés comme CDATA. En ce qui concerne la contrainte d’existence NOT NULL, elle a
une équivalence directe dans la DTD.

1. si la colonne est à NOT NULL, l’attribut XML est qualifié avec #REQUIRED ;
2. sinon l’attribut XML est qualifié avec #IMPLIED.

On choisit donc de ne pas représenter un attribut à NULL, ce qui est le plus proche équivalent en XML
du fait que la valeur est inconnue. La valeur NULL correspond vraiment à une absence de valeur, ce qui est
très différent d’une valeur à 0 ou de la chaîne vide, cette dernière pouvant être représentée par un élément
ou un attribut vide en XML.
Les autres contraintes sur le contenu de la table sont d’une part la clé primaire, d’autre part l’ensemble
de valeurs énumérées pour la colonne region. Quand la clé primaire est constituée d’une seule colonne,
elle correspond à l’ID d’une DTD XML :

nomStation ID #REQUIRED

Si le parseur est validant (autrement dit s’il vérifie que le document est conforme à la DTD), il contrôlera
qu’il n’y a pas deux éléments h Station i avec le même attribut nomStation. En fait la portée d’une
déclaration d’identifiant couvre tous les éléments d’un document, quel que soit leur type, alors qu’elle est
restreinte à une table en relationnel. Si on déclare un ID pour un autre élément correspondant à une autre
table, il faut envisager qu’il puisse exister des valeurs de clé identiques dans les deux tables (dans ce cas on
peut par exemple préfixer les clés par le nom de la table, même si ce n’est pas une garantie totale). Dans
le cas – fréquent – où la clé primaire comprend plusieurs colonnes de la table, il n’existe pas d’équivalent
dans la notation des DTD.
Pour la valeur énumérée, on peut aussi l’indiquer dans la DTD. Notez que, par chance (!), il n’y a pas
de valeur contenant des blancs dans notre liste des régions, ce qui serait possible dans le schéma relationnel
mais ne pourrait pas être retranscrit dans la DTD.
Finalement il reste à indiquer qu’un élément h Station i peut avoir comme fils 0 ou plusieurs élé-
ments h Sejour i . Voici la partie de la DTD correspondant à la table Station.

<!ELEMENT Station (Sejour*)>


<!ATTLIST Station
nomStation ID #REQUIRED
capacite CDATA #IMPLIED
lieu CDATA #REQUIRED
tarif CDATA #REQUIRED
region (Antilles Europe Amérique Asie) #REQUIRED
>

Tables Séjour et Client


Voici la commande de création de la table Séjour. La clé est constituée de plusieurs attributs, et on ne peut
donc pas la représenter avec la DTD.

CREATE TABLE Sejour (idClient INTEGER NOT NULL,


station VARCHAR (30) NOT NULL,
debut DATE NOT NULL,
nbPlaces INTEGER NOT NULL,
7.1. BASES DE DONNÉES ET XML 217

PRIMARY KEY (idClient, station, debut),


FOREIGN KEY (idClient) REFERENCES Client,
FOREIGN KEY (station) REFERENCES Station);

Cette table comprend deux clé étrangères : chaque séjour fait référence à une (une seule) station et
un (un seul) client. Comme nous avons choisi de représenter par une imbrication les liens entre ces trois
entités, la reprise de ces clés étrangères dans la DTD est inutile. Il sufit de dire qu’un élément de type
Sejour est composé d’un (un seul) élément de type Client, un élément h Sejour i étant par ailleurs
fils d’un et un seul élément h Station i .

<!ELEMENT Sejour (Client)>


<!ATTLIST Sejour
debut CDATA #REQUIRED
nbPlaces CDATA #REQUIRED
>

Enfin la table Client est retranscrite en reprenant simplement les colonnes de la tables comme attributs
dans la DTD. Notez que l’on ne peut plus dire que l’attribut id est unique dans le document puisqu’un
client sera dupliqué pour chaque séjour auquel il a participé (voir document StationSejourClient.xml,
page 214). On doit quand même conserver l’attribut id dans l’élément, pour pouvoir reconnaître les
éléments correspondant au même client.

La table Activite
Pour les besoins de la cause, nous plaçons les éléments de type Activite indépendamment de la station
à laquelles ils se rattachent, en conservant un lien identique à celui de la base relationnelle. Voici la
commande de création de cette table.

CREATE TABLE Activite (nomStation VARCHAR (30) NOT NULL,


libelle VARCHAR (30) NOT NULL,
prix DECIMAL (10,2),
PRIMARY KEY (nomStation, libelle),
FOREIGN KEY (nomStation) REFERENCES Station
);

On ne peut pas déclarer d’identifiant puisqu’il est composé de deux colonnes. En revanche il est possi-
ble de transcrire partiellement la clé étrangère par une référence IDREF.
<!ELEMENT Activite EMPTY>
<!ATTLIST Activite
nomStation IDREF #REQUIRED
libelle CDATA #REQUIRED
prix CDATA #IMPLIED
>
Un processeur validant vérifiera, sur notre exemple, que chaque attribut nomStation d’un élément
h Activite i a une valeur égale à celle de l’attribut correspondant dans un élément h Station i . Con-
trairement au schéma de la table relationnelle, rien n’indique que nomStation dans h Activite i fait
référence à nomStation dans h Station i puisque les identifiants sont globaux au document.
Voici pour conclure la DTD complète.

Exemple 93 BaseStation.dtd : La DTD de la base


<!-- DTD des documents exportés de la base
"Agence de voyages -->

<!ELEMENT Stations (Station*)>


218 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

<!ELEMENT Station (Sejour*)>


<!ATTLIST Station
nomStation ID #REQUIRED
capacite CDATA #IMPLIED
lieu CDATA #REQUIRED
tarif CDATA #REQUIRED
region (Antilles Europe Amérique Asie) #REQUIRED
>

<!ELEMENT Sejour (Client)>


<!ATTLIST Sejour
debut CDATA #REQUIRED
nbPlaces CDATA #REQUIRED
>

<!ELEMENT Client EMPTY>


<!ATTLIST Client
id CDATA #REQUIRED
nom CDATA #REQUIRED
prenom CDATA #REQUIRED
ville CDATA #REQUIRED
region CDATA #REQUIRED
solde CDATA #REQUIRED
>

<!ELEMENT Activite EMPTY>


<!ATTLIST Activite
nomStation IDREF #REQUIRED
libelle CDATA #REQUIRED
prix CDATA #IMPLIED
>

7.2 Architectures
Nous allons maintenant étudier quelques architectures-types permettant d’intégrer dans un système de pub-
lication des informations extraites d’une base de données. Il n’existe pas à l’heure actuelle de mécanisme
standard, mais on peut dégager quelques principes généraux sur lesquels s’appuient la plupart des outils.
Une des principales motivations dans ce type d’architecture est la séparation des points de vues (sep-
aration of concern). L’idée est que dans un système basé sur plusieurs couches logicielles présentant
chacune un haut degré de complexité, le passage d’une couche à une autre doit être le plus transparent
possible. Concrètement, les développeurs XSLT ne devraient pas avoir à connaître aussi un langage de
programmation come Java, la structure de la base de données ou l’interface JDBC.
Il existe de nombreux outils qui exportent en XML une partie d’une base de données, et permettent
l’intégration avec XSLT. Dans la mesure où ces outils diffèrent les uns des autres et sont amenés, de plus,
à évoluer rapidement, nous avons choisi de présenter tout d’abord un exemple complet et autonome de
réalisation d’un extracteur et d’insertion de cet extracteur dans divers types d’architectures. Cet exemple
est bien sûr simplifié mais doit permettre de comprendre rapidement les problèmes posés par la création de
XML « dynamique ».
Nous décrirons ensuite deux outils assez différents qui proposent, chacun à sa manière, une solution à
ces problèmes : l’environnement de publication Cocoon, et les outils XML d’Oracle.

7.2.1 Une classe Java d’exportation XML


Commeçons par créer une classe Java qui exporte le résultat d’une requête en suivant les principes exposés
dans la section précédente. Cette classe doit offrir les fonctionnalités suivantes :
7.2. ARCHITECTURES 219

1. connexion à n’importe quelle base de données ;

2. exécution d’une requête ;

3. mise en forme du résultat de la requête en représentant chaque ligne soit par des éléments XML, soit
par des attributs.

Bien entendu cette classe, ExportXML.java, utilise JDBC, l’interface standard de connexion aux bases
de données relationnelles. Voici le code de la classe, les méthodes formatXML(), formatEle-
ments() et formatAttributs() étant décrites par la suite.

public class ExportXML


{
static Connection connexion;

public ExportXML(String driver, String nomBase,


String login, String password)
throws SQLException, ClassNotFoundException
{
// Chargement du driver
Class.forName (driver);

// Connection à la base
connexion = DriverManager.getConnection
(nomBase, login, password);
}

public String formatXML (String requete,


String nomElement,
String mode)
{
...
}

// Formatage avec éléments


private String formatElements (String nomElement,
ResultSet resultat,
ResultSetMetaData schema)
throws SQLException
{
...
}

// Formatage avec attributs


private String formatAttributs (String nomElement,
ResultSet resultat,
ResultSetMetaData schema)
throws SQLException
{
...
}
}

Le constructeur de la classe (appelé au moment de l’instanciation d’un nouvel objet avec new) reçoit
le nom du driver JDBC à utiliser, et les paramètres de connexion à la base. Le constructeur cherche alors
à instancier le driver (ce qui suppose que la classe soit accessible dans le CLASSPATH au moment de
l’exécution), et essaie de se connecter à la base avec les paramètres fournis. Si l’une de ces opérations
échoue, une exception Java est envoyée au programme appelant.
220 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

Remarque : Nous considérons comme acquise une connaissance de base de JDBC, suffisante pour com-
prendre nos exemples. Pour en savoir plus, reportez-vous à un ouvrage spécialisé, par exemple JDBC et
Java, Guide du programmeur, par George Reese, aux Éditions O’Reilly.

Si l’instanciation d’un objet de la classe ExportXML réussit, l’objet est connecté à la base et prêt à
exécuter et formatter des requêtes. Ce service est fourni par la méthode formatXML() ci-dessous.
public String formatXML (String requete,
String nomElement,
String mode)
{
StringBuffer chaineXML = new StringBuffer ();
Statement reqJDBC; // Le ’statement’ JDBC
ResultSet resultat; // Le résultat de la requête
ResultSetMetaData schema; // Le schéma de la requête

// Exécution de la requête
try
{
reqJDBC = connexion.createStatement ();
resultat = reqJDBC.executeQuery (requete);
schema = resultat.getMetaData();

// Sortie du résultat avec balises XML


while (resultat.next ())
{
if (mode.equals("elements"))
{
chaineXML.append(formatElements(nomElement,
resultat, schema));
}
else
{
chaineXML.append(formatAttributs(nomElement,
resultat, schema));
}
}
resultat.close();
}
catch (SQLException e)
{
chaineXML.append("<ERREUR>" + e.getMessage() +"</ERREUR>\n");
}

return chaineXML.toString();
}

La méthode reçoit trois arguments : la requête à exécuter, le nom de l’élément décrivant chaque ligne,
et le mode de formattage qui peut être elements ou attributs. La requête est alors exécutée, et on
récupère deux variables : resultat est un curseur sur la liste des lignes renvoyées par l’exécution de la
requête, et schema est la description du résultat (nombre d’attributs, nom des attributs, etc). Il ne reste
plus qu’à appeler la méthode qui, selon le cas, va mettre en forme chaque ligne avec des éléments ou des
attributs. Voici par exemple formatAttributs(), formatElements() étant tout à fait semblable
(vous pouvez bien entendu récupérer le code complet sur le site).
private String formatAttributs (String nomElement,
ResultSet resultat,
7.2. ARCHITECTURES 221

ResultSetMetaData schema)
throws SQLException
{
StringBuffer chaine = new StringBuffer();
String valeur, nom ;
int i, nbAttrs;

// On prend le nombre d’attributs


nbAttrs = schema.getColumnCount();

chaine.append("<" + nomElement + " ");


for (i=1; i <= nbAttrs; i++)
{
nom = schema.getColumnName(i);
valeur = resultat.getString(i);
if (!resultat.wasNull())
{
chaine.append(nom + "=’" + valeur + "’ \n");
}
}
chaine.append("/>\n");
return chaine.toString();
}

La méthode crée un élément (le nom est celui passé en paramètre) et insère autant d’attributs XML
qu’il y a de colonnes dans le résultat. Noter que les valeurs nullles ne sont pas prises en compte grâce au
test :

if (!resultat.wasNull())

Pour compléter ce code, il faudrait tester que chaque valeur issue de la base ne contient pas de caractère
réservé XML comme « < », « > » ou « & », et les remplacer éventuellement par des entités. Telle quelle,
cette classe est déjà suffisante pour étudier les différents types d’architecture dans lesquels elle peut prendre
place.
Avant d’étudier des solutions basées sur des servlet, JSP ou XSP, mentionnons le cas le plus simple,
celui d’un programme lancé sur la ligne de commande qui prend en argument la requête, et sort le document
XML.
Le programme Extracteur.java ci-dessous se connecte à une base « agence de voyage » gérée par
MySQL. Il prend en paramètre, sur la ligne de commande, n’importe quelle requête sur cette base, ainsi
que le nom de l’élément représentant chaque ligne du résultat, et le nom de l’élément racine du document.
Tout l’export est pris en charge par une instance de Export.java.

Exemple 94 Extracteur.java : Programme d’extraction d’une base de données


/* Ce programme fait appel à la classe ExportXML pour formatter
* le résultat d’une requête SQL en XML (en mode attributs).
* Il prend trois arguments:
* 1 - La requête SQL sur la table Station
* 2 - Le nom de l’élément pour chaque ligne
* 3 - Le nom de l’élément racine du document
* Exemple: java Extracteur ’select * from Station’ ’STATION’ ’STATIONS’
*
* NB: ceci est un programme de démonstration:
* aucun contrôle n’est effecté sur les paramètres
*/

// Import des classes Java


222 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

import java.util.*;
import ExportXML;

class Extracteur
{
public static void main (String args [])
{
try
{
ExportXML export = new ExportXML
("org.gjt.mm.mysql.Driver",
"jdbc:mysql://localhost/Station",
"visiteurStation", "mdpVisiteur");

System.out.println
("<?xml version=’1.0’ encoding=’ISO-8859-1?>’\n");

// Elément racine du document


System.out.println ("<" + args[2] + ">\n");

// Mise en forme du résultat


System.out.println(export.formatXML (args[0],
args[1],
"attributs"));
// Fin de l’élément racine
System.out.println ("</" + args[2] + ">\n");
}
catch (Exception e)
{
System.out.println ("Impossible de se connecter à MySQL");
System.out.println (e.getMessage());
}
}
}

L’utilisation d’un programme comme celui-ci, combiné à des transformations XSLT pour créer par ex-
emple un site HTML, constitue une solution simple et robuste qui ne pose pas de problème de performance
ou de disponibilité du serveur. Le seul inconvénient, qui doit être apprécié en fonction des caractéristiques
de l’application, est l’absence de rafraîchissement en temps réel des données. Nous passons maintenant à
des solutions plus sophistiquées où le représentation XML est produite dynamiquement.

7.2.2 Architecture Servlet


La première solution permettant de générer dynamiquement du XML en fonction de demandes utilisateurs
est une architecture servlet. Une servlet est un objet Java intégré à un serveur web qui prend en charge des
requêtes HTTP (figure 7.3). cet objet dispose de toutes les possibilités du langage Java, et en particulier de
la possibilité de se connecter à une base de données via JDBC.
Nous allons prendre l’exemple d’une servlet qui reçoit des requêtes SQL sur la base Station et y répond
sous forme d’un document XML. Pour l’instant nous n’introduisons pas de transformation XSLT.
La figure 7.4 montre le formulaire HTML qui permet d’interroger la servlet. Comme dans le cas du
programme Extracteur.java ci-dessus, le formulaire envoie la requête, ainsi que des paramètres de créa-
tion du document : nom de l’élément racine, nom de l’élément pour chaque ligne, mode de présentation
(attributs ou éléments).
Au lieu de répondre comme d’habitude par un document HTML mis en page par le navigateur, la
servlet renvoie un document XML que l’utilisateur peut choisir soit de stocker, soit de mettre en forme
avec un programme XSLT ou une feuille de style CSS. Nous verrons un peu plus loin comment on peut,
7.2. ARCHITECTURES 223

requêtes HTTP Request


Serveur
web Servlet
document(s) Response
HTML Machine Java JDBC

BD
Machine serveur

Figure 7.3: Archictecture avec servlet

sur le serveur, appliquer un programme XSLT afin d’obtenir une version HTML transmise au client. Le
résultat « brut » fourni par la servlet est donné dans la figure 7.5.
Voyons maintenant comment on met en œuvre ce service web. Le code complet de la servlet est donné
ci-dessous.

Exemple 95 ServletXML.java : La servlet d’extraction XML


import java.io.*; import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

import ExportXML;

public class ServletXML extends HttpServlet {


public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
StringBuffer chaineXML = new StringBuffer();
String requete, element, mode, racine;
ExportXML export;

response.setContentType("text/plain");
PrintWriter out = response.getWriter();

// Récupération des paramètres


requete = request.getParameter("requete");
mode = request.getParameter("mode");
racine = request.getParameter("racine");
element = request.getParameter("element");

try
{
// Exécution de la requête
export = new ExportXML ("org.gjt.mm.mysql.Driver",
"jdbc:mysql://localhost/Station",
"visiteurStation", "mdpVisiteur");

// Extraction XML
chaineXML.append (export.formatXML (requete,
element,
224 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

Figure 7.4: Un formulaire d’interrogation de servlet

mode));

// Affichage du résultat
out.println("<?xml version=’1.0’ encoding=’ISO-8859-1?>’\n");
out.println("<" + racine + ">");
out.println (chaineXML.toString());
out.println("</" + racine + ">");
}
catch (Exception e)
{
chaineXML.append ("Erreur JDBC: " + e.getMessage());
}
}
}

La servlet ServletXML est une sous-classe HttpServlet, et hérite donc de toutes ses fonctionnal-
ités. En particulier elle reçoit deux paramètres, request et response qui représentent respectivement
un objet contenant toutes les caractéristiques de la requête HTPP transmise à la servlet, et un objet servant
d’intermédiaire pour construire et communiquer le résultat. On se sert de cet objet pour indiquer que le
type MIME du document fourni est text/plain (on peut également utiliser text/xml si le navigateur
le connaît) au lieu de l’habituel text/html.
response.setContentType("text/plain");

La première tâche consiste à récupérer les paramètres requete, racine, element et mode provenant
du formulaire. Ensuite on instancie un objet de la classe ExportXML et on le charge d’exécuter la requête
et de constituer une représentation XML appropriée du résultat. Enfin on place ce résultat dans le document
résultat transmis par le serveur au navigateur (ou à tout autre programme client ayant effectué la requête
HTTP).
7.2. ARCHITECTURES 225

Figure 7.5: Le résultat de l’interrogation

Cette servlet très simple fournit donc un moyen de publier sous forme XML dees extraits de la base de
données. Sur ce même canevas on peut construire des services plus ou moins complexes qui vont permettre
d’échanger des documents XML construits dynamiquement avec d’autres applications (voir chapitre 6).
Maintenant la question qui peut nous préoccuper est : où faire intervenir une transformation XLT ? Il existe
(au moins..) deux possibilités.

1. Laisser le programme client traiter le document à sa guise. C’est la situation où on publie sur le
web des documents qui, contrairement aux pages HTML, sont exploitables : on peut en extraire des
informations, les restructurer, les intégrer à d’autres, etc. Nous avons déjà discuté dans les chapitres
précédents de ce livre du rôle de XML/XSLT dans l’intégration de données. Dans ces circonstances
XSLT est utilisé du côté client pour traduire le document fourni dans sa propre DTD (exemple d’un
moteur de recherche).

2. Effectuer la transformation côté serveur. Dans ce cas on connaît un service sur le web qui « consomme »
des documents conformes à une certaine DTD, et c’est au niveau du serveur que la transformation
est effectuée afin de communiquer des informations au bon format à ce service.

Pour effectuer la transformation côté serveur, il faut, avant la transmission du document XML au client,
lui appliquer un programme XSLT. On peut le faire dans notre servlet en appelant les services Java d’un
processeur XSLT (par exemple Xalan). Nous allons montrer une solution un peu plus simple à base de
Java Server Pages.

7.2.3 Utilisation des Java Server Pages


Les Java Server Pages constituent une extension des servlet dont l’objectif principal est de faciliter la
création de documents combinant des parties statiques et des parties dynamiques. Un des principaux in-
convénients des servlets est en effet la nécessité de produire tout le résultat en faisant appel, pour chaque
226 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

ligne, à la fonction println(), ce qui alourdit considérablement le code et va à l’encontre du partage des
tâches entre les différents intervenants d’un système de publication.
Dans une servlet, tout est programmé. Il n’ya donc plus de distinction entre le contenu, la présentation
et les parties « applicatives » (accès à la base, calculs, etc). Au contraire, avec les JSP, on peut constituer
un service web de plusieurs couches (figure 7.6) :

1. la couche contenu/présentation utilise un langage avec balise qui uniformise (relativement...) la


manipulation des parties statiques et des parties dynamiques ;
2. la couche application est constituée d’objets qui fournissent les services de calcul, mise en forme,
transformation des données ;
3. enfin la couche données constitue le stockage des informations de l’application.

La figure 7.6 montre cette architecture, la couche applicative étant représentée par un composant Java
Bean.

Serveur JDBC
JSP JavaBean
web
Représentation XML Objet intermédiaire

BD

Contenu/Présentation Application Données

Figure 7.6: Architecture avec JSP et un java bean

Au départ les JSP sont principalement destinées à faciliter la production de HTML dynamiquement. On
peut donc les considérer, au même titre que les ASP ou que PHP, comme un moyen d’introduire souplement
des parties programmées dans des pages HTML. Voici un exemple très simple de page JSP, illustrant ce
mécanisme.
Exemple 96 JSPSimple.jsp : Un exemple simple de page JSP
<HTML>
<HEAD><TITLE>JSP Simple</TITLE></HEAD>
<BODY>

<%@ page import="java.io.*,java.util.*" %>

Date : <%= new Date()%>

</BODY>
</HTML>

Il s’agit donc d’un document HTML, au sein duquel les parties programmées en Java sont placées dans
des balises marquées par <%. Au moment où le serveur lit ces pages, il va compiler les parties programmées
et les associer aux parties statiques dans une servlet transitoire qui est alors exécutée. Les JSP peuvent très
bien être considérées comme un moyen de faciliter l’écriture de servlets.
Les JSP étant initialement orientées vers HTML, les notions de contenu et de présentation ne sont pas
encore clairement séparées. On peut cependant utiliser les JSP pour produire du XML, et tirer parti de
la capacité des JSP à « masquer » les parties programmées. Nous allons illustrer les JSP en prenant pour
exemple un petit formulaire qui permet de donner le nom d’une station, et d’obtenir en retour un document
XML représentant cette station. La requête est donc toujours :
7.2. ARCHITECTURES 227

select * from Station where nomStation=’nom’


Nous avons besoin d’une classe intermédiaire (un « bean » Java) qui va prendre en charge les échanges
entre la page JSP et la classe ExportXML.java. Voici le code de cette classe :

Exemple 97 XMLBean.java : Un JavaBean associé à une page JSP


// Bean Java pour page JSP
import ExportXML;

public class XMLBean


{
private StringBuffer chaineXML = new StringBuffer();
private String nomStation, element, mode;
private ExportXML export;

public XMLBean()
{
try
{
export = new ExportXML ("org.gjt.mm.mysql.Driver",
"jdbc:mysql://localhost/Station",
"visiteurStation", "mdpVisiteur");
}
catch (Exception e)
{
chaineXML.append ("Impossible de se connecter à MySQL : ");
chaineXML.append (e.getMessage());
}

mode = "attributs";
nomStation = "";
element = "Station";
}

public void setNomStation(String s) {nomStation = s;}


public void setElement(String e) {element = e;}
public void setMode(String m) {mode = m;}

public String getChaineXML() {


chaineXML.append (export.formatXML
("select * from Station where nomStation=’"
+ nomStation + "’", element, mode));
return chaineXML.toString();
}
}

Cette classe est très simple. Son principal intérêt est de se conformer à une interface normalisé qui va
permettre de faire appel à ses services très facilement dans une page JSP. Chaque propriété (nomStation,
element, mode) est modifiée par une méthode nommée setXXX() où XXX est le nom de la propriété.
Réciproquement des méthodes getXXX() permettent de récupérer la valeur d’une propriété. Dans le
code précédent nous n’avons mis que les méthodes dont nous avons vraiment besoin pour simplifier la
présentation.
Voici maintenant la page JSP. On peut constater que cette fois le code Java est complètement caché.

Exemple 98 RequeteXML.jsp : La page JSP effectuant la mise en page de la requête


<% response.setContentType("text/plain"); %>
<%@ page import="java.io.*,java.util.*,XMLBean" %>
<jsp:useBean id="monBean" class="XMLBean"/>
228 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

<jsp:setProperty name="monBean" property="nomStation"/>


<jsp:setProperty name="monBean" property="element"/>
<jsp:setProperty name="monBean" property="mode"/>

<?xml version=’1.0’ encoding=’ISO-8859-1’?>


<<%= request.getParameter("racine") %>>

<jsp:getProperty name="monBean" property="chaineXML"/>

</<%= request.getParameter("racine") %>>

On utilise, de manière transparente, les fonctionnalités du bean avec des instructions JSP :
1. l’instruction n jsp:useBean id="monBean" class="XMLBean"/ o est l’équivalent, en JSP,
de l’instanciation d’un objet : on lui donne un nom qui permettra d’y faire référence, et on indique
sa classe ;
2. l’instruction n jsp:setProperty name="monBean" property="nomStation"/ o re-
vient à appeler la méthode setNomStation() sur l’objet monBean : on l’occurrence on affecte
à cette propriété du bean la valeur transmise par le formulaire ;
3. inversement, l’instruction n jsp:getProperty name="monBean" property="chaineXML"/ o
revient à appeler la méthode getChaineXML() sur l’objet monBean.
La modification ou l’extraction de certaines propriétés déclenche des opérations internes (accès à la
base, mise en forme XML) qui sont transparentes dans cette page. On obtient donc l’équivalent de la
servlet de la section précédente, en obtenant une séparation relativement satisfaisante du contenu (ici un
document XML dynamique que l’on pourrait facilement intégrer à des parties statiques) et de la « logique »
(ici un accès à une base de donnée). Voici un exemple plus concret qui reprend le document Promotion.xml,
page 208, dont nous avions signalé qu’il comprenait des parties statiques, et des parties extraites de la base.
Nous disposons maintenant d’un moyen technique d’intégrer ces parties dynamiques.
Exemple 99 Promotion.jsp : Le document Promotion.xml avec du code JSP
<?xml version="1.0" encoding="ISO-8859-1"?>

<% response.setContentType("text/plain"); %>


<%@ page import="java.io.*,java.util.*,XMLBean" %>
<jsp:useBean id="monBean" class="XMLBean"/>

<Promotion auteur="Jules">
<Description>
Nous proposons une réduction de <Reduction>25</Reduction
pourcent, restreinte à la période du
<Periode> <Debut>Septembre 2001</Debut>
au <Fin>Octobre 2001</Fin> </Periode> pour tous
les séjours dans certaines stations de vacances.
L’automne est une saison <Important>merveilleuse</Important>
pour reprendre des forces à la montagne. Pour pourrez
profiter du calme,
d’une nature aux couleurs chatoyantes, et d’un contact
privilégié avec l’autochtone. <Important>Attention
le nombre de places offertes est limité.</Important>
</Description>

<jsp:setProperty name="monBean" property="nomStation" value="Passac"/>

<jsp:getProperty name="monBean" property="chaineXML"/>


</Promotion>
7.2. ARCHITECTURES 229

C’est presque un document XML bien formé, à l’exception des instructions JSP pour les parties dy-
namiques.
Il reste à intégrer la présentation des données obtenues avec un programme XSLT. JSP offre la possi-
bilité de créer des librairies de balises qui permettent d’invoquer simplement des fonctionnalités comme
l’application d’un programme XSLT. Des librairies sont fournies par la fondation Apache, sur le site
http://jakarta.apache.org/taglibs. Voici un exemple de leur utilisation :
Exemple 100 PromotionXSL.jsp : Transformation du document Promotion.jsp avec un programme XSLT
<%@ taglib uri="http://jakarta.apache.org/taglibs/xsl-1.0"
prefix="xsltlib" %>

<% response.setContentType("text/plain"); %>


<%@ page import="java.io.*,java.util.*,XMLBean" %>
<jsp:useBean id="monBean" class="XMLBean"/>

<xsltlib:apply xsl="/bdxml/Promotion.xsl">
<?xml version="1.0" encoding="ISO-8859-1"?>
<Promotion auteur="Jules">

<Description>
Nous proposons une réduction de <Reduction>25</Reduction>
pourcent, restreinte à la période du
<Periode> <Debut>Septembre 2001</Debut>
au <Fin>Octobre 2001</Fin> </Periode> pour tous
les séjours dans certaines stations de vacances.
L’automne est une saison <Important>merveilleuse</Important>
pour reprendre des forces à la montagne. Vous pourrez
profiter du calme,
d’une nature aux couleurs chatoyantes, et d’un contact
privilégié avec l’autochtone. <Important>Attention
le nombre de places offertes est limité.</Important>
</Description>

<jsp:setProperty name="monBean" property="nomStation" value="Passac"/>

<jsp:getProperty name="monBean" property="chaineXML"/>


</Promotion>
</xsltlib:apply>

Le programme JSP commence par déclarer l’utilisation de la librairie de balises xsl-1.0, avec le
préfixe xsltlib.

<%@ taglib uri="http://jakarta.apache.org/taglibs/xsl-1.0"


prefix="xsltlib" %>
On peut ensuite appliquer un programme XSLT avec la balise n xsltlib:apply o en indiquant le
nom du fichier contenant le programme :

<xsltlib:apply xsl="/bdxml/Promotion.xsl">
...
</xsltlib:apply>

Cette solution n’est pas encore totalement satisfaisante puisque des fragments XML sont associés à
des balises non-XML, ce qui empêche de les utiliser indépendamment du service web, par exemple pour
effectuer une transformation XSL-FO.
En résumé les JSP offrent un premier exemple d’une architecture cherchant à « séparer les points de
vue » du programmeur, de l’administrateur de bases de données, et du gestionnaire de présentation. Mal-
heureusement la séparation n’est pas encore parfaite entre l’aspect « contenu » et l’aspect « présentation ».
230 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

Une page JSP contenant et engendrant du XML n’est pas elle-même du XML bien formé, et l’utilisation
de XML/XSLT est donc limitée à la production de fragments assemblés par des instructions JSP.

7.3 XML dynamique


Les solutions conçues initialement pour HTML ne sont donc pas totalement adaptées à la création « dynamique »
de XML. Les producteurs de logiciels ont donc proposé de nouveaux outils, en reprenant souvent en partie
les principes des servlets ou des JSP. La présentation d’un panorama complet de ces outils dépasse le cadre
de ce livre, d’autant qu’il s’agit d’un domaine qui évolue très rapidement. Nous présentons deux outils qui
nous semblent assez représentatifs :

1. Cocoon est un environnement de publication open source développé dans le cadre du projet XML de
la fondation Apache. Une des innovations proposées dans le cadre de ce projet est XSP, un langage
qui généralise les JSP.
2. Oracle développe également de très nombreux outils autour de son SGBD, dont une « suite » XML.
Cette suite comprend un outil de transformation automatique du résultat d’une requête SQL en XML,
suivi d’une transformation XSLT.

Il existe de très nombreux autres produits qui s’apparentent à l’un ou l’autre : nous en donnons une liste
(pas forcément exhaustive...) sur le site associé à ce livre.

7.3.1 XSP
Les eXtensible Server Pages (XSP), proposées initialement dans le cadre du projet Cocoon, et maintenant
adoptées également par un environnement de publication comme AxKit (www.axkit.org), sont une adap-
tation des principes des JSP en mettant cette fois l’accent sur une parfaite intégration avec XML. Un
document XSP est un document XML, incluant, dans des éléments spécifiques, du code Java.
La transformation d’un document XSP s’effectue en plusieurs étapes. Tout d’abord le document XSP
est compilé et exécuté, ce qui donne un document XML intermédiaire dans lequel les instructions java
ont été remplacées par leur résultat, au format XML. Puis ce document XML intermédiaire est soumis à
nouveau à un processus de transformation, avec un programme XSLT cette fois, et le résultat produit (du
HTML, du XML, etc) est enfin transmis au programme client.
L’architecture de Cocoon1 permet une généralisation de ce processus impliquant plusieurs transforma-
tions successives d’un document. Le système est basé sur la combinaison de producteurs, chacun étant
chargé d’effectuer une transformation (par XSLT, exécution de code ou tout autre mécanisme) d’un doc-
ument XML en entrée vers un document XML en sortie (figure 7.7). En bout de chaîne un formateur est
chargé d’effectuer la mise en forme du document final (en HTML, en PDF si le document est en XSL-FO,
ou tout autre format) avant de le transmettre au client.

Présentation de XSP
Il n’est pas dans notre propos de présenter de manière appronfondie XSP. Nous allons simplement présenter
les principes de fonctionnement sur un exemple. Voici donc un document PromotionXSP.xml qui reprend
des parties statiques (tout ce qui concerne le texte de la promotion) et une partie dynamique, consistant à
interroger la base de données et à intégrer le résultat dans le document.

Exemple 101 PromotionXSP.xml : Une document XSP


<?xml version="1.0" encoding="ISO-8859-1"?>

<?cocoon-process type="xsp"?>
<?cocoon-process type="xslt"?>
<?xml-stylesheet href="Promotion.xsl" type="text/xsl"?>
1 Nous parlons ici de la version 1.8, la version 2.0 étant encore, à l’heure où ces lignes sont écrites, en phase de développement.
7.3. XML DYNAMIQUE 231

Requête

Producteur Producteur
(autres
(XSP) transformations) (XSLT)

Document Document Formateur


intermédiaire intermédiaire
Réponse

Figure 7.7: Transformations successives dans Cocoon

<xsp:page language="java"
xmlns:xsp="http://www.apache.org/1999/XSP/Core">

<xsp:structure>
<xsp:include>java.sql.*</xsp:include>
</xsp:structure>

<Promotion auteur="Jules">

<xsp:logic>
DriverManager.registerDriver(new org.gjt.mm.mysql.Driver());
// Connection à la base
Connection conn = DriverManager.getConnection
("jdbc:mysql://localhost/Station",
"visiteurStation", "mdpVisiteur");
Statement stmt = conn.createStatement ();
ResultSet resultat = stmt.executeQuery (
"select * from Station where nomStation=’Passac’");
</xsp:logic>

<Description>
Nous proposons une réduction de <Reduction>25</Reduction>
pourcent, restreinte à la période du
<Periode> <Debut>Septembre 2001</Debut>
au <Fin>Octobre 2001</Fin> </Periode> pour tous
les séjours dans certaines stations de vacances.
L’automne est une saison <Important>merveilleuse</Important>
pour reprendre des forces à la montagne. Vous pourrez
profiter du calme,
d’une nature aux couleurs chatoyantes, et d’un contact
privilégié avec l’autochtone. <Important>Attention
le nombre de places offertes est limité.</Important>
</Description>

<Station>
<nomStation><xsp:expr>resultat.getString (1)</xsp:expr></nomStation>
<capacite><xsp:expr>resultat.getString (2)</xsp:expr></capacite>
<lieu><xsp:expr>resultat.getString (3)</xsp:expr></lieu>
<region><xsp:expr>resultat.getString (4)</xsp:expr></region>
<tarif><xsp:expr>resultat.getString (5)</xsp:expr></tarif>
</Station>
232 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

</Promotion>
</xsp:page>

Il faut bien noter pour commencer que ce document est du XML tout à fait correct. Son élément racine
est xsp:page, et il contient de nombreux éléments appartenant à l’espace de nom xsp, déclaré de la
manière suivante :

xmlns:xsp="http://www.apache.org/1999/XSP/Core"

On trouve dans cette page les principaux éléments de XSP :

1. p xsp:structure q permet d’insérer des commandes d’inclusion de modules externes : dans le


cas de Java on trouve des p xsp:include q qui donnent les packages à utiliser (l’équivalent de
import) ;

2. p xsp:logic q est un élément dont le contenu est constitué de code Java (attention, c’est toujours
du XML donc il ne faut pas utiliser directement « < », mais la référence à l’entité &lt;) ;

3. p xsp:expr q enfin permet d’insérer dans le document le résultat d’une expression Java (il est
automatiquement converti en chaîne de caractères).

Dans notre exemple l’élément p xsp:logic q contient le code JDBC pour se connecter à la base et
évaluer une requête.

<xsp:logic>
DriverManager.registerDriver(new org.gjt.mm.mysql.Driver());
// Connection à la base
Connection conn = DriverManager.getConnection
("jdbc:mysql://localhost/Station",
"visiteurStation", "mdpVisiteur");
Statement stmt = conn.createStatement ();
ResultSet resultat = stmt.executeQuery (
"select * from Station where nomStation=’Passac’");
</xsp:logic>

Quand ce code est exécuté au moment de la transformation par le producteur XSP, la variable resul-
tat est définie et il est possible d’y faire référence ailleurs dans le document, comme par exemple :

<Station>
<nomStation><xsp:expr>resultat.getString (1)</xsp:expr></nomStation>
<capacite><xsp:expr>resultat.getString (2)</xsp:expr></capacite>
<lieu><xsp:expr>resultat.getString (3)</xsp:expr></lieu>
<region><xsp:expr>resultat.getString (4)</xsp:expr></region>
<tarif><xsp:expr>resultat.getString (5)</xsp:expr></tarif>
</Station>

Il reste une dernière particularité dans ce document, les instructions de traitement placée dans le pro-
logue :
<?cocoon-process type="xsp"?>
<?cocoon-process type="xslt"?>
<?xml-stylesheet href="Promotion.xsl" type="text/xsl"?>

Ces instructions indiquent que deux transformations successives doivent être appliquées. La première
est un traitement des instructions XSP. Tout se passe en fait – au moins conceptuellement – comme dans
le cas de XSLT. Le document est transformé en arbre DOM, puis le processeur XSP regarde les nœuds de
l’espace de nom xsp:, évalue leur contenu (en l’occurrence en exécutant le code Java qui s’y trouve) et
remplace le nœud par les données caractères produites par cette exécution.
7.3. XML DYNAMIQUE 233

Ensuite l’élément racine p xsp:page q est supprimé. L’élément p xsp:page q ne peut avoir qu’un
seul élément littéral fils, qui devient l’élément racine après cette suppression. Dans notre cas c’est p Promotion q
qui devient donc l’élément racine.
Le document obtenu est alors soumis à une seconde transformation, avec XSLT cette fois, définie par
le programme Promotion.xsl. Il faut souligner que la séquence XSP-XSLT n’est pas une obligation et que
toute manipulation peut être appliquée à un document issu d’une évaluation XSP.

Séparation des points de vue


Pour l’instant on peut dire que nous n’avons pas gagné grand chose pour la séparation des points de vues
puisqu’il a fallu insérer dans un document XML du code Java, avec du SQL et du JDBC. L’étape suivante
est elle-aussi inspirée des JSP et consiste à définir des librairies de balises, strictement conformes à la
syntaxe XML cette fois. Voici la nouvelle et dernière version de notre promotion :
Exemple 102 PromotionXSPLib.xml : Un document XSP avec balise dynamique
<?xml version="1.0" encoding="ISO-8859-1"?>

<?cocoon-process type="xslt"?>
<?xml-stylesheet href="PromotionXSP.xsl" type="text/xsl"?>

<Promotion auteur="Jules"
xmlns:BDS="http://cortes.cnam.fr/Station">

<Description>
Nous proposons une réduction de <Reduction>25</Reduction>
pourcent, restreinte à la période du
<Periode> <Debut>Septembre 2001</Debut>
au <Fin>Octobre 2001</Fin> </Periode> pour tous
les séjours dans certaines stations de vacances.
L’automne est une saison <Important>merveilleuse</Important>
pour reprendre des forces à la montagne. Vous pourrez
profiter du calme,
d’une nature aux couleurs chatoyantes, et d’un contact
privilégié avec l’autochtone. <Important>Attention
le nombre de places offertes est limité.</Important>
</Description>

<BDS:Station nom="Passac"/>

</Promotion>

Cette fois il n’y a plus de JavaṪout le code qui apparaissait dans la version précédente est maintenant
réduit à :
<BDS:Station nom="Passac"/>

Il s’agit d’un élément XML très simple, appartenant à un espace de nom « BDS: » qui désigne notre
librairie de balises, et contenant un attribut qui permet de paramétrer la station que l’on souhaite obtenir.
La signification de cet élément est : « insère ici, à chaque fois que ce document est utilisé, une description
XML de la station dont le nom est donné dans l’attribut nom. ». Cette insertion est dynamique : si la base
de données change, le contenu du document reflètera ce changement dès qu’on y accèdera à nouveau.
Par quelle miracle est-on passé d’un document très compliqué avec du code Java à un document très
simple sans aucune instruction de programmation ? Et bien tout simplement (!) en ajoutant une nouvelle
étape de transformation pour traiter la balise dynamique. Cette étape devient la première du processus de
transformation, et elle consiste à recopier le document tel quel, sauf la balise dynamique qui est remplacée
par le code java que nous avons vu tout à l’heure. Dans Cocoon, cette première transformation est prise en
charge par XSLT. Voici le programme PromotionXSP.xsl qui traite notre balise dynamique :
234 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

Exemple 103 PromotionXSP.xsl : La transformation XSLT associée à la balise dynamique


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsp="http://www.apache.org/1999/XSP/Core"
xmlns:BDS="http://cortes.cnam.fr/Station">

<xsl:template match="Promotion">

<xsl:processing-instruction name="cocoon-process">
type="xsp"
</xsl:processing-instruction>
<xsl:processing-instruction name="cocoon-process">
type="xslt"</xsl:processing-instruction>
<xsl:processing-instruction name="xml-stylesheet">
href="Promotion.xsl" type="text/xsl"
</xsl:processing-instruction>

<xsp:page language="java" xmlns:xsp="http://www.apache.org/1999/XSP/Core">


<xsp:structure>
<xsp:include>java.sql.*</xsp:include>
</xsp:structure>
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsp:page>

</xsl:template>

<xsl:template match="BDS:Station">
<xsp:logic>
DriverManager.registerDriver(new org.gjt.mm.mysql.Driver());
// Connection à la base
Connection conn = DriverManager.getConnection
("jdbc:mysql://localhost/Station",
"visiteurStation", "mdpVisiteur");
Statement stmt = conn.createStatement ();
ResultSet resultat = stmt.executeQuery (
"select * from Station "
+ "where nomStation=’<xsl:value-of select=’@nom’/>’");
// Affichage du résultat
resultat.next ();

<Station>
<nomStation><xsp:expr>resultat.getString (1)</xsp:expr></nomStation>
<capacite><xsp:expr>resultat.getString (2)</xsp:expr></capacite>
<lieu><xsp:expr>resultat.getString (3)</xsp:expr></lieu>
<region><xsp:expr>resultat.getString (4)</xsp:expr></region>
<tarif><xsp:expr>resultat.getString (5)</xsp:expr></tarif>
</Station>
</xsp:logic>
</xsl:template>

<xsl:template match="@*|node()" priority="-1">


<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
7.3. XML DYNAMIQUE 235

</xsl:template>
</xsl:stylesheet>

Puisque vous êtes maintenant familiarisé avec XSLT, vous pouvez constater que ce programme ap-
pliqué au document PromotionXSPLib.xml (page 233) va créer un document résultat identique à Promo-
tionXSP.xml (page 230). Voici quand même quelques explications pour vous faciliter la tache :
r les instructions de traitement de PromotionXSP.xml sont obtenue avec xsl:processing-intruction :

<xsl:processing-instruction name="cocoon-process">
type="xsp"
</xsl:processing-instruction>
r les règles du programme XSLT recopient le document source : notez que la dernière a une priorité
égale à -1 ;
r la règle avec le pattern BDS:Station est prise en priorité quand le nœud correspondant à la balise
dynamique est traité : c’est alors le code Java qui est inséré dans le résultat ;
r remarquez enfin que le nom de la station à rechercher dans la requête SQL est pris dans le document
source grâce à xsl:value-of. Il s’agit de l’attribut nom de la balise dynamique :

ResultSet resultat = stmt.executeQuery (


"select * from Station "
+ "where nomStation=’<xsl:value-of select=’@nom’/>’");

Il reste à appliquer au document résultat les deux transformations déjà étudiées, l’une avec XSP, et
l’autre avec XSLT, pour obtenir la version finale.
Il existe dans Cocoon des mécanismes qui permettent d’associer automatiquement à un espace de nom
comme BDS des programmes XSLT qui vont remplacer un élément par le code Java correspondant. Nous
ne décrivons pas ces mécanismes qui dépassent le cadre de ce livre, d’autant que notre but est maintenant
atteint. Nous avons :

1. un document XML simple et intégrant des balises « dynamiques » de manière transparente : le ges-
tionnaire de contenu peut se contenter de connaître la signification de ces balises, sans avoir à com-
prendre leur fonctionnement ;
2. un programme XSLT/XSP qui contient la « logique » de l’application : nous avons montré l’exemple
d’un accès base de données avec Java, mais on peut imaginer toutes sortes d’architectures, avec par
exemple l’utilisation de beans comme celui que nous avons créé pour nos exemples JSP ;
3. enfin un ou plusieurs programmes XSLT pour transformer le document final en HTML, WML ou
XSL-FO/PDF.

L’utilisation de XSP reste relativement complexe, ce qui induit un coût de conception et de développe-
ment non négligeable si on veut aboutir à une vraie séparation des points de vue. De plus les performances
posent problème. La version 2.0 de Cocoon va probablement s’attacher à corriger ces défauts.

7.3.2 XSQL
L’utilitaire XSQL fait partie du XML Development Kit (XDK) d’Oracle, un ensemble d’outils de traitement
de documents XML comprenant les parseurs DOM et SAX, un processeur XSLT, et de nombreux packages
Java. Contrairement à XSP qui est un langage généraliste destiné à permettre l’inclusion de n’importe quel
code Java dans des pages XML, XSQL se concentre sur l’extraction de données d’une base Oracle avec
le langage SQL (quelque peu étendu), sur l’inclusion au format XML du résultat de la requête dans un
document, suivie enfin d’une transformation XSLT. XSQL est donc de ce point de vue plus limité que XSP,
mais s’avère en contrepartie beaucoup plus simple à utiliser.
236 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

XSQL fournit la plupart des fonctionnalités que nous étudions depuis le début de ce chapitre et constitue
donc un excellent exemple d’une réalisation pratique d’un environnement de publication web intégrant une
base de données. On y trouve :

1. le paramétrage du format de sortie XML, semblable à ce qu’offre notre petit outil ExportXML.java ;
2. la possibilité de paramétrer les requêtes avec des variables provenant par exemple d’une requête
HTTP ;
3. un enchaînement du processus d’intégration des données issues de la base avec une transformation
XSLT ;
4. enfin une cloisonnement (presque) complet entre les couches SQL, XML et XSLT.

Nous commençons par quelques exemples simples de documents XSQL avant de décrire les principales
options fournies par cet outil.

Exemples de documents XSQL


Nous reprenons bien entendu notre base Station et notre document Promotion.xml (page 208) dans lequel
nous souhaitons toujours intégrer dynamiquement des données issues de la base. Voici le document XSQL
pour atteindre ce but :
Exemple 104 Promotion.xsql : Le document XSQL avec la promotion pour Passac
<?xml version="1.0" encoding="ISO-8859-1"?>

<?xml-stylesheet href="Promotion.xsl" type="text/xsl"?>

<Promotion auteur="Jules">
<Description>
Nous proposons une réduction de <Reduction>25</Reduction>
pourcent, restreinte à la période du
<Periode> <Debut>Septembre 2001</Debut>
au <Fin>Octobre 2001</Fin> </Periode> pour tous
les séjours dans certaines stations de vacances.
L’automne est une saison <Important>merveilleuse</Important>
pour reprendre des forces à la montagne. Vous pourrez
profiter du calme,
d’une nature aux couleurs chatoyantes, et d’un contact
privilégié avec l’autochtone. <Important>Attention
le nombde de places offertes est limité.</Important>
</Description>

<xsql:query connection="connexionVisiteur"
xmlns:xsql="urn:oracle-xsql">
SELECT * FROM Station WHERE nomStation=’Passac’
</xsql:query>

</Promotion>

On retrouve les même principes déjà étudiés pour XSP (et, plus globalement, pour des langages de
production de HTML dynamique comme les JSP). Ce document est un document XML, certaines balises
étant associées à un espace de nom particulier (ici xsql). Le processeur qui traite ce document reconnaît
ces balises comme des instructions, déclenche un traitement et crée un nouveau document dans lequel les
balises « dynamiques » sont remplacées par le résultat de ce traitement.
Le principal élément de XSQL est p xsql:query q . Son contenu est une requête SQL (ici l’interrogation
de la table Station), et il peut prendre un ensemble d’attributs pour paramétrer notamment la manière dont
le résultat est mis en forme XML. Les deux attributs utilisés dans ce premier exemple sont :
7.3. XML DYNAMIQUE 237

r connection qui indique le nom de la connexion à utiliser pour accéder à Oracle ; ce nom de
connexion est associé, dans un fichier de paramétrage, au compte utilisateur ainsi qu’à la base à
utiliser ;
r la déclaration de l’espace de nom xmlns.

Ce document peut être traité dans plusieurs des architectures présentées précédemment : avec un pro-
gramme lancé depuis la ligne de commande, avec une servlet, ou dans une page JSP.
En l’absence d’indication sur la mise en forme souhaitée, XSQL produit un document XML de la forme
suivante :

Exemple 105 Station.xsql : Le document XSQL résultat de la requête sur Passac

<?xml version="1.0" encoding="ISO-8859-1"?>

<ROWSET>
<ROW id="1">
<nomStation>Passac</nomStation>
<capacite>400</capacite>
<lieu>Alpes</lieu>
<region>Europe</region>
<tarif>1000.00</tarif>
</ROW>
</ROWSET>

L’élément racine du document est p ROWSET q (ensemble de lignes). Chaque ligne de la table est
représentée par un élément de type ROWSET, automatiquement identifié par un attribut id dont la valeur,
par défaut, est simplement un compteur sur les lignes du résultat. Enfin chaque colonne est également
représentée par un élément.
Ce résultat est intégré dans le document principal. Éventuellement un programme XSLT spécifié par
l’instruction de traitement p ?xml-stylesheet q est alors appliqué pour effectuer une transformation.
Voici maintenant comment utiliser des paramètres provenant d’une requête HTTP. Nous reprenons
notre exemple d’un serveur web permettant d’interroger la base Station en donnant trois paramètres (voir
notre servlet page 223 et son formulaire associé) : le nom de la station à afficher, le nom de l’élément racine
du document, et le nom de l’élément pour chaque ligne. Voici ce service d’interrogation avec XSQL :

Exemple 106 RequeteXSQL.xsql : Document XSQL avec paramètres

<?xml version="1.0" encoding="ISO-8859-1"?>

<xsql:query connection="connexionVisiteur"
xmlns:xsql="urn:oracle-xsql"
rowset-element="{@racine}"
row-element="{@element}">

SELECT * FROM Station WHERE nomStation=’{@nomStation}’

</xsql:query>

Les paramètres sont représentés par la syntaxe @nomParam. On peut les intégrer dans les attributs de
p xsql:query q , ou dans la requête SQL elle-même. Cet exemple montre deux nouveaux attributs de
cet élément :
r rowset-element définit le nom de l’élément racine du document produit, sa valeur par défaut
étant ROWSET ;
r row-element définit le nom de l’élément pour chaque ligne du résultat de la requête SQL.
238 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

Le document ci-dessus renvoie le résultat au format XML, mais on pourrait bien entendu appliquer un
programme de transformation XSLT sur le serveur avant la transmission au client.
XSQL fournit donc une interface très simple entre une base de données et XML. Il existe de nombreuses
autres éléments et options pour choisir par exemple la mise en forme XML, le mode de sérialisation du
document résultat, ou, à l’inverse, le stockage d’un document XML dans Oracle. Nous complétons cette
présentation en décrivant les possibilités de mise en forme du document XML produit par une requête
XSQL.

Options de sorties XML

XSQL fournit des options à plusieurs niveaux pour les options de sorties XML. Tout d’abord l’élément
p xsql:query q utilise un ensemble d’attributs présentés dans le tableau 7.1. Les plus importants ont
été illustrés dans les exemples qui précèdent.

Nom de l’attribut Description


rowset-element Nom de l’élément racine
row-element Nom de l’élément pour chaque ligne
max-rows Nombre maximal de lignes ramenées par la requête
skip-rows Nombre de lignes à ignorer dans le résultat
id-attribute Nom de l’attribut XML identifiant une ligne (id) par défaut
id-attribute-column Nom de la colonne constituant la clé du résultat (par défaut
XSQL crée un compteur de lignes)
null-indicator Si yes, inclut les valeurs à NULL avec un indicateur (par défaut
une valeur à NULL n’engendre pas d’élément).
tag-case Permet d’indiquer si les noms d’éléments sont en majuscules,
minuscules, ou respectent la casse utilisée dans la requête.
bind-params Définit une liste de paramètres

Table 7.1: Les attributs de l’élément xsql:query

Au niveau de la requête SQL elle-même, on peut agir sur le format du résultat en demandant notamment
une imbrication des éléments. En principe SQL est un langage qui agit sur des tables et produit une table.
Dans une table relationnelle, on trouve des lignes constituée d’attributs dont la valeur est « atomique » (un
entier, une chaîne de caractères). On ne peut pas en théorie dire qu’une valeur est un graphe, une autre table,
ou toute structure un tant soit peu complexe. Il n’existe donc, à aucun niveau, la possibilité de manipuler
une structure hiérarchique.
Oracle fournit deux types d’extensions pour étendre le modèle relationnel : au niveau du modèle, et
au niveau du langage d’interrogation. Au niveau du modèle le SGBD d’Oracle est, depuis la version 8,
« relationnel-objet », et permet d’imbriquer des types de données complexes dans des tables relationnelles.
La mise en forme XML d’une table de ce type reprend exactement l’imbrication du modèle Oracle.
La seconde possibilité apparaît au niveau du langage lui-même, avec l’opérateur CURSOR qui, utilisé
dans la clause SELECT, permet de constituer une résultat de requête qui comprend des attributs simples et
des tables imbriquées. Voici un exemple de requête SQL avec CURSOR :

SELECT nomStation, capacite,


CURSOR(SELECT libelle, prix FROM Activite
WHERE A.nomStation = S.nomStation) AS activites
FROM Station S

Dans la clause SELECT, nomStation et capacite sont des valeurs atomiques (des chaînes de
caractères), mais l’évaluation de CURSOR est une table. Ce troisième attribut est nommé activites
avec la clause AS. On obtient donc une table imbriquée dont voici la représentation XML (en nous limitant
à la station Passac).
7.4. PERSPECTIVES 239

<ROWSET>
<ROW num=’1’>
<nomStation>Passac</nomStation>
<capacite>400</capacite>
<activites>
<activites_row num=’1’>
<libelle>Ski</libelle>
<prix>200.00</prix>
</activites_row>
<activites_row num=’2’>
<libelle>Piscine</libelle>
<prix>20.00</prix>
</activites_row >
</activites>
</ROW>
</ROWSET>

On peut utiliser plusieurs curseurs, avec plusieurs niveaux d’imbrication, ce qui permet d’obtenir des
documents hiérarchiques XML arbitrairement complexes.

7.4 Perspectives
Comme dans toute situation où des systèmes basés sur des représentations différentes de l’information
doivent coexister, l’association entre XML et une base de données relationnelle, et les conversions néces-
saires aux échanges dans l’un ou l’autre sens, introduisent un niveau de difficulté supplémentaire dans des
architectures logicielles déjà passablement complexes. Nous n’avons parlé ici que de ce qui relève de notre
sujet, l’exportation de données vers XML afin de les intégrer à un système de publication basé sur XSLT.
L’opération inverse, le stockage de documents XML dans une base de données, est au moins aussi déli-
cate, la conversion d’une représentation hiérarchique comme XML vers une représentation relationnelle
« à plat » étant difficile à définir sans perte d’information.

Ce qu’une base de données fait mieux que XML


La question suivante se pose donc : puisque le modèle de XML semble plus puissant que celui des bases de
données relationnelles, pourquoi ne pas utiliser ce modèle et s’épargner ainsi le processus de transformation
des données ? Ou, pour dire les choses plus simplement, XML est-il un format de bases de données ?
On peut être tenté de répondre « oui », en prenant comme définition minimale d’une base de données
celle d’un ensemble d’information, structuré, et pouvant être sauvegardé sur disque. Cela étant XML ne
propose pas beaucoup plus dans ce cadre qu’un simple fichier de texte. Même si on prend en compte le
nombre considérable d’outils qui existent maintenant pour traiter des documents XML, de très grandes
différences subsistent avec les services fournis par un système de gestion de base de données. Citons-en
quelques-unes :
r Typage : il est difficile d’exprimer des contraintes sur des données XML, les DTD étant très insuff-
isantes de ce point de vue. Or un SGBD est capable de prendre en compte un grand nombre de
contraintes et de garantir leur satisfaction à tout moment.
r Interrogation : le langage qui se rapproche le plus de SQL est probablement ... XSLT ! Il n’offre
cependant pas du tout les mêmes facilités, notamment en terme d’intégration avec les langages de
programmation ;
r Mises à jour : même si on en parle moins, la possibilité d’effectuer des mises à jour (insertion,
destruction, modifications) est essentielle. Il n’existe pas en XML d’équivalent aux clauses UPDATE,
DELETE ou INSERT. On peut bien sûr utiliser un éditeur de texte, mais vec une absence à peu près
totale de contrôle.
240 CHAPTER 7. PUBLICATION DE BASES DE DONNÉES

r Performances : les SGBD proposent des structures d’index très performantes pour accéder aux don-
nées.
r Sécurité, transactions, ... : enfin beaucoup d’aspects systèmes liés à la sécurité des données (droits
d’accès, transactions, reprises sur panne) manquent en XML.

Certains systèmes utilisant XML comme format natif semblent en cours d’expérimentation, ce qui per-
mettra(it) de régler certains de ces problèmes. À l’heure actuelle il semble cependant plus raisonnable
d’utiliser une base de données classique dès qu’on a besoin de gérer un ensemble de données de taille con-
séquente, et de prendre plutôt XML comme format d’échange ou de « vue » sur les données pour certaines
applications. Il est cependant juste de signaler que certains travaux menés par le W3C visent à lever cer-
taines des limitations mentionnées ci-dessus. Nous en citons brièvement deux : l’introduction d’un typage
plus précis avec XML Schema, et le langage d’interrogation XML Query.

Plus de typage : XMLSchema


TODO: qq paragraphes sur XMl Schema

Interrogation avec XML Query


TODO: idem avec XML Query
Chapter 8

Un serveur de publication XML

Sommaire

241
242 CHAPTER 8. UN SERVEUR DE PUBLICATION XML
Appendix A

L’environnement XML/Apache

Sommaire

A.1 Le projet XML/Apache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244


A.2 Xalan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
A.2.1 Préliminaire : le Java Development Kit . . . . . . . . . . . . . . . . . . . . . . 245
A.2.2 Installation de Xalan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
A.2.3 Test d’expressions XPath avec ApplyXPath . . . . . . . . . . . . . . . . . . . . 245
A.2.4 Effectuer des transformations XSLT avec Xalan . . . . . . . . . . . . . . . . . 246
A.2.5 Utiliser Xalan en Applet ou en Servlet . . . . . . . . . . . . . . . . . . . . . . 247
A.3 Cocoon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
A.3.1 Tomcat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
A.3.2 Cocoon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
A.4 Intégration Apache/Tomcat/Cocoon . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
A.4.1 Compilateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
A.4.2 Apache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
A.4.3 PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
A.4.4 Lien Apache/Tomcat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
A.4.5 Et Cocoon ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252

Nous décrivons dans ce chapitre l’installation et l’utilisation des principaux outils du projet XML/Apache1.
Ce projet a pour principaux objectifs de fournir des logiciels et boîtes à outils de grande qualité, gratuits
et développés en suivant la philosophie Open Source : une communauté de programmeur contribue, via
le Web, à la conception, à l’élaboration et à l’amélioration de produits dont les sources sont librement
disponibles. Le site de référence est :

http://xml.apache.org

Il existe maintenant une très grande quantité de logiciels intégrant des fonctionnalités de traitement
XML, et nous ne prétendons pas que ceux de XML/Apache sont les meilleurs. Cet environnement offre
simplement l’avantage d’être gratuit, de s’installer relativement facilement, et de s’appuyer sur les librairies
XML de la fondation Apache, largement utilisées et qui suivent de près l’évolution des normes du W3C
(Xalan par exemple se présente comme un processeur XSLT totalement compatible avec la norme XSLT
1.0). Tous les exemples de ce livre ont été testés avec ces outils.
1 Ne pas confondre avec le serveur web Apache, qui n’est que l’un des logiciels – le plus connu – diffusé par la fondation Apache

dont les objectifs sont plus généraux.

243
244 APPENDIX A. L’ENVIRONNEMENT XML/APACHE

A.1 Le projet XML/Apache


Le projet est subdivisé en plusieurs sous-projets. Voici ceux dont nous décrivons l’installation et l’utilisation.
Deux sous-projets qui ne sont pas abordés ici sont Xang, un outils de production de pages web dynamiques
en JavaScript, et SOAP, un protocole d’échanges de services XML.

1. Xerces, un ensemble d’outils d’analyse avec notamment des parseurs SAX et DOM ;

2. Xalan, un processeur XSLT ;

3. Cocoon, un l’environnement de publication web XML/XSLT ;

4. FOP, une librairie permettant de formatter en PDF des documents XSL-FO.

Les parseurs SAX et DOM fournis par Xerces sont utilisés par les autres sous-projets pour analyser
et sérialiser les documents XML : nous ne détaillerons pas l’interface (API) qui est disponible en Java et
en C++. En revanche nous décrivons l’installation, et quelques exemple d’application de Xalan, qui peut
s’utiliser indépendamment de tout autre outil pour les tâches suivantes :

1. test interactif d’expressions XPath avec le programme Java ApplyXPath ;

2. transformation « statique » de documents XML avec XSLT : un exemple de production statique est
la génération de pages HTML destinées à être placées sur un serveur web ;

3. appel à l’API dans le cadre d’applications Java.

Xalan s’installe et s’utilise extrêmement facilement et peut vous fournir en peu de temps un environ-
nement de test.
Les choses sont un peu différentes pour Cocoon qui se présente sous la forme d’une servlet, autrement
dit un objet Java intégré à un serveur web qui prend en charge des requêtes HTTP. Il s’agit donc d’un outil
spécifiquement orienté vers la publication web. À l’heure où ces lignes sont écrites la version stable de
Cocoon est la 1.8, mais une version 2 – longtemps attendue – est en phase béta et devrait être prochainement
disponible. Cocoon en association avec un serveur web comme Tomcat fournit un environnement tout à
fait satisfaisant pour expérimenter la publication à base de documents XML/XSLT.
Enfin nous concluons le chapitre par l’installation d’une architecture plus complexe incluant le serveur
web Apache associé à PHP et à une base de données, et communiquant avec Tomcat pour les services
XML. Voici les sites web où vous pourrez récupérer tous les logiciels :
r pour le serveur web Apache, c’est www.apache.org ;
r pour Tomcat, c’est java.apache.org ;
r pour PHP, c’est www.php.net.

Toutes les installations sont décrites en prenant comme environnement de référence un serveur Linux.
Les outils étant écrit en Java, il n’y a pas de grandes différences quand on veut utiliser un serveur sous
Windows : nous citons ces différences au fur et à mesure.

A.2 Xalan
Xalan est une librairie Java, accompagnée de plusieurs programmes utilitaires ou de démonstration. La
librairie propose une API conforme à la – récente – norme TrAX qui définit l’interface d’un processeur
de transformation XSLT. Le fait de définir une interface commune permet (en principe...) de passer d’un
processeur à un autre sans avoir à réécrire toute une application.
Xalan s’appuie en principe sur les parseurs Xerces mais il peut – toujours en principe – utiliser d’autres
parseurs. Il existe en Java et C++ : c’est la version Java que nous décrivons ci-dessous.
A.2. XALAN 245

A.2.1 Préliminaire : le Java Development Kit


Toutes les applications sont écrites en Java. Il est donc indispensable de disposer d’un compilateur Java
raisonnablement récent, par exemple le 1.2. Si Java n’est pas installé sur votre machine, récupérez la
version la plus récente du Java Development Kit (JDK) sur le site http://java.sum.com et installez-la, par
exemple dans /usr/local. Par exemple :

cp jdk-1_2_2_007-linux-i386.tar.gz /usr/local
tar xvfz jdk-1_2_2_007-linux-i386.tar.gz /usr/local

Ces commandes créent un répertoire jdk-1.2.2. Il reste à modifier deux variables d’environnement pour
que le JDK soit disponible. Placez par exemple les commandes suivantes dans votre fichier .bashrc :

export JAVA_HOME=jdk-1.2.2
export PATH=$JAVA_HOME/bin:$PATH

Sous Windows il suffit de suivre exatement la même démarche, en définissant les variables soit dans le
fichier autoexec.bat, soit avec le panneau de contrôle, option Système.
À partir de là vous pouvez compiler du code Java avec la commande javac, et exécuter un programme
Java avec la commande java. Au cas où vous ne connaitriez pas du tout Java, rassurez-vous : il n’y a pas
besoin d’écrire du code.

A.2.2 Installation de Xalan


Récupérez la dernière version sur le site xml.apache.org. À l’heure où ces lignes sont écrites c’est Xalan-
Java 2. Le fichier pour Linux s’appelle xalan-XXX.tar.gz, et pour Windows xalan-XXX.tar.zip (le XXX
étant une partie variable en fonction des évolutions). Placez l’archive dans le répertoire de votre choix, et
décompressez-la.

cd /usr/local
cp xalan-XXX.tar.gz .
tar xvfz xalan-XXX.tar.gz

Cela crée un répertoire xalan-XXX qui contient, entre autre :

1. le sous-répertoire bin avec toutes les archives (librairies) Java (.jar) ;

2. un répertoire docs avec toute la documentation au format HTML ;

3. un répertoire samples avec de nombreux exemples d’utilisation.

Il ne reste plus qu’à placer les deux archives xerces.jar et xalan.jar dans la variable d’environnement
CLASSPATH. Voici un exemple (toujours sous Linux) : utilisez les commandes équivalentes pour Win-
dows.

export CLASSPATH=/usr/local/xalan-XXX/bin/xalan.jar:$CLASSPATH
export CLASSPATH=/usr/local/xalan-XXX/bin/xerces.jar:$CLASSPATH

C’est prêt ! Il est maintenant possible de compiler des programmes utilisant l’API de Xalan.

A.2.3 Test d’expressions XPath avec ApplyXPath


Xalan comprend un package org.apache.xpath.XPathAPI dédié au traitement des expressions
XPath. On peut appeler les méthodes de ce package pour faire de la programmation XML/XPath, mais
il y a beaucoup plus simple : un programme ApplyXPath permet d’interpréter interactivement des com-
mandes XPath. Ce programme se trouve dans le sous-répertoire samples/ApplyXPath. Il faut commencer
par compiler ApplyXPath.java :
246 APPENDIX A. L’ENVIRONNEMENT XML/APACHE

javac ApplyXPath.java

On obtient un fichier ApplyXPath.class qui peut être exécuté par une machine java avec la commande 2 :
java ApplyXpath fichierXML expressionXPath
Vous pouvez tester vos expressions XPath. Voici quelques exemples, en utilisant le fichier ExArbreX-
Path.xml que nous avons utilisé dans le chapitre 2 pour présenter XPath (voir page 87) et que vous pouvez
trouver sur notre site (le « % » indique le prompt du shell Linux) :

% java ApplyXPath ExArbreXPath.xml /A/B


<output>
<B att1="a1">
<D>Texte1</D>
<D>Texte2</D>
</B>
<B att1="a2">
<D>Texte2</D>
</B>
</output>

% java ApplyXPath ExArbreXPath.xml /A/*[@att2]


<output>
<C att2="a3" att3="15"/>
</output>

% java ApplyXPath ExArbreXPath.xml /A/C/@att3


<output>
15
</output>

Noter que toutes les expressions XPath sont basées sur des chemins absolus.

A.2.4 Effectuer des transformations XSLT avec Xalan


Le processeur XSLT de Xalan peut, comme le processeur XPath, être appelé à partir de la ligne de com-
mande. Voici la syntaxe de base :
java java org.apache.xalan.xslt.Process -in fichierXML -xsl FichierXSL -
out fichierHTML
L’option -out est facultative : par défaut le document résultat est affiché à l’écran. L’option -xsl est
également facultative si le document XML contient une instruction de traitement p ?xsl-stylesheet q
indiquant le programme XSLT à appliquer.
Voici un exemple de transformation interactive, avec des documents extraits des exemples donnés dans
le chapitre 1.

% java org.apache.xalan.xslt.Process -in Alien.xml -xsl Film.xsl


<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Film: Alien</title>
</head>
<body bgcolor="white">
<p>
<img height="220" align="left" SRC="Alien.gif"><h1>
<i>Alien</i>
2 Le fichier ApplyXPath.class doit être dans un répertoire référencés par la variable CLASSPATH.
A.3. COCOON 247

</h1>Science-fiction,
<i>Etats Unis</i>,
1979</p>
<p>
Mis en sc&egrave;ne par <b>Ridley Scott</b>
<h3>R&eacute;sum&eacute;</h3>Pr&egrave;s d’un vaisseau
spatial &eacute;chou&eacute; sur une lointaine
plan&egrave;te, des Terriens en mission
d&eacute;couvrent de bien &eacute;tranges
"oeufs". Ils en ram&egrave;nent un &agrave; bord,
ignorant qu’ils viennent d’introduire parmi eux
un huiti&egrave;me passager particuli&egrave;rement
f&eacute;roce et meurtrier.
</p>
</body>
Ce mode d’utilisation de Xalan peut être utile pour tester des programmes XSLT, ainsi que pour en-
gendrer des sites HTML « statiques » et éviter le coût de transformations dynamiques. De très nombreuses
autres options sont disponibles pour contrôler le format de sortie, passer des paramètres, etc. La définition
de paramètre de premier niveau par exemple s’effectue avec l’option :
-PARAM nomParam valeurParam
Si le programme XSLT appelé a un élément de premier niveau p xsl:param name=’nomParam’ q ,
la valeur valeurParam lui sera affectée. Nous renvoyons à la documentation de cet utilitaire (fichier
docs/commandline.html) pour plus d’informations.

A.2.5 Utiliser Xalan en Applet ou en Servlet


Les exemples fournis par Xalan incluent une Applet qui fournit la possibilité d’effectuer des transformations
côté client, et une servlet pour effectuer des transformations côté serveur.
L’applet se trouve dans le répertoire samples/AppletXMLtoHTML, avec une petite documentation et un
fichier appletXMLtoHTML.html qui permet d’avoir un aperçu de ses possibilités. En résumé, le principe
consiste à charger les archives xerces.jar et xalan.jar dans le navigateur et à accéder aux fonctionnalités de
transformation avec JavaScript ce qui permet de tout faire en local.
L’inconvénient immédiatement rencontré est la nécessité de transférer du serveur au client les deux
archives qui sont très volumineuses : 1,8M pour xerces.jar et 800K pour xerces.jar !!
En ce qui conerne la servlet, elle se trouve dans samples/servlet (fichier ApplyXSLT.java avec un peu
de documentation. La mise en place d’une servlet est un peu compliquée par la nécessité d’utiliser un
servlet container comme Tomcat. De plus Cocoon que nous présentons dans la prochaine section offre des
fonctionnalités plus puissantes.

A.3 Cocoon
Cocoon doit être associé à un serveur web capable de gérer les servlets. Nous proposons l’utilisation de
Tomcat, un serveur web entièrement écrit en java et également fourni par la fondation Apache. Cocoon
peut cependant fonctionner en association avec tout serveur compatible avec la version 2.0 des servlets :
nous vous renvoyons aux spécifications disponibles sur le site http://java.sun.org et à la documentation de
Cocoon pour toute installation avec un serveur autre que Tomcat.

A.3.1 Tomcat
Tomcat est un servlet container ce qui correspond, pour dire les choses brièvement, à un serveur web
capable de charger des objets java (les servlets) qui vont prendre en charge certaines requêtes HTPP et
engendrer dynamiquement le document HTML constituant la réponse.
248 APPENDIX A. L’ENVIRONNEMENT XML/APACHE

Tomcat est un sous-projet de Jakarta/Apache, le projet de la fondation Apache dédié aux environ-
nements Java, comme Cocoon est un sous-projet de XML/Apache. Vous pouvez récupérer Tomcat sur le
site
http://jakarta.apache.org
Si vous n’avez pas l’intention de modifier le code source (!), l’archive contenant les exécutables suffira.
Au moment où ces lignes sont écrites la version de référence est la 3.2.2, et le fichier archive s’appelle
jakarta-tomcat-3.2.2.tar.gz.
Comme d’habitude, il faut décompacter l’archive quelque part.
cd /usr/local
tar xvfz jakarta-tomcat-3.2.2.tar.gz
Et maintenant une bonne nouvelle : Tomcat est prêt ! On peut simplement le lancer en allant dans
jakarta-tomcat-3.2.2 et en entrant :

bin/startup.sh

Si la variable JAVA_HOME est correctement définie, Tomcat devrait se lancer sans problème. Cela
étant il est sans doute préférable de définir la variable d’environnement TOMCAT_HOME qui doit contenir
le chemin d’accès vers jakarta-tomcat-3.2.2 :

export TOMCAT_HOME=/usr/local/jakarta-tomcat-3.2.2

Tomcat est un serveur web. Par défaut il est lancé sur le port 8080 (vous pouvez changer cette valeur
dans le fichier conf/server.xml). Après le startup, on peut donc accéder à Tomcat à l’URL http://localhost:8080.
La page d’accueil propose de tester quelques exemples de servlets et de pages JSP.
Pour arrêter Tomcat, on exécute simplement :

bin/shutdown.sh

Le script tomcat.sh est lancé par startup et shutdown avec les options respectives start et stop. On peut
donc s’en servir comme script d’initialisation de Tomcat au lancement de Linux. Nous sommes maintenant
prêts pour installer Cocoon.

A.3.2 Cocoon
Cocoon est simplement (!) une servlet qui va être appelée par Tomcat. Récupérer Cocoon, sous la forme
habituelle d’un fichier .tar.gz, sur le site httpd://xml.apache.org et l’installer (par exemple) dans /usr/local/.
On obtient, en décompressant l’archive, un répertoire cocoon-1.8 (à la version près).
Pour installer Cocoon dans Tomcat, il faut commencer par quelques copies de fichier. Notez que
Cocoon est livré avec ses propres versions de xalan.jar et xerces.jar de manière à éviter les problèmes
consécutifs à des incompatibilités de version. Il est donc recommandé de s’en tenir aux librairies fournies
et de ne pas chercher à les mélanger avec d’autres.

1. Copier tous les .jar de COCOON_HOME/lib dans TOMCAT_HOME/lib ; copier également CO-
COON_HOME/bin/cocoon.jar dans TOMCAT_HOME/lib
Tomcat charge automatiquement toutes les classes dont le fichier .jar se trouve dans TOMCAT_HOME/lib,
ce qui évite d’avoir à configurer ce chargement.
2. Il faut maintenant ajouter un « contexte » à Tomcat pour lui indiquer quand il doit utiliser Cocoon.
Pour cela, ajouter la ligne suivante dans le fichier TOMCAT_HOME/conf/server.xml.

<Context path="/cocoon" docBase="webapps/cocoon"


debug="0" reloadable="true" >
</Context>
A.4. INTÉGRATION APACHE/TOMCAT/COCOON 249

Maintenant, toute URL commençant par /cocoon sera traitée par Cocoon, et les fichiers seront pris
dans TOMCAT_HOME/webapps/cocoon qui tient lieu d’adresse relative.

3. Finalement, il reste à placer des fichiers XML dans TOMCAT_HOME/webapps/cocoon. Commencez


par créer les répertoires :

mkdir TOMCAT_HOME/webapps/cocoon
mkdir TOMCAT_HOME/webapps/cocoon/WEB-INF

Puis copiez les fichiers fournis par Cocoon :

cp $COCOON_HOME/src/WEB-INF/web.xml
$TOMCAT_HOME/webapps/cocoon/WEB-INF
cp $COCOON_HOME/conf/cocoon.properties
$TOMCAT_HOME/webapps/cocoon/WEB-INF

Important : il faut éditer le fichier web.xml et indiquer un chemin d’accès relatif vers le fichier
cocoon.properties. Ce chemin doit être WEB-INF/cocoon.properties. Voici la partie du fichier, avec
la bonne valeur.

<servlet>
<servlet-name>org.apache.cocoon.Cocoon</servlet-name>
<servlet-class>org.apache.cocoon.Cocoon</servlet-class>
<init-param>
<param-name>properties</param-name>
<param-value>WEB-INF/cocoon.properties</param-value>
</init-param>
</servlet>

4. Dernière opération : copiez les fichiers de COCOON_HOME/samples dans TOMCAT_HOME/webapps/cocoon/samples.

Voilà ! Relancez Tomcat, et essayez d’accéder à l’URL http:localhost:8080/cocoon/Cocoon.xml ou


http:localhost:8080/cocoon/samples. En principe tout doit bien se passer mais... il se peut que le problème
suivant survienne : Tomcat initialise automatiquement la variable CLASSPATH au démarrage, en prenant
tous les .jar de TOMCAT_HOME/lib. Or, pour que Cocoon fonctionne, le .jar de Xerces doit être placé
avant les autres .jar dans le CLASSPATH.
Si Cocoon refuse de traiter un document XML, c’est probablement de là que vient le problème (un
jour où l’autre cette anomalie sera corrigée). La manipulation suivante devrait tout régler : renommez les
fichiers lib/xml.jar et lib/parser.jar en lib/zxml.jar et lib/zparser.jar. C’est scabreux, mais efficace.
Quand tout marche, vous êtes équipés d’un environnement de publication web à base de XML. Nous
vous invitons à consulter les exemples fournis dans cocoon/samples, en accédant avec votre navigateur à
l’URL

http:localhost:8080/cocoon/samples

Bien entendu vous pouvez également récupérer les exemples de ce livre et les tester dans votre propre
environnement.

A.4 Intégration Apache/Tomcat/Cocoon


Tomcat est un serveur web généraliste qui est capable de fournir des documents HTML, de gérer des
servlets et de traiter des Java Server Pages, une forme simplifiée des servlets permettant d’intégrer sou-
plement balises HTML et instructions Java. En pratique il n’est cependant pas recommandé de baser en
250 APPENDIX A. L’ENVIRONNEMENT XML/APACHE

totalité un serveur web sur Tomcat. Si Tomcat est parfait pour gérer des servlets et leurs dérivés (JSP), il est
loin d’être aussi souple, aussi paramétrable et aussi ouvert qu’un serveur web classique comme Apache.
Une solution robuste et ouverte à de très nombreux outils de développement consiste donc à faire
collaborer un serveur comme Apache et Tomcat, selon une architecture illustrée dans la figure A.1. Deux
serveurs web, Apache et Tomcat, tournent en parallèle, chacun en écoute sur le port réseau qui leur est
affecté. Dans notre schéma Apache est en écoute sur le port HTTP standard 80, tandis que Tomcat est
associé au port 8080.

Requêtes HTTP

80 8080
Transfert requêtes
Apache Servlets Tomcat

Cocoon Servlet A

Programmes CGI Pages HTML

Scripts PHP Doc. XML Pages JSP

Figure A.1: Architecture Apache-Tomcat-Cocoon

Toutes les requêtes peuvent être adressées au port 80 : s’il s’agit de demandes HTTP pour des docu-
ments HTML ou PHP, Apache les prend en charge sans recourir à Tomcat. En revanche des demandes qui
impliquent les services basés sur des servlets sont transmis par Apache à Tomcat.
C’est l’installation de cette architecture que nous décrivons ci-dessous. Encore une fois il est tout à fait
possible de s’arrêter à l’installation de Tomcat seul, et de s’en servir comme environnement de test.
Toutes les indications qui suivent ont été testées sous une version 7.0 de la distribution SuSe de Linux.

A.4.1 Compilateur
Éventuellement, il faut récupérer le compilateur GNU C++ si vous ne l’avez pas. On peut le trouver par ex-
emple à http://www.gnu.ai.mit.edu/software/gcc/gcc.html ou sur un site miroir GNU. Voici les commandes
permettant d’installer le compilateur :
1. Récupérez par le fichier gcc-2.8.1.tar.gz (ou version supérieure) et placez le dans /usr/local/src.
2. Décompressez l’archive, et extrayez son contenu :
% gunzip gcc-2.8.1.tar.gz
% tar xvf gcc-2.8.1.tar
Ce qui crée un nouveau répertoire gcc-2.8.1 dans /usr/local/src.
3. Placez vous dans ce répertoire avec la commande
% cd gcc-8.2.1
4. Entrez successivement les commandes suivantes :
% ./configure
% make
% make install
C’est tout ! Par défaut, l’installation se fait dans /usr/local/bin. Il faut donc mettre ce répertoire
au début de la variable PATH, avec une commande qui dépend du shell employé, ici pour les shell de type
Bourne comme bash :
% export PATH=/usr/local/bin:$PATH
Vous pouvez vérifier alors que tout s’est bien passé avec la commande gcc -v qui devrait vous afficher
gcc version 2.8.1 (ou version supérieure).
A.4. INTÉGRATION APACHE/TOMCAT/COCOON 251

A.4.2 Apache
Le plus simple d’installer Apache avec les modules dynamiques (DSO), ce qui évite de tout recompiler
à chaque fois. Commencez par décompacter l’archive apache_1.3.20 (ou une version ultérieure) quelque
part, disons dans /usr/local/src/apache_1.3.20. Placez le fichier archive dans /usr/local/src et entrez la
commande suivante :
% tar xvfz apache_1.3.20.tar.gz
Tous les fichiers vont être extraits de l’archive et placés dans le répertoire /usr/local/src/apache_1.3.20.
Allez alors dans ce répertoire et entrez les commandes suivantes :

./configure --prefix=/usr/local/apache --enable-module=so


make
make install

Apache est maintenant prêt et installé dans /usr/local/apache. Entrez les commandes suivantes : % cd
/usr/local/apache
% ./bin/apachectl start
httpd est lancé et se met en écoute sur le port 80 (à moins que vous n’ayez changé la valeur de Port
dans httpd.conf ). Pour lancer et stopper Apache avec Linux, copiez le script apachectl dans /etc/rc.d et
créez dans /etc/rc.d/rc3.d deux liens comme suit :

ln -s ../apachectl S33Apache
ln -s ../apachectl K33Apache

A.4.3 PHP
Pour ajouter le module PHP (optionnel !), entrez les commandes suivantes dans le répertoire racine des
sources de PHP (on peut ajouter l’option --with-mysql si vous avez installé MySQL) :

./configure --with-apxs=/usr/local/apache/bin/apxs
make
make install

La dernière commande copie le fichier libphp4.so dans /usr/local/apache/libexec, et indique à Apache


que le module doit être chargé en plaçant la commande suivante dans le fichier httpd.conf :

LoadModule php4_module libexec/libphp4.so

Il ne reste plus qu’à décommenter les lignes suivantes dans httpd.conf pour que PHP soit disponible :

AddType application/x-httpd-php .php


AddType application/x-httpd-php-source .phps

Maintenant si MySQL ou un autre SGBD est aussi installé, on dispose d’un environnement complet
pour faire de la programmation web et base de données avec PHP. On se servira de cet environnement
pour toutes les requêtes HTTP demandant du HTML ou du PHP, et on redirigera vers Tomcat toutes les
demandes de type XML/XSLT ou JSP.

A.4.4 Lien Apache/Tomcat


Il reste à bien répartir le travail entre Apache et Tomcat. Le premier doit prendre en charge tous les
documents classiques, type HTML, PHP ou autre, et passer la main au second pour les servlets, les JSP
ou les documents XML. Initialement, on utilisait le module JServ pour permettre à Apache de prendre
en compte les servlets. Maintenant il est plus simple d’utiliser le module JK. Un fichier mod_jk.so est
disponible sur java.apache.org avec Tomcat. Installez ce fichier dans /usr/local/apache/libexec. Si par
malheur ce fichier ne correspond pas à votre distribution, il n’y a plus qu’à le recompiler...
252 APPENDIX A. L’ENVIRONNEMENT XML/APACHE

1. Récupérez le code source de Tomcat sur java.apache.org


2. Décompressez-le, et allez dans src/native/apache1.3 (vérifiez la version d’Apache).
3. La commande de compilation est la suivante :
apxs -o mod_jk.so -I../jk -I/usr/local/jdk/include \
-I/usr/local/jdk/include/linux -I../jk \
-c *.c ../jk/*.c
Le programme apxs est dans /usr/local/apache/bin, et il faut vérifier que le JDK est bien installé dans
/usr/local, ou modifier les options -I de manière appropriée.
4. Copiez le fichier mod_jk.so dans /usr/local/apache/libexec.
Maintenant il faut inclure dans le fichier dans httpd.conf les directives pour charger le module JK et
pour lui signaler que certaines URL doivent être transmises à Tomcat.
Par chance (!) Tomcat produit automatiquement un fichier de configuration qui doit suffire dans la
plupart des cas. Ce fichier est dans TOMCAT_HOME/conf et s’appelle mod_jk.conf-auto. Attention : ce
fichier est regénéré à chaque lancement de Tomcat. Commencez par le copier avant de faire une modifica-
tion :
cp mod_jk.conf-auto mon-mod-jk.conf
Il faut inclure ce fichier dans le httpd.conf :
Include /usr/local/jakarta-tomcat-3.2.1/conf/mon-mod-jk.conf
Ce fichier inclut lui-même un autre fichier, nommé workers.properties, qui indique à Apache comment
communiquer avec Tomcat. Il faut éditer workers.properties et mettre les bonnes valeurs. Par exemple :
workers.tomcat_home=usr/local/jakarta-tomcat-3.2.1
workers.java_home=/usr/lib/jdk1.1.8
ps=/
Bien. Redémarrons Apache et Tomcat, et essayons d’accéder à l’URL suivante :
http://localhost/examples/jsp/
C’est le serveur Apache qui a reçu la requête (noter l’absence du port 8080). Comme elle commence
par /examples, Apache transmet cette requête à Tomcat. Cette redirection est spécifiée par une directive
JkMount dans le fichier mon-mod-jk.conf.

A.4.5 Et Cocoon ?
Il reste à indiquer à Apache ce qu’il faut faire en présence d’un fichier XML. Bien entendu il faut traiter ce
XML avec Cocoon. Voici les lignes à ajouter dans le fichier mon-mod-jk.conf.
Alias /cocoon TOMCAT_HOME/webapps/cocoon
<Directory "TOMCAT_HOME/webapps/cocoon">
Options Indexes FollowSymLinks
</Directory>
JkMount /cocoon/*.xml ajp12
AddType text/xml .xml

<Location /cocoon/WEB-INF/ >


AllowOverride None
deny from all
</Location>
Maintenant, vous devriez, en accédant à Apache, pouvoir rediriger vers Cocoon une URL comme :
localhost://cocoon/Cocoon.xml
Appendix B

Référence XPath/XSLT

Sommaire

B.1 Éléments XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253


B.2 Fonctions XPath/XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282

Cette annexe est consacrée aux éléments et aux fonctions XLST. Elle est conçue et présentée comme
une référence, venant compléter les chapitres « explicatifs » qui précèdent. Contrairement aux autres
chapitres de ce livre qui suivaient un ordre basé sur la thématique et la mise en œuvre des fonctionalités
XSLT, la présentation suit l’ordre alphabétique pour faciliter la recherche. Nous donnons une description
la plus concise et informative possible de chaque élément, en renvoyant si besoin est à la page du livre qui
développe des explications et des exemples sur son utilisation.
Vous pouvez aussi vous aider de l’annexe pour trouver toutes les pages de ce livre qui traitent d’un
élément XSLT donné, les pages relatives à la référence étant indiquées en gras.

B.1 Éléments XSLT


La liste des éléments XSLT a été donnée dans le chapitre 3, avec une répartition en éléments de premier
niveau (tableau 3.1 page 112) et en instructions (tableau 3.2 page 114). Dans ce qui suit nous reprenons,
dans l’ordre alphabétique cette fois, tous ces éléments en donnant la syntaxe complète, une description de
la sémantique, et éventuellement un ou deux exemples complétant ceux que vous avez déjà pu trouver dans
les chapitres qui précèdent.
Chaque élément est défini par son type, la liste de ses attributs, et le type de son contenu. Pour les at-
tributs nous distinguons ceux qui sont obligatoires, indiqués en gras, de ceux qui sont optionnels, indiqués
simplement avec une police à chasse fixe.
Il est possible d’exprimer des contraintes sur le type d’un attribut ou d’un élément sous la forme de
catégories syntaxiques qui définissent la forme que peut prendre la valeur de l’attribut ou le contenu de
l’élément. Quand c’est le cas nous l’indiquons dans la description de l’élément. Les catégories syntaxiques
les plus courantes sont rappelées dans le tableau B.1.
Nous utilisons les conventions des DTD pour indiquer éventuellement l’ordre ou la multiplicité d’apparition
de telle ou telle catégorie syntaxique dans le contenu d’un élément.

xsl:apply-imports

Syntaxe

p xsl:apply-imports/ q

253
254 APPENDIX B. RÉFÉRENCE XPATH/XSLT

Désignation Description
Expression Toute expression XPath
QName Le terme Qualified name (QName) désigne tout
nom d’élément XML valide, comme par exemple
xbook:monEl. Un QName se compose d’un
préfixe, optionnel (en l’occurrence xbook), cor-
respondant à un espace de nom déclaré, et d’un
nom local, obligatoire (ici monEl)
NCName Cette catégorie désigne tout nom XML valide,
utilisable par exemple por un préfixe, ou un nom
local, ou un nom d’élément.
Pattern Les patterns appartiennent au sous-ensemble
des expressions XPath autorisées dans l’attribut
match de l’élément xsl:template : voir
page 119
URI Un Uniform Resource Identifier. Il prend le plus
souvent la forme d’un fichier local, ou d’une
adresse HTTP
Corps de règle Un corps de règle (voir page 111) est toute com-
binaison de texte littéral, d’éléments littéraux
(c’est-à-dire non interprétés par le processeur) et
d’instructions XSLT correctement formées. Un
corps de règle définit un fragment du document
XML à instancier au cours du traitement

Table B.1: Catégories syntaxiques

Description
Quand on importe un programme XSLT dans un autre, les règles du programme importé ont une priorité in-
férieure à celles du programme importateur. Une des conséquences est que la règle importée est remplacée,
ce qui n’est pas toujours l’effet souhaité. On peut très bien vouloir utiliser cette règle, et la compléter
par d’autres instructions. Dans ce cas on utilise, dans le corps de la règle, l’instruction xsl:apply-
imports.
Cette fonctionnalité s’apparente au mécanisme de surcharge de méthode dans la programmation orientée-
objet. Notez qu’il est souvent possible d’obtenir le même résultat avec xsl:call-template.
XSLT prévoit la possibilité de passer des paramètres à la règle importée en plaçant dans son contenu
une ou plusieurs instructions xsl:with-param (voir page 282).

Exemple
Voici par exemple un programme XSLT qui contient une règle de présentation standard pour le contenu
d’un élément p PERSONNE q (nom, prénom, date de naissance) :
Exemple 107 Personne.xsl : Un règle générique pour les personnes
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<html>
<head><title>Ficher personne</title></head>
<body bgcolor="white">
<xsl:apply-templates/>
B.1. ÉLÉMENTS XSLT 255

</body></html>
</xsl:template>

<xsl:template match="PERSONNE">
<b> Prénom</b> : <xsl:value-of select="PRENOM"/>,
<b> Nom </b> :<xsl:value-of select="NOM"/>,
Né le <i><xsl:value-of select="NAISSANCE"/></i>
</xsl:template>

</xsl:stylesheet>

Maintenant supposons qu’on se trouve avec une occurrence d’un élément de type PERSONNE plus
détaillée, comme celle du fichier ci-dessous.

Exemple 108 JohnDoe.xml : Le salarié John Doe


<?xml version="1.0" encoding="ISO-8859-1"?>

<PERSONNE NOSS="17517652987">
<NOM>Doe</NOM>
<PRENOM>John</PRENOM>
<NAISSANCE>15:10:1981</NAISSANCE>
<POSTE>Directeur Informatique</POSTE>
<SALAIRE>50 000</SALAIRE>
</PERSONNE>

Au lieu de redéfinir complètement la règle du programme Personne.xsl, on peut l’importer, puis l’utiliser
avec xsl:apply-import inséré dans la nouvelle règle de traitement des éléments de type PERSONNE

Exemple 109 ApplyImports.xsl : Utilisation de xsl:apply-imports


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:import href="Personne.xsl"/>
<xsl:output method="html" indent="yes"/>

<xsl:template match="/">
<html>
<head><title>Ficher personne</title></head>
<body bgcolor="white">
<xsl:apply-templates/>
</body></html>
</xsl:template>

<xsl:template match="PERSONNE">
<xsl:apply-imports/>

<b> Poste</b> : <xsl:value-of select="POSTE"/>,


<b> Salaire </b> :<xsl:value-of select="SALAIRE"/>
</xsl:template>

</xsl:stylesheet>

Une règle est utilisée dans xsl:apply-imports si et seulement si elle s’applique au nœud courant
et si elle a été importée. Une solution simple pour être sûr qu’une règle importée et une règle locale
s’appliquent au même nœud est bien entendu qu’elles aient toutes deux le même pattern.
256 APPENDIX B. RÉFÉRENCE XPATH/XSLT

xsl:apply-templates

Syntaxe
p xsl:apply-templates
select=Expression
mode=QName q
( p xsl:with-param q | p xsl-sort q )s
p /xsl:apply-templates q

Description
Cette instruction désigne tous les nœuds à traiter au sein du document source (ou, éventuellement, d’un
document référencé par la fonction document()). Le processeur détermine alors pour chaque élément sélec-
tionné la règle à appliquer. Les deux attributs possibles sont optionnels. L’attribut select est une expres-
sion XPath dont l’évaluation doit donner un ensemble de nœuds. Si cette expression est relative, le nœud
contexte est le nœud du document source qui a instancié la règle contenant xsl:apply-templates
(voir page 81). Si select est absent, alors les nœuds sélectionnés sont les fils du nœud courant (autrement
la valeur par défaut de select est child::node()).
L’attribut mode indique un critère complémentaire pour la sélection des règles à appliquer. Si cet
attribut est présent avec ue valeur nomMode, seules les règles xsl:template ayant elles-mêmes un
attribut mode égale à nomMode seront prises en compte (voir page 126).
On peut passer des paramètres aux règles déclenchées importée en plaçant dans le contenu de xsl:apply-
templates un ou plusieurs instructions xsl:with-param (voir page 282).
Par défaut les éléments sélectionnés sont pris en compte dans l’ordre de parcours du document. En
introduisant un ou plusieurs éléments xsl:sort, on peut changer cet ordre : voir page 277.

Exemples
xsl:apply-templates est bien entendu l’un des éléments les plus utilisés. De très nombreux exemple
ont été donnés dans ce livre : voir notamment la section consacrée au règles, page 119 du chapitre 3.

xsl:attribute

Syntaxe
p xsl:atrribute
name=QName
namespace=URI q
Corps de règle p /xsl:attribute q

Description
Cet élément déclenche l’ajout d’un attribut dans l’élément courant du document résultat. Cet élément
courant peut être soit un élément littéral, soit un élément créé avec l’instruction xsl:element, soit un
élément du document source copié avec xsl:copy. L’élément xsl:attribute doit être instancié
immédiatement après la balise ouvrante de l’élément courant.
Le contenu dexsl:attribute définit la valeur de l’attribut. C’est un corps de règle qui peut contenir
d’autres instructions XSLT, et doit impérativement engendrer un nœud de type Text (donc sans marquage).
Il est possible de calculer les deux attributs, name et namespace, en utilisant des expressions XPath
encadrées par { }, désignées par le terme (attribute value template). Ce même mécanisme est applicable
pour placer directement les attributs dans l’élément, sans avoir donc besoin d’utiliser xsl:attribute.
Voici quelques exemples pour illustrer ces possibilités.
B.1. ÉLÉMENTS XSLT 257

Exemples
Reprenons le document JohnDoe.xml, page 255. Il contient un élément racine de type PERSONNE, avec
des fils NOM et PRENOM. Le programme suivant crée un document contenant un seul élément, les fils étant
transformés en attributs.

Exemple 110 Attribute1.xsl : L’élément xsl:attributes


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="PERSONNE">
<PERSONNE>
<xsl:attribute name="NOM">
<xsl:value-of select="NOM"/>
</xsl:attribute>
<xsl:attribute name="PRENOM">
<xsl:value-of select="PRENOM"/>
</xsl:attribute>
</PERSONNE>
</xsl:template>

</xsl:stylesheet>

Le résultat de la transformation est :


p ?xml version="1.0" encoding="UTF-8"? q
p PERSONNE NOM="Doe" PRENOM="John"/ q
Maintenant on obtient exactement le même résultat avec le programme suivant :

Exemple 111 Attribute2.xsl : Un programme équivalent, sans xsl:attributes


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="PERSONNE">
<PERSONNE NOM="{NOM}" PRENOM="{PRENOM}"/>
</xsl:template>

</xsl:stylesheet>

Alors quel est l’intérêt d’utiliser xsl:attribute ? Et bien dans tous les cas où on ne veut pas
l’associer à un élément littéral (par exemple quand l’élément est engendré par xsl:element), ou quand
le nom ou la valeur de l’attribut sont calculés par des expressions complexes.
Voici un exemple où on veut ajouter un attribut AGE à l’élément p PERSONNE q dans le document
résultat, en calculant la valeur de cet attribut par différence entre l’année courante (disons que c’est 2002)
et l’année de naissance.

Exemple 112 Attribute3.xsl : L’élément xsl:attributes, avec une valeur calculée


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="PERSONNE">
<PERSONNE NOM="{NOM}" PRENOM="{PRENOM}">
<xsl:attribute name="AGE">
<xsl:value-of select="2002 - substring(NAISSANCE/text(),7)"/>
258 APPENDIX B. RÉFÉRENCE XPATH/XSLT

</xsl:attribute>
</PERSONNE>
</xsl:template>

</xsl:stylesheet>

On pourrait certes mettre l’expression directement dans la balise p PERSONNE q , comme pour NOM,
mais on arrive rapidement aux limites de cette solution quand on utilise pour calculer la valeur de l’attribut
des tests, des itérations, etc.

xsl:attribute-set

Syntaxe
p xsl:attribute-set
name=QName
use-attribute-sets=QNames q
p xsl:attribute qts
p /xsl:attribute-set q

Description
Cet élément permet de grouper des définitions d’attributs, et de nommer les groupes ainsi constitués afin
de pouvoir les affecter d’un bloc à un élément. Cette fonctionnalité est assez proche des feuilles de style
(CSS) dans lesquelles on factorise des propriétés de mise en forme de certains éléments HTML.
L’attribut name est obligatoire : il sert à référencer le groupe d’attribut. Le second attribut, use-
attribute-set, permet de composer récursivement un groupe d’attributs à l’aide d’autres groupes. La
valeur de attruse-attribute-set doit être une liste de noms de groupe d’attributs, séparés par des espaces. On
peut ainsi par exemple définir un groupe pour les attributs relatifs aux polices de caractères, un autre pour
les couleurs, et les grouper tous deux dans un troisième groupe.
Il est possible de trouver plusieurs groupes d’attributs avec le nom dans un programme XSLT. Dans ce
cas le processeur fusionne les deux listes.
Pour affecter un groupe d’attribut à un élément, on utiliser l’attribut use-attribute-sets des
éléments xsl:copy ou xsl:element : voir pages 264 et 267, ou introduire un attribut xsl:use-
attribute-sets dans un élément littéral.

Exemple
Le programme suivant définit un groupe nommé MonStyle avec des attributs de présentation reconnus
par HTML. Ce groupe est ensuite appliqué à l’élément p body q .

Exemple 113 AttributeSet.xsl : L’élément xsl:attribute-set


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:attribute-set name="MonStyle">
<xsl:attribute name="bgcolor">white</xsl:attribute>
<xsl:attribute name="font-name">Helvetica</xsl:attribute>
<xsl:attribute name="font-size">18pt</xsl:attribute>
</xsl:attribute-set>

<xsl:template match="/">
<html>
<head><title>Ficher personne</title></head>
B.1. ÉLÉMENTS XSLT 259

<body xsl:use-attribute-sets="MonStyle">
Exemple de use-attribut-sets
</body>
</html>
</xsl:template>

</xsl:stylesheet>

L’application de ce programme produit le résultat suivant :

Exemple 114 AttributeSet.html : Résultat du programme précédent


<html>
<head>
<META http-equiv="Content-Type"
content="text/html; charset=UTF-8">
<title>Ficher personne</title>
</head>
<body bgcolor="white" font-name="Helvetica"
font-size="18pt">
Exemple de use-attribut-sets
</body>
</html>

xsl:call-template

Syntaxe
p xsl:call-template
name=QName q
p xsl:with-param qts
p /xsl:call-template q

Description
L’élément xsl:call-template permet d’appeler une règle par son nom. Il est utilse dès qu’un frag-
ment doit être instancié à plusieurs endroits d’un programme. Pour éviter des répétitions, on peut placer ce
fragment être placé dans une règle, et appeler cette règle avec xsl:call-template. Le ou les éléments
xsl:with-param peuvent être utilisés pour passer des paramètres à la règle : voir page 282.
La fonctionnalité apportée par cet élémet s’apparente à un appel de fonction dans un langage de pro-
grammation classique. Il faut noter cependant qu’il n’y a pas de valeur retournée, ni de modification
des « arguments » définis par xsl:with-param. Une des manières de contourner ces restrictions est
d’inclure l’appel à xsl:call-template dans un élément xsl:variable : voir page 281.

Exemples
Voir la section consacrée aux règles, page 119.

xsl:choose

Syntaxe
p xsl:choose q
260 APPENDIX B. RÉFÉRENCE XPATH/XSLT

p
xsl:when qvu
p
xsl:otherwise qvw
p /xsl:choose q

Description
Cet élément est associé xsl:when et xsl:otherwise pour créer l’équivalent des structures de test
que l’on trouve habituellement dans les langages de programmation (if-then-else ou switch). Son
contenu est une liste d’éléments xsl:when (au moins un), chacun étant associé à un test, et chacun ayant
un contenu sous forme de corps de règle. Le premier élément xsl:when pour lequel le test s’évalue à
true voit son corps de règle instancié. Les éléments qui suivent sont alors ignorés. Si aucun xsl:when
ne s’évalue à true, le contenu de l’élément xsl:otherwise, s’il existe, est instancié.

Exemples
Le programme suivant affiche tous les titres des chapitres du livre en les classant en trois catégories :
chapitres « courts », « moyens » et « longs ». Le classement s’effectue en fonction de la valeur de l’attribut
LONGUEUR de chaque chapitre.

Exemple 115 RefChoose.xsl : Exemple d’utilisation de xsl:choose


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="XBOOK">
<CHAPITRES>
<xsl:apply-templates select="CHAPITRE"/>
</CHAPITRES>
</xsl:template>

<xsI:template match="CHAPITRE">
<xsl:choose>
<xsl:when test="@LONGUEUR &lt; 20">
Le chapitre "<xsl:value-of select="TITRE"/>" est court
</xsl:when>

<xsl:when test="@LONGUEUR &lt; 30">


Le chapitre "<xsl:value-of select="TITRE"/>" est moyen
</xsl:when>

<xsl:when test="@LONGUEUR &gt;= 30">


Le chapitre "<xsl:value-of select="TITRE"/>" est long
</xsl:when>

<xsl:otherwise>
Le chapitre "<xsl:value-of select="TITRE"/>"
n’est ni court, ni moyen, ni long !
</xsl:otherwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet>

L’attribut test a pour valeur une expression XPath quelconque qui est convertie en booléen selon les
règles présentées dans le chapitre 2, parge 103. Noter que l’opérateur « x » ne peut être utilisé directement
dans le test et doit être remplacé par une référence à l’entité prédéfinie &lt;.
B.1. ÉLÉMENTS XSLT 261

Voir également page 134.

xsl:comment

Syntaxe
x xsl:comment y
corps de règle
x /xsl:comment y

Description
Cette instruction permet d’inclure un commentaire dans le document résultat. Bien entendu il est illusoire
de placer un commentaire sous la forme habituelle x !- ... - y dans le programme XSLT en espérant
le copier dans le document résultat, puisqu’il sera ignoré tout simplement ignoré par le processeur. Le con-
tenu de l’élément peut être un corps de règle avec des instructions XSLT, du texte, des éléments littéraux,
etc. Il faut éviter d’y introduire deux tirets --. L’instanciation du corps de règle sera introduit dans le
document résultat sous la forme :
x !-- instanciation du corps de règle -- y
L’introduction de commentaires peut être utile pour comprendre, en lisant le document résultat, quelles
sont les règles qui ont été instanciées et d’où proviennent les informations.

Exemples
Voici un document représentant (très synthétiquement) le présent livre.

Exemple 116 XBook.xml : Une description du livre

<?xml version="1.0" encoding="ISO-8859-1"?>

<XBOOK ISBN="1-67098-09">
<TITRE>Publication web avec XML/XSLT</TITRE>
<EDITEUR>Editions O’Reilly France</EDITEUR>
<AUTEURS>
<AUTEUR><NOM>Bernd Amann</NOM>
<AFFILIATION>Cnam</AFFILIATION>
</AUTEUR>
<AUTEUR><NOM>Philippe Rigaux</NOM>
<AFFILIATION>Université Paris-Sud</AFFILIATION>
</AUTEUR>
</AUTEURS>
<CHAPITRE LONGUEUR="8">
<TITRE>Avant-propos</TITRE>
</CHAPITRE>
<CHAPITRE LONGUEUR="43">
<TITRE>Introduction à XML/XSLT</TITRE>
</CHAPITRE>
<CHAPITRE LONGUEUR="34">
<TITRE>Documents XML : Structure et navigation</TITRE>
<MOT-CLE>DOM</MOT-CLE><MOT-CLE>XPath</MOT-CLE>
</CHAPITRE>
<CHAPITRE LONGUEUR="45">
<TITRE>Programmation XSLT</TITRE>
<MOT-CLE>XSLT</MOT-CLE>
</CHAPITRE>
</XBOOK>
262 APPENDIX B. RÉFÉRENCE XPATH/XSLT

Le programme suivant produit la liste de tous les mots-clés présents dans XBook.xml, avec un commen-
taire indiquant de quels chapitres proviennent les mots-clés.
Exemple 117 Comment.xsl : Exemple d’utilisation de xsl:comment
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="XBOOK">
<MOTS-CLES>
<xsl:apply-templates select="CHAPITRE/MOT-CLE"/>
</MOTS-CLES>
</xsl:template>

<xsl:template match="MOT-CLE">
<xsl:comment>
Ces mots-clés sont issus du chapitre
<xsl:value-of select="../TITRE"/>
</xsl:comment>

<xsl:value-of select="."/>
</xsl:template>

</xsl:stylesheet>

xsl:copy

Syntaxe
x xsl:copy
use-attribute-sets=QNames y
corps de règle
x /xsl:copy y

Description
Cette instruction copie le nœud courant dans le document résultat. Cette copie comprend le balisage et la
valeur, mais n’effectue pas de copie en profondeur. Les éléments sont donc copiés sans leur contenu.
L’attribut use-attribute-set permet d’introduire des attributs dans l’élément copié en faisant
référence au nom d’un groupe d’attributs : voir page 259.
On peut introduire un contenu dans un élément copié en plaçant un corps de règle dans xsl:copy.

Exemples
Voici un document XML :
Exemple 118 Copy.xml : Un document XML à copier
<?xml version="1.0" encoding="ISO-8859-1"?>

<A att1="2">
<!-- Test de xsl:copy -->
<B>Contenu B</B>
<C>Contenu C</C>
</A>
B.1. ÉLÉMENTS XSLT 263

Et voici un programme qui sélectionne dans ce document les principaux types de nœud (à l’exception
de Document et ProcessingInstruction) et les copie :
Exemple 119 Copy.xsl : Un programme d’analyse et de copie
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<xsl:apply-templates select="//node()|@*"/>
</xsl:template>

<xsl:template match="*">
Voici un élément : "<xsl:copy/>"
<xsl:apply-templates select="@*"/>
</xsl:template>

<xsl:template match="@*">
<attribut><xsl:copy/></attribut>
</xsl:template>

<xsl:template match="text()">
Voici du texte : "<xsl:copy/>"
</xsl:template>

<xsl:template match="comment()">
Voici un commentaire : "<xsl:copy/>"
</xsl:template>
</xsl:stylesheet>

Le résultat obtenu est :


Exemple 120 ResultCopy.xml : Résultat du programme précédent
<?xml version="1.0" encoding="ISO-8859-1"?>

Voici un élément : "<A/>"


<attribut att1="2"/>
Voici du texte : " "
Voici un commentaire : "<!-- Test de xsl:copy -->"
Voici du texte : " "
Voici un élément : "<B/>"
Voici du texte : "Contenu B"
Voici du texte : " "
Voici un élément : "<C/>"
Voici du texte : "Contenu C"
Voici du texte : " "

Ce résultat appelle quelques explications :

1. les attributs sont copiés dans l’élément courant : ici on a introduit un élément littéral x attribut y
dans la règle qui traite les attributs, ce qui implique
(a) que c’est à cet élément que viennent se rattacher les attributs ;
(b) que les éléments issus du document pprincipal se retrouvent sans attribut.
2. le document contient des nœuds de type Text constitués uniquement d’espaces : ces nœuds apparais-
sent ici ;
264 APPENDIX B. RÉFÉRENCE XPATH/XSLT

3. enfin les éléments apparaissent vides puisqu’ils n’ont pas de valeur.

Une utilisation de courante de xsl:copy consiste à recopier un document en excluant certains élé-
ments ou certains types de nœuds. Le programme suivant par exemple recopie le document Copy.xml en
supprimant les commentaires. Il illustre l’introduction d’un corps de règle dans le contenu de xsl:copy.

Exemple 121 Copy2.xsl : Copie avec exclusion des commentaires

<?xml version="1.0" encoding="ISO-8859-1"?>


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<xsl:apply-templates select="*|@*|text()"/>
</xsl:template>

<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="*|@*|text()"/>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

La première règle s’applique à la racine du document et déclenche un appel xsl:apply-templates


en sélectionnant tous les types de nœuds à l’exception des commentaires (et des instructions de traitement).
Pour tous les nœuds sélectionnés (y compris les attributs) la seconde règle s’applique : elle effectue une
copie du nœud courant, et s’appelle récursivement.
Il est important de remarquer que si les commentaires sont exclus, c’est parce qu’il n’existe pas de
règle par défaut pour ce type de nœud. En revanche, si on souhaite exclure les nœuds de type Text, il faut
indiquer explicitement une règle qui ne fait rien, comme dans le programme ci-dessous :

Exemple 122 Copy3.xsl : Copie avec exclusion des nœuds texte

<?xml version="1.0" encoding="ISO-8859-1"?>


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>

<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="*|@*|comment()"/>
</xsl:copy>
</xsl:template>

<xsl:template match="text()"/>

</xsl:stylesheet>
B.1. ÉLÉMENTS XSLT 265

xsl:copy-of

Syntaxe
x xsl:copy
select=Expression y
x /xsl:copy-of y

Description
L’élément xsl:copy-of déclenche une copie en profondeur de tous les nœuds sélectionnés par l’expression
de l’attribut select. La copie en profondeur implique que tous les descendants sont copiés également.
Ce recouvre notamment, pour les éléments, la copie de tous les éléments descendants, avec leurs attributs
(qui sont aussi des nœuds) et leur contenu textuel.

Exemple
Le programme suivant copie tout d’abord l’élément racine A, puis recopie en profondeur les fils de type B.
Tous les autres éléments sont ignorés.

Exemple 123 CopyOf.xsl : Copie en profondeur


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="A">
<xsl:copy/>
<xsl:copy-of select="B"/>
</xsl:template>

</xsl:stylesheet>

Appliqué au document Copy.xml, on obtient le résultat suivant :

Exemple 124 ResultCopyOf.xml : Résultat du programme CopyOf.xsl


<?xml version="1.0" encoding="ISO-8859-1"?>
<A/><B>Contenu B</B>

xsl:decimal-format

Syntaxe
x xsl:decimal-format
name=nom
decimal-separator=séparateurDécimale
grouping-separator=séparateurGroupe
infinity=infini
minus-sign=signeMoins
NaN=symboleNaN
percent=symbolePourCent
266 APPENDIX B. RÉFÉRENCE XPATH/XSLT

per-mille=symbolePourMille
zero-digit=complémentZéro
digit=complémentDigit
pattern-separator=séparateurPlusMoins y
x /xsl:decimal-format y

Description

blabla

xsl:document

Syntaxe

x xsl:document
href=URI
method= ("xml" | "html" | "text" | autre)
version=noVersion
encoding=codage
omit-xml-declaration=("yes" | "no")
standalone=("yes" | "no")
doctype-public=DTDPublique
doctype-system=DTDSystème
cdata-section-elements=listeEléments
standalone=("yes" | "no")
media-type=typeMedia y
x /xsl:document y

Description

XSLT 1.1

xsl:element

Syntaxe

x xsl:element
name={QName}
namespace={URI}
use-attribute-sets=QNames y
corps de règle
x /xsl:element y

Description

Cette instruction permet d’insérer un élément dans le document résultat. Son principal intérêt est de per-
mettre de déterminer dynamiquement (au moment de l’exécution du programme) le nom ou l’espace de
nom de l’élément créé, tous les autres cas pouvant se ramener à l’insertion d’un élément littéral.
L’attribut use-attribute-sets permet de faire référence à un groupe d’attribut nommé par xsl:attribute-
set : voir page 259.
B.1. ÉLÉMENTS XSLT 267

Exemples
Le programme suivant transforme l’attribut ISBN du document XBook.xml en élément, et copie en pro-
fondeur les éléments x TITRE y et x EDITEUR y .

Exemple 125 Element.xsl : Exemple d’utilisation de xsl:element


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/XBOOK">
<LIVRE>
<xsl:copy-of select="TITRE"/>

<xsl:element name="ISBN">
<xsl:value-of select="@ISBN"/>
</xsl:element>
<xsl:copy-of select="EDITEUR"/>
</LIVRE>
</xsl:template>
</xsl:stylesheet>

Évidemment on pourrait tout aussi bien inclure x ISBN y comme un élément littéral.

xsl:fallback

Syntaxe
x xsl:fallback y
corps de règle
x /xsl:fallback y

Description
Cette instruction s’exécute quand le père de l’élément n’est pas reconnu par le processeur XSLT. Il est donc
principalement destiné à permettre des extensions de XSLT tout en préservant dans une certaine mesure la
portabilité des programmes.

Exemples
Voici un élément de type xbook:refChapitre. Si cet élément est référencé dans un appel de règle, et
que le processeur XSLT est dans l’incapacité de le traiter, le message Instruction inconnue sera
inséré dans le résultat.
x xbook:refChapitre no=’1’ y
x fallback y Instruction inconnue
x /fallback y
x /xbook:refChapitre y

xsl:for-each

Syntaxe
x xsl:for-each
select=Expression y
268 APPENDIX B. RÉFÉRENCE XPATH/XSLT

( x xsl:sort y{z , corps de règle)


corps de règle
x /xsl:for-each y

Description

L’instruction xsl:for-each instancie son contenu pour chacun de nœuds désigné par l’expression de
l’attribut select. Le nœud est pris à chaque fois comme nœud courant, et le contexte pour l’ensemble
de la boucle est constitué de l’ensemble des nœuds sélectionnés par le select. L’instruction xsl:for-
each change donc temporairement le contexte et le nœud courant d’une règle.

Exemples

Voir la description et des cas d’utilisation de cette instruction dans le chapitre 3, page 136.

xsl:if

Syntaxe

x xsl:if
test=Expression y
corps de règle
x /xsl:if y

Description

Cette instruction instancie son contenu si l’expression de l’attribut test s’évalue à true. Il n’y a pas
d’équivalent en XSLT au else habituellement trouvé dans la syntaxe des langages programmation, mais
on peut utiliser l’instruction xsl:choose qui est beaucoup plus puissante : voir page B.1.

Exemples

Voir la description et des cas d’utilisation de cette instruction dans le chapitre 3, page 134.

xsl:import

Syntaxe

x xsl:import href=URI/ y

Description

Cet élément de premier niveau importe un autre programme XSLT avec tous ses éléments de premier
niveau et toutes ses règles. La précédence de tous les éléments importés est inférieure à ceux du document
principal.
Cet élément doit apparaître avant tous les autres éléments de premier niveau parmi les enfants de
l’élément racine xsl:stylesheet.
Nous renvoyons au chapitre 3, page 111 pour une description détaillée des règles d’importation de
documents.
B.1. ÉLÉMENTS XSLT 269

xsl:include

Syntaxe
x xsl:include href=URI/ y

Description
xsl:include insère dans le programme le contenu du document XSLT référencé par l’attribut href.
Tout se passe ensuite comme si les éléments importés avaient été présent dans le programme principal dès
l’origine. Contrairement à xsl:import, il n’existe donc pas d’ordre de précédence entre les éléments
inclus et les autres.

xsl:key

Syntaxe
x xsl:key
name=QName
match=pattern
use=expression/ y

Description
XSLT permet de définir (attribut match) des groupes de nœuds dans le document source, de référencer ces
groupes par un nom (attribut name), et enfin d’indiquer une expression dont le résultat identifie de manière
unique chaque nœud du groupe (attribut use). Tous ces attributs sont obligatoires.
Un fois un groupe (une « clé » dans la terminologie XSLT) défini, on peut extraire un nœud avec la
fonction key().

Exemples
Voic un document XML contenant quelques films avec leurs metteurs en scène.

Exemple 126 Films.xml : Quelques films


<?xml version="1.0" encoding="ISO-8859-1"?>

<FILMS>
<FILM ANNEE="1979">
<TITRE>Alien</TITRE><AUTEUR>Scott</AUTEUR>
</FILM>
<FILM ANNEE="1958">
<TITRE>Vertigo</TITRE><AUTEUR>Hitchcock</AUTEUR>
</FILM>
<FILM ANNEE="1960">
<TITRE>Psychose</TITRE><AUTEUR>Hitchcock</AUTEUR>
</FILM>
<FILM ANNEE="1980">
<TITRE>Kagemusha</TITRE><AUTEUR>Kurosawa</AUTEUR>
</FILM>
<FILM ANNEE="1997">
<TITRE>Volte-Face</TITRE><AUTEUR>Woo</AUTEUR>
</FILM>
<FILM ANNEE="1997">
270 APPENDIX B. RÉFÉRENCE XPATH/XSLT

<TITRE>Titanic</TITRE><AUTEUR>Cameron</AUTEUR>
</FILM>
<FILM ANNEE="1986">
<TITRE>Sacrifice</TITRE><AUTEUR>Tarkovski</AUTEUR>
</FILM>
</FILMS>

Le programme XSLT suivant définit une clé de nom FilmsDate qui définit un groupe contenant tous
les films dont la clé est l’attribut ANNEE de l’élément x FILM y .

Exemple 127 Key.xsl : Utilisation de xsl:key

<?xml version="1.0" encoding="ISO-8859-1"?>


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key name="FilmsDate" match="FILM" use="@ANNEE"/>

<xsl:template match="/">
<xsl:value-of
select=’key("FilmsDate", "1958")/TITRE’/>
</xsl:template>

</xsl:stylesheet>

On peut alors utiliser la fonction key() pour désigner un ou plusieurs des éléments du groupe en fonction
d’une valeur de la clé. Le programme ci-dessus désigne par exemple tous les films de 1958 (soit Vertigo).
On peut noter que key()] s’intégère à des expressions XPath complexes puisque son évaluation donne un
ensemble de nœuds à partir desquels on peut exprimer d’autres étapes XPath.

xsl:message

Syntaxe
x xsl:message
terminate=("yes" | "no") y
corps de règle
x /xsl:message y

Description
Cette instruction permet d’afficher un message sur la « console » du processeur XSLT. Elle peut principale-
ment être utilisée pour suivre le déroulement de l’exécution du programme. L’attribut terminate avec
la valeur yes permet de forcer l’interruption du programme.

xsl:namespace-alias

Syntaxe

x xsl:namespace-alias
stylesheet-prefix=préfixe | "#default"
result-prefix=préfixe | "#default" / y
B.1. ÉLÉMENTS XSLT 271

Description
Cet élément demande au processeur XSLT de modifier le préfixe de certains éléments littéraux quand ils
sont recopiés dans le document résultat. Le préfixe présent dans le programme est indiqué par stylesheet-
prefix, et son équivalent dans le document résultat est donné par result-prefix. Ces deux attributs
sont obligatoires.
Cette transformation est surtout importante pour transformer des documents XSLT eux-mêmes.

Exemples
Supposons que le but d’un programme XSLT soit de produire un autre programme XSLT. On trouverait
alors typiquement des règles comme celles du programme ci-dessous, qui sont évidemment invalides
puisque la présence d’un xsl:stylesheet n’est pas autorisée dans un corps de règle.

Exemple 128 NamespaceAlias1.xsl : Problème d’un élément littéral avec un préfixe xsl:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:stylesheet version="1.0">
<xsl:apply-templates />
</xsl:stylesheet>
</xsl:template>

</xsl:stylesheet>

La solution consiste à utiliser, dans le programme, un préfixe spécial, par exemple myxsl, pour les
éléments littéraux, et à convertir ce préfixe spécial en xsl au moment de l’inclusion de ces éléments
littéraux dans le document résultat. La conversion est indiquée avec xsl:NamspaceAlias, comme
dans l’exemple ci-dessous.

Exemple 129 NamespaceAlias2.xsl : Utilisation de xsl:NamespaceAlias


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:namespace-alias
stylesheet-prefix="myxsl"
result-prefix="xsl"/>

<xsl:template match="/">
<myxsl:stylesheet version="1.0">
<xsl:apply-templates/>
</myxsl:stylesheet>
</xsl:template>

</xsl:stylesheet>

xsl:number

Syntaxe
x xsl:number
272 APPENDIX B. RÉFÉRENCE XPATH/XSLT

level="single" | "multiple" | "any"


count=pattern
from=pattern
value=expression
format=chaîneFormat
lang=codeLangage
letter-value="alphabetic" | "traditional"
grouping-separator=séparateurGroupe
grouping-size=tailleGroupe / y

Description
Blabla

xsl:otherwise

Syntaxe
x xsl:otherwise y
corps de règle
x /xsl:otherwise y

Description
Cet élément est subordonné à l’élément xsl:choose : voir page 261.

xsl:output

Syntaxe
x xsl:output
method="xml" | "html" | "text" | QName
version=Ntoken
encoding=string
omit-xml-declaration=("yes" | "no")
standalone=("yes" | "no")
doctype-public=string
doctype-system=strin
cdata-section-elements=QNames
indent=("yes" | "no")
media-type=string / y

Description
Cet élément indique au processeur le type de document à produire. En fonction de ce type, des mises
en forme spéciales peuvent être appliquées. Les trois types de document préconisés par la norme sont
html, xml et text, la valeur par défaut étant xml. De plus d’autres types de document spécifiques à un
processeur peuvent être pris en compte, mais le programme ne sera alors pas portable.
Les attributs version et encoding correspondent à la version XML (à l’heure actuelle la 1.0) ou
HTML (à l’heure actuelle la 4.0), et à l’encodage du document résultat.
B.1. ÉLÉMENTS XSLT 273

L’attribut omit-xml-declaration (avec pour valeur par défaut no) peut être utilisé pour sup-
primer la déclaration XML (sa valeur doit alors être yes). L’attribut standalone est spécifique à un
document résultat de type XML : il indique si le document fait référence ou non à des entités externes.
Les attributs doctype-public et doctype-system peuvent être utilisés respectivement pour un
document XML avec DTD publique et un document XML avec une DTD de type SYSTEM.
On peut demander à ce que les fils de type Text de certains éléments dans le document XML résultat
fassent partie d’une section littérale (CDATA). Dans ce cas les types de ces éléments doivent être donnés,
séparés par des espaces, dans la valeur de l’attribut cdata-section-elements.
Le document résultat peut être indenté si l’attribut indent est à yes (ce qui n’est pas le cas par
défaut). Enfin l’attribut media-type donne le type MIME du document produit. Ce type peut être utile
quand le document est transmis par le protocole HTTP. Pour HTML il doit valoir text/html, pour WML
text/xml, etc. Sa valeur par défaut est text/xml.

Exemples

Voir page 197 la description de cet élément et son application à une transformation XHTML –> HTML.

xsl:param

Syntaxe

x xsl:param
name=QName
select=Expression y
corps de règle
x /xsl:param y

Description

Cet élément peut être utilisé de deux manières :

1. dans une règle, pour indiquer un paramètre local reconnu et pris en compte par la règle ;

2. comme élément de premier niveau, pour désigner des paramètres extérieurs passés au programme.

L’attribut select est optionnel. S’il est présent, il donne la valeur par défaut du paramètre. Si
select est omis, le corps de l’élément (également optionnel) xsl:param définit la valeur par défaut du
paramètre.

Exemples

Voir la section consacrée au passage de paramètres, page 132.

xsl:preserve-space

Syntaxe

x xsl:preserve-space
elements=liste-éléments/ y
274 APPENDIX B. RÉFÉRENCE XPATH/XSLT

Description

Cet élément, ainsi que son complément xsl:strip-space, permet de contrôler la prise en compte
des nœuds de type Text constitués uniquement de blancs. Il est associé à une liste d’éléments donnée dans
l’attribut elements. Pour tous les élément indiqués, le nœuds de type domtypeText doivent être préservés
même s’ils ne contiennent que des espaces.
Par défaut le processeur XSLT doit conserver les nœuds de textes vides, ce qui peut introduire des effets
désagréables, notamment quand on utilise la fonction position(). Tout se passe donc comme si l’option
suivante était prise par défaut :
x xsl:preserve-space elements="*"/ y

Exemples

L’exemple suivant est un document avec l’indentation habituelle pour clarifier la hiérarchie des éléments.
x A y et x B y ont tous deux deux fils de type Text vides, encadrant un élément.
Exemple 130 Space.xml : Un document XML avec indentation

<?xml version="1.0" encoding="ISO-8859-1"?>

<A>
<B>
<C>Contenu</C>
</B>
</A>

Le programme suivant commence par définir une règle inverse à l’option par défaut : tous les nœuds de
type Text constitués uniquement d’espaces doivent être supprimés. On procède ensuite par exception en
indiquant que ce type de nœud doit être préservé uniquement pour le éléments de type B.

Exemple 131 PreserveSpace.xsl : Exemple de xsl:preserve-space et xsl:strip-space

<?xml version="1.0" encoding="ISO-8859-1"?>


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="B"/>

<xsl:template match="/A">
Fils de A : <xsl:value-of select="count(node())"/>
<xsl:apply-templates select="B"/>
</xsl:template>

<xsl:template match="B">
Fils de B : <xsl:value-of select="count(node())"/>
</xsl:template>

</xsl:stylesheet>

On appelle ensuite deux règles, l’une pour les éléments de type A, l’autre pour les éléments de type B,
et dans chaque règle on affiche le nombre de fils du nœud courant. On obtient 1 pour x A y et 3 pour x B y .
B.1. ÉLÉMENTS XSLT 275

xsl:processing-instruction

Syntaxe
x xsl:processing-intruction
name=QName y
corps de règle
x /xsl:processing-instruction y

Description
Cette instruction permet d’insérer un nœud de type ProcessingInstruction dans le document résultat.
L’attribut name est obligatoire et donne le nom ou « cible » de l’instruction de traitement. Le contenu de
l’élément xsl:processing-instruction doit produire du texte formant le contenu de l’instruction
de traitement dans le document résultat

xsl:sort

Syntaxe
x xsl:sort
select=expression
lang=codeLangue
order=("ascending" | "descending")
case=("lower-first" | "upper-first")
data-type= ("text" | "number" ) / y

Description
Cet élément est utilisé pour trier les nœuds séléctionnés soit par un appel de règles xsl:apply-templates,
soit par une boucle xsl:for-each. L’élément xsl:sort doit toujours apparaître immédiatement
après la balise ouvrante de xsl:for-each ou xsl:apply-templates, le mélange avec des élé-
ments xsl:with-param étant possible dans le second cas.
La clé de tri est indiquée par l’expression de l’attribut select (tous les attributs sont optionnels). Cette
expression est évaluée en prenant pour nœud courant, tour à tour, chaque nœud de l’ensemble sélectionné
par xsl:for-each ou xsl:apply-templates. Le tri de l’ensemble s’effectue alors d’apprès les
valeurs obtenues.
Par défaut le tri se fait d’après l’ordre lexicographique sur les chaînes de caractères, ce qui signifie que
« 4 » est plus grand que « 30 » (les caractères sont comparés de gauche à droite). En indiquant la valeur
number pour l’attribut data-type, on obtient un classement numérique.
L’ordre de tri est croissant par défaut et peut être modifié par l’attribut order. L’attribut lang est
supposé indiqué l’ordre des caractères spéciaux (est-ce que « é » est inférieur ou supérieur à « è » ?) qui
dépend de la langue. Enfin case indique le classement des mots en majuscule par rapport aux mêmes
mots en minuscules.
On peut indiquer plusieurs xsl:sort successifs : le processeur effectue un premier tri avec la pre-
mière clé, puis un second tri sur les groupes qui n’ont pas été départagés par le premier tri, et ainsi de
suite.

Exemples
Le tri est présenté page 140. Voici un exemple complémentaire montrant comment trier les chapitres du
document XBook.xml (page 261) d’après leur nombre de pages.

Exemple 132 RefSort.xsl : Exemple de xsl:sort


276 APPENDIX B. RÉFÉRENCE XPATH/XSLT

<?xml version="1.0" encoding="ISO-8859-1"?>


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:template match="/">
<CHAPITRES-TRIES>
<xsl:apply-templates select="//CHAPITRE">
<xsl:sort select="@LONGUEUR" data-type="number"/>
</xsl:apply-templates>
</CHAPITRES-TRIES>
</xsl:template>

<xsl:template match="CHAPITRE">
<CHAPITRE>
<TITRE><xsl:value-of select="TITRE"/></TITRE>
<LONGUEUR><xsl:value-of select="@LONGUEUR"/></LONGUEUR>
</CHAPITRE>
</xsl:template>
</xsl:stylesheet>

Remarquez l’attribut data-type avec la valeur number. Par défaut, le classement lexicographique
dirait que l’avant-propos (8 pages) est plus long que tous les autres chapitres.
Toute valeur associée à un nœud par une expression XPath peut être utilisée comme critère de tri.
Reprenons le document Films.xml, page 269, et supposons que le fichier Artiste.xml contienne les infor-
martions sur les metteurs en scènes.

Exemple 133 Artistes.xml : Les metteurs en scène

<?xml version="1.0" encoding="ISO-8859-1"?>

<ARTISTES>
<ARTISTE><NOM>Scott</NOM>
<PRENOM>Ridley</PRENOM>
<ANNEE>1943</ANNEE>
</ARTISTE>
<ARTISTE><NOM>Hitchcock</NOM>
<PRENOM>Alfred</PRENOM>
<ANNEE>1899</ANNEE>
</ARTISTE>
<ARTISTE><NOM>Kurosawa</NOM>
<PRENOM>Akira</PRENOM>
<ANNEE>1910</ANNEE>
</ARTISTE>
<ARTISTE><NOM>Woo</NOM>
<PRENOM>John</PRENOM>
<ANNEE>1946</ANNEE>
</ARTISTE>
<ARTISTE><NOM>Cameron</NOM>
<PRENOM>James</PRENOM>
<ANNEE>1954</ANNEE>
</ARTISTE>
<ARTISTE><NOM>Tarkovski</NOM>
<PRENOM>Andrei</PRENOM>
<ANNEE>1932</ANNEE>
</ARTISTE>
</ARTISTES>
B.1. ÉLÉMENTS XSLT 277

Voici un programme qui trie les films en fonction de l’année de naissance de leur metteur en scène.

Exemple 134 RefSort2.xsl : Films triés sur l’année de naissance du réalisateur


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="ISO-8859-1"/>

<xsl:variable name="artistes"
select="document(’Artistes.xml’)/ARTISTES"/>

<xsl:template match="FILMS">
<FILMS-TRIES>
<xsl:apply-templates select="FILM">
<xsl:sort
select="$artistes/ARTISTE[NOM = current()/AUTEUR]/ANNEE"
data-type="number"/>
</xsl:apply-templates>
</FILMS-TRIES>
</xsl:template>

<xsl:template match="FILM">
<FILM>
<TITRE><xsl:value-of select="TITRE"/></TITRE>
<AUTEUR><xsl:value-of select="AUTEUR"/></AUTEUR>
<NE-EN>
<xsl:value-of
select="$artistes/ARTISTE[NOM = current()/AUTEUR]/ANNEE"/>
</NE-EN>
</FILM>
</xsl:template>
</xsl:stylesheet>

La variable $artistes est initialisée avec le contenu du document Artistes.xml (voir la description
de la fonction document() page 283). À partir de là on peut l’utiliser comme s’il s’agissait de l’élément
racine de ce document. L’expression :

$artistes/ARTISTE[NOM = current()/AUTEUR]/ANNEE

sélectionne l’élément x ARTISTE y dont l’élément fils x NOM y a un contenu identique à celui du nœud
courant. Attention : il s’agit de l’un des rares cas où le nœud contexte de XPath est différent du nœud
courant de XSLT.

1. le nœud courant est un des élément de type FILM du document Films.xml ;


2. le nœud contexte dépend des étapes de l’expression XPath : dans l’expression ci-dessus, si on rem-
plaçait current par « . », on désignerait un élément x ARTISTE y du document Artistes.xml, et
pas un film.

La fonction current() désigne toujours l’élément courant (voir page 283).

xsl:strip-space

Syntaxe
x xsl:strip-space
278 APPENDIX B. RÉFÉRENCE XPATH/XSLT

elements=QNames/ y

Description
Cet élément donne la liste des éléments du documents source dont les fils de type Text constitués unique-
ment d’espaces doivent être supprimés. L’attribut elements est obligatoire : il indique, séparés par des
blancs, la liste des éléments concernés par xsl:strip-space. On peut utiliser le caractère « * » pour
désigner tous les éléments.

Exemples
Voir page 82, ainsi que la description de xsl:preserve-space, page 274.

xsl:stylesheet

Syntaxe
x xsl:stylesheet
id=idElément
extension-elements-prefixes=tokens
exclude-result-prefixes=tokens
version=number y
éléments de premier niveau
x /xsl:stylesheet y

Description
Cet élément est toujours l’élément racine d’un programme XSLT (xsl:transform est un synonyme).
Il doit toujours être accompagné d’un numéro de version (actuellement seule la 1.0 est une recommanda-
tion du W3C) afin de permettre au processeur de s’adapter aux éventuelles différences entre les versions
successives de XSLT. Tous les autres attributs sont optionnels.
L’attribut id donne un identifiant au programme. Cet attribut n’est utile que quand le programme est
inclus directement dans un document XML, et permet alors d’identifier le nœud racine des instructions
XSLT.
L’attribut extension-elements-prefixes donne la liste des préfixes des éléments qui sont
des extensions de XSLT. On peut exclure les éléments de certains espaces de nom en les indiquant dans
l’attribut exclude-result-prefixes.
Les fils de xsl:stylesheet sont tous les éléments de premier niveau de XSLT (voir tableau 3.1,
page 112, les éléments de type xsl:import devant apparaître en premier.

Exemples
Voir notamment la section consacrée à la structure d’un document XSLT, page 111.

xsl:template

Syntaxe
x xsl:template
name=QName
match=Pattern
mode=QName
priority=number y
B.1. ÉLÉMENTS XSLT 279

( x xsl:param y{z , corps de règle)


x /xsl:template y

Description
Cet élément définit une règle XSLT. Une règle peut être appelée par son nom (attribut name) avec une
instruction xsl:call-template. On peut aussi l’associer à un pattern avec l’attribut match, et la
règle est déclenchée pour tous les nœuds auxquels le pattern s’applique. L’un des deux attributs doit être
défini, mais pas les deux à la fois.
Deux attributs complémentaires conditionnent le choix d’une règle. L’attribut priority détermine
le degré de priorité : il est pris en compte quand plusieurs règles sont possibles pour un xsl:apply-
templates. L’attribut mode permet de définir plusieurs catégories de règles à appliquer dans des con-
textes différents.

Exemple
Voir la section du chapitre 3 consacrée aux règles, page 119.

xsl:text

Syntaxe
x xsl:text
disable-output-escaping=("yes" | "no") y
#PCDATA
x /xsl:text y

Description
Cette instruction permet d’insérer un nœud de type Text dans le document résultat. Le contenu de l’élément
ne doit pas contenir de balisage : les caractères spéciaux doivent donc être référencés via une entité
prédéfinie comme &lt; pour x ou &amp; pour &. Par défaut tous ces caractères spéciaux seront à
leur tour produits sous forme de référence à un entité dans le document résultat, mécanisme désigné par le
terme escaping en anglais.
Pour insérer directement le caractère, et pas la référence à l’entité, on peut mettre à no l’attribut
disable-output-escaping. Attention : cela affecte le document résultat, et pas le programme
XSLT qui doit, lui, toujours utiliser les références aux entités.
Les blancs introduits dans le contenu d’un élément xsl:text sont toujours préservés dans le docu-
ment résultat.

Exemples
Le programme XSLT ci-dessous produit une simple phrase contenant quelques caractères réservés. L’utilisation
des entités est requise.

Exemple 135 Text.xsl : Exemple de xsl:text


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

<xsl:text disable-output-escaping="yes">
Si 0 &lt; 1, alors 1 &gt; 0,
&amp; vice et versa
280 APPENDIX B. RÉFÉRENCE XPATH/XSLT

</xsl:text>
</xsl:template>

</xsl:stylesheet>

Le résultat de ce programme est le suivant. Il contient des caractères réservés qui le rendent impropre
à une inclusion dans un document XML bien formé.
Si 0 x 1, alors 1 y 0,
& vice et versa
Si disable-output-escaping n’était pas défini (ou défini à no, ce qui revient au même), on
obtiendrait dans le résultat une version avec entités identique à celle du programme XSLT.

xsl:transform

Syntaxe
Voir xsl:stylesheet

Description
Cet élément est synonyme de xsl:stylesheet : voir page 278.

xsl:value-of

Syntaxe
x xsl:value-of
select=Expression
disable-output-escaping=("yes" | "no") / y

Description
Cet élément évalue une expression sur le document source (ou sur un document référencé par la fonction
document()), puis convertit le résultat en chaîne de caractères selon les règles de conversion présentées
dans le chapitre 2, et enfin insère la chaîne dans le document résultat.
L’attribut disable-output-escaping a la même signification que dans le cas de l’élément xsl:text
décrit précédemment.

Exemples
Voir la section consacrée à cet élément, page ??.

xsl:variable

Syntaxe
x xsl:variable
name=QName
select=Expression / y
corps de règle
x /xsl:variable y
B.1. ÉLÉMENTS XSLT 281

Description
Une variable dans XSLT est un nom référençant une information qui peut être de nature très variée : un
nœud, un ensemble de nœuds, une valeur numérique ou alphanumérique, ou un result tree fragment, type
spécifique à XSLT 1.0 qui va probablement disparaître avec XSLT 1.1.
La valeur d’une variable est définie soit par l’évaluation de l’expression associée à l’attribut select
(auquel cas le contenu doit être vide), soit par le contenu de l’élément xsl:variable s’il n’y a pas de
select.
La portée d’une variable dépend de la position de l’élément. Si c’est un élément de premier niveau
(fils de xsl:stylesheet) la variable est définie dans tout le programme XSLT. Si, en revanche, la
variable est définie dans un élément xsl:template, elle est visible dans tous ses frères droits et leurs
descendants.
On ne peut pas définir une variable avec le même nom qu’une variable visible. (autrement dit on ne
peut pas trouver deux xsl:variable avec la même valeur pour l’attribut name si les éléments ont, au
moins en partie, le même espace de visibilité). Il s’ensuite qu’une variable est plutôt une constante, au sens
habituellement donné à ce mot en programmation. Cette particularité fait partie des propriétés qui font de
XSLT un langage « déclaratif », et laisse un certain degré de liberté au processeur XSLT pour évaluer un
programme.
Cette interdiction ne s’applique pas aux définitions de variables présentes dans des documents im-
portés : dans ce cas l’ordre de précédence joue et la définition de variable présente dans le document
principal ou dans le document importé ayant la plus grande précédence est prise en compte.

Exemples
Voir la section consacrée aux variables, page 138.

xsl:when

Syntaxe
x xsl:value-of
test=Expression / y
corps de règle
x /xsl:variable y

Description
Cet élément est subordonné à l’élément xsl:choose : voir page 261.

xsl:with-param

Syntaxe
x xsl:value-of
name=QName
select=Expression / y
corps de règle
x /xsl:with-param y

Description
Cet élément est utilisé pour passer des paramètres à une règle. Il suit un xsl:call-template, un
xsl:apply-templates ou un xsl:apply-imports.
282 APPENDIX B. RÉFÉRENCE XPATH/XSLT

La valeur du paramètre est déterminée comme pour les variables, en évaluant l’attribut select s’il est
présent, ou en prenant le contenu de l’élément sinon. Comme beaucoup d’autres aspects de la programma-
tion XSLTY, le passage de paramètres est très faiblement typé : on peut passer à une règle des paramètres
qu’elle n’attend pas, ou au contraire ne pas lui passer de paramètres. Dans le premier cas le paramètre est
tout simplement ignoré. Dns le second cas la règle prend en compte la valeur par défaut du paramètre, si
cette valeur existe : voir page B.1.

Exemples
Voir la section consacrée au passage de paramètres, page 132.

B.2 Fonctions XPath/XSLT


Les fonctions qui suivent sont utilisables dans toute expression XPath apparaissant dans un programme
XSLT. La plupart sont des fonctions définies dans la recommandation XPath, mais certaines (format-
number(), document(), key() par exemple) sont spécifiques à XSLT. Nous ne les distinguons pas dans ce
qui suit.
Une fonction prend zéro, un ou plusieurs arguments, parfois optionnels. Nous utilisons les conventions
habituelles des DTD : arg z indique un argument qui peut être répété 0 ou plusieurs fois, arg? indique un
argument optionnel, etc.
En général le type de ces arguments est l’un des quatre types de base XPath (number, string,
boolean et node-set), ou l’union de ces quatres types que nous dénotons objet comme dans la
recommandation XPath.
Bien entendu un argument peut lui-même être le résultat d’une autre fonction, ou bien être une ex-
pression XPath dont l’évaluation donnera la valeur à passer à la fonction. Si le type de cette valeur ne
correspond pas au type attendu, par exemple number, le processeur tentera d’effectuer une conversion au
moment de l’appel de la fonction.

boolean

Boolean boolean (object arg)


La fonction boolean() convertit son argument arg en booléen. Les règles de conversion ont été présentées
dans le chapitre 2, page 103. Rappelons-les briévement :
1. un numérique à zéro est converti à false, toutes les autres valeurs sont true ;
2. une chaîne de longueur nulle est false, toutes les autres sont true ;
3. un node-set vide est false, sinon la conversion renvoie true.

ceiling

number ceiling (number valeur)


Cette fonction renvoie le plus petit entier immédiatement supérieur à valeur. Par exemple ceil-
ing(1.5) est 2.

concat

string concat (string chaîne1, string chaîne2,


string chaines z )
Cette fonction concatène les chaînes de caractères (au moins deux) qui lui sont passées en argument.
B.2. FONCTIONS XPATH/XSLT 283

contains

Boolean contains (string chaîne, string sous-chaîne)

Cette fonction teste si chaîne contient sous-chaîne, et renvoie true ou false selon le cas.

count

Boolean count (node-set nœuds)

Cette fonction compte le nombre de nœuds dans le node-set passé en argument.

current

node-set current ( )

Cette fonction renvoie le nœud courant ou, pour être plus précis, node-set contenant un seul nœud, le
nœud courant.
Qu’est-ce que le nœud courant (qu’il faut bien distinguer du nœud contexte pour une expression XPath).
Un programme XSLT consiste à considérer certains nœuds du document source, à rechercher quelle est la
règle associée à chaque nœud et à instancier cette règle. Chaque règle s’instancie donc en association avec
le nœud qui a déclenché sont instanciation : c’est le nœud courant.
Au sein d’une règle on peut trouver des instructions qui vont temporairement changer le nœud courant :
xsl:apply-templates va sélectionner, avec une expression XPath un ensemble de nœud et les pren-
dre chacun à son tour comme nœuds courants pour instancier un règle, et de même pour xsl:for-each.
Ces deux éléments modifient localement le nœud courant, qui revient à sa valeur initiale quand l’évaluation
de xsl:apply-templates ou xsl:for-each est terminée.
Le nœud courant peut être différent du nœud contexte, désigné dans XPath par l’expression self:node()
ou « . ». Par exemple, dans l’expression suivante :
FILM/TITRE[.=’Alien’]
le nœud courant est celui à partir duquel on va chercher un fils de type FILM, puis un petit-fils de type
TITRE, etc. Dans cette expression en revanche, le nœud contexte désigné par « . » est un élément de type
TITRE. Les prédicats sont les seuls cas où le nœud courant et le nœud contexte diffèrent, et les seuls cas
où l’utilisation de la fonction current() est justifiée. Voici par exemple un appel de règle qui sélectionne
tous les nœuds frères du nœud courant qui ont le même contenu.
x xsl:apply-templates match="../*[.=current()]" y
La réféence de l’élément xsl:sort présente un exemple où l’utilisation de current est impérative.

document

node-set document (node-set uri, node-seturi)

TO DO

element-available

Boolean element-available (string nomElément)

Cette fonction teste si un élément XSLT est connu du processeur. Elle est principalement utile pour tester
si certaines extensions largement répandues (comme, par exemple, xsl:document) sont disponibles.
284 APPENDIX B. RÉFÉRENCE XPATH/XSLT

false

Boolean false ()

Cette fonction renvoie false, et peut être utilisée pour palier l’absence de constantes booléennes dans
XSLT. En pratique les conversions effectuées automatiquement sont le plus souvent suffisantes, et évitent
d’avoir à écrire « expression!=false() » alors que « expression » a une signification équiva-
lente.

floor

number floor (number valeur)

Cette fonction renvoie le plus grand entier immédiatement inférieur à valeur. Par exemple floor(1.5)
est 1. Appliquée à une valeur entiére, la fonction renvoie cette valeur.

format-number

string format-number ()

TO DO

function-available

Boolean function-available (string nomFonction)

Cette fonction teste si un élément XSLT est connu du processeur. Elle peut être utile pour vérifier l’existence
de fonctions fournies seulement par certains processeurs, ou apparues dans de nouvelles versions de XSLT.

generate-id

string generate-id (node-set nœud)

TO DO

id

node-set id (object arg)

TO DO

key

node-set key (string nomClé, object expression)

La fonction key() fonctionne en association avec l’élément xsl:key décrit page 270. Rappelons que
cet élément définit un groupe de nœud, lui attribue un nom et définit l’expression (la clé) qui permet de
différencier les nœuds au sein de ce groupe.
La fonction prend deux arguments : le nom de la clé, et la valeur de la clé. Elle renvoie le nœud identifié
par cette valeur.
B.2. FONCTIONS XPATH/XSLT 285

Exemples
Voir page 270.

lang

Boolean lang (string codeLangue)

Cette fonction vérifie que le langage du nœud contexte est codeLangue, et renvoie true ou false
selon le cas.
Le langage d’un élément est défini par l’attribut réservé xml:lang, soit dans l’élément lui-même, soit
dans le plus proche ancêtre ayant cet attribut.

last

number last ()

La fonction last() renvoie la taille du contexte XPath. Dans XSLT il s’agit du nombre de nœud sélection-
nés par l’expression de l’attribut select dans xsl:apply-templates ou xsl:for-each. Si la
fonction est utilisée dans une prédicat XPath, elle correspond au nombre de nœuds sélectionnés par l’étape
précédente.
Il faut être attentif aux nœuds textes vides qui peuvent être comptés ou non selon que l’instruction
xsl:strip-space a été utilisée ou pas.

local-name

string local-name (node-set nœud?)

La fonction renvoie le nom local (sans le préfixe correspondant à l’espace de nom) du nœud passé en
argument. Si l’argument est un ensemble, le premier nœud est pris en compte. Si l’argument est omis la
fonction s’applique au nœud contexte.

name

string name (node-set nœud?)

La fonction renvoie le nom complet, comprenant éventuellment le préfixe correspondant à l’espace de


nom, du nœud passé en argument. Si l’argument est un ensemble, le premier nœud est pris en compte. Si
l’argument est omis la fonction s’applique au nœud contexte.

namespace-uri

string namespace-uri (node-set nœud?)

La fonction renvoie l’URI associée au préfixe du nœud passé en argument.

normalize-space

string normalize-space (string chaîne?)

TO DO
286 APPENDIX B. RÉFÉRENCE XPATH/XSLT

not

Boolean not (Boolean valeur?)

Cette fonction calcule la négation de son argument.

number

number number (object valeur?)

Cette fonction convertit l’argument valeur en numérique.

position

number position ()

Cette fonction renvoie la position de l’objet courant dans l’ensemble de nœud que constitue le contexte
XPath.

round

number round (number valeur)

Cette fonction arrondit son argument à l’entier le plus proche.

starts-with

Boolean starts-with (string chaîne, string sous-chaîne)

Cette fonction teste si chaîne débute avec sous-chaîne.

string

string string (object valeur?)

TO DO

string-length

number string-length (string chaîne?)

TO DO

substring

string substring (string chaîne, number début, number longueur?)

TO DO
B.2. FONCTIONS XPATH/XSLT 287

substring-after

string substring-after (string chaîne, string sous-chaîne)

TO DO

substring-before

string substring-before (string chaîne, string sous-chaîne)

TO DO

sum

number sum (node-set nœuds)

Cette fonction effectue la somme des valeurs des nœuds dans le node-set passé en argument.

system-property

number system-property (string nomParamètre)

TO DO

translate

string translate (string chaîne, string arg1, string arg2)

TO DO

true

Boolean true ()

Cette fonction renvoie true, et peut être utilisée pour palier l’absence de constantes booléennes dans
XSLT. En pratique les conversions effectuées automatiquement sont le plus souvent suffisantes, et évitent
d’avoir à écrire « expression=true() » alors que « expression » a une signification équivalente.

unparsed-entity-uri

string unparsed-entity-uri (string nom)

TO DO

You might also like