Transformations avec XSL, XHTML, FO et SVG

Utiliser le langage XSL pour effectuer des transformations sur un document XML.

Utiliser XML sur la couche Presentation d'une application web

XSL : transformer du XML en XHTML

Temps1h

Dans cette partie nous allons transformer des éléments XML en balises HTML à l'aide de XSL.

Les feuilles de style XSL permettent d'enrichir et d'extraire des données d'un document XML.

Pour cela XSL fournit des balises spécifiques.

Ajouter une feuille de style (XSL) à un document XML

Pour déclarer quelle feuille de style le moteur de transfromation XSL doit appliquer au document, insérer l'instruction xml-stylesheet dans le document XML.

Fichier exemple.xml

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

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

<ClubTarot>

<Joueur niveau="bon">
 <Nom>Albert</Nom>
 <Tel type="domicile">04-56743678</Tel>
 <Tel type="travail">04-45367624</Tel>
 <Couleur>Red</Couleur>
</Joueur>

</ClubTarot>

L'instruction ?cocoon-process? indique à Cocoon quel type de traitement appliquer au document XML.

Enregistrer ce fichier XML dans le répertoire %FORMATIONX% du serveur.

Modèles de documents XSL

Nous allons maintenant créer une feuille de style XSL pour ce document.

Fichier page.xsl

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

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

 <xsl:output method="html"/>

 <xsl:template match="/">

 <xsl:processing-instruction
name="cocoon-format">type="text/html"</xsl:processing-instruction>

<html>
 <head>
<title>Bienvenue au club !</title>
 </head>
 <body>
 Bienvenue au club !
 </body>
</html>
</xsl:template>

</xsl:stylesheet>

Le HTML est inclus dans un élément xml-template et est considéré comme du xml. Il faut donc veiller à produire du HTML "bien-formé".

Copier le fichier sur le serveur.

Maintenant que notre document et notre feuille de style sont sur le serveur nous allons les modifier et leur ajouter progressivement d'autres fonctions.

Testez l'accès au document xml sur le serveur.

Navigation dans le document XML / Extraire des données avec Xpath

Extraire les données d'un élément XML

Il faut maintenant extraire des données du document XML.

Les balises prédéfinies de XSL permettent d'éxécuter ce type d'opération.

Pour commencer nous allons extraire le nom du joueur de tarot et l'afficher.

Pour extraire la valeur d'un élément on utilise la balise xsl:value-of.

Fichier page.xsl


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

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

 <xsl:output method="html"/>

<xsl:template match="/">

 <xsl:processing-instruction name="cocoon-format">type="text/html"</xsl:processing-instruction>

 <html>
 <head>
 <title>Bienvenue au club <xsl:value-of select="/ClubTarot/Joueur/Nom">!</title>
 </head>

 <body>
 Bienvenue au club <xsl:value-of select="/ClubTarot/Joueur/Nom"/> !
 </body>
 </html>
</xsl:template>

</xsl:stylesheet>

Mettre à jour le fichier page.xsl et constater l'utilisation de la donnée XML.

Utiliser une donnée XML dans un attribut : évaluation d'une expression Xpath

Dans l'exemple précédent nous avons extrait une donnée du document XML en utilisant une expression Xpath comme valeur de l'attribut select.

L'expression Xpath indique quels éléments du document sont visés par l'instruction.

Un / au début de l'expression Xpath indique que l'on commence la recherche à la racine du document.

L'expression /ClubTarot/Joueur/Nom indique au processeur XSL d'aller, à partir de la racine du document, à l'élément ClubTarot, puis d'aller à l'élément Joueur parmis ses fils puis d'aller à l'élément Nom.

Utilisation des {} pour assigner la valeur de l'element

Comme cela a été vu, un attribut ne peut pas avoir comme valeur une chaîne contenant les caractères < ,> et &.

Il est possible d'affecter la valeur d'un élément XML à un attribut en utilisant la notation entre {}.

Exemple :


<body bgcolor="{/ClubTarot/Joueur/Couleur}">
…
</body>

Cette instruction indique d'utiliser la valeur de lélément Couleur du Joueur pour l'attribut bgcolor de la balise body.

Insérer cette instruction dans la feuille de style page.xsl et mettre à jour le serveur.

Quand utiliser {} et ne pas l'utiliser ?

Sélection d'un prédicat : Elément XML + valeur(s) d'attribut(s)

Pour accéder à un attribut dans une expression Xpath, il faut précéder son nom de @.

Il est possible d'afficher un élément en fonction d'un prédicat en utilisant la notation entre [ ].

Exemple :


<p>Votre numéro de téléphone personnel est <xsl:value-of
select="/ClubTarot/Joueur/Tel[@type='domicile']"/></p>

Si l'un des éléments du prédicat est une chaîne il faut l'encadrer entre des guillemets simples ( ' ' ) car l'expression Xpath est déjà entre guillemets.

Insérer l'exemple dans la feuille de style.

Itérations / Affichage d'une collection d'éléments XML : for-each

Si un élément père comporte plusieurs éléments fils du même type, il faut pouvoir traiter accéder à chacun de ces éléments individuellement.

L'instruction XSL xsl:for-each permet de parcourir tous les éléments visés par un prédicat et de les traiter.

Exemple :


<xsl:for-each select="predicat">

 <!-- A l'interieur de
la boucle for-each l'element courant est atteint par l'expression Xpath
"." -->

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

</xsl:for-each>

Sur la base de cet exemple et des précédents, afficher la liste des numéros de téléphone du Joueur.

Accéder à plusieurs éléments XML simultanèment (../)

Pour accéder à un élément situé au-dessus de l'élément courant, il faut utiliser l'expression Xpath "..", autant de fois que nécessaire.

Exemple :


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

Cet exemple affiche la valeur du grand père de lélément courant.

Accéder à tous les éléments XML (select="@*", select="*")

Pour accéder à tous les éléments on utilisera l'expression "*".

L'expression "@*" permet de sélectionner tous les attributs d'un élément.

Attribut identifiant

XSL offre une facilité pour créer un identifiant unique pour chaque élément.

Création d'un identifiant avec generate-id()

On utilise la fonction generate-id(predicat) pour créer un identifiant unique pour un élément.

Exemple :


<a name="{generate-id(.)}"><xsl-value-of
select="."></a>

Hyperliens

La fonction generate-id peut être réutilisée plusieus fois dans un document et donnera toujours le même résultat pour un élément donné.

Exemple :


<a href="#{generate-id(.)}"><xsl-value-of
select="."></a>

Traitement conditionnel

Dans cette partie nous allons étudier les instructions XSL pour le traitement conditionnel.

xsl:if

Pour traiter un document XML il est possible de réaliser des tests simples avec xsl:if.

Exemple :


<xsl:if test="/ClubTarot/Joueur/@niveau='bon'">

<p>Une partie spéciale pour les bons a lieu aujourd'hui
!</p>

</xsl:if>

Insérer cet exemple dans le fichier exemple.xml et observer le résultat.

Expressions Test=

L'attribut test permet d'effectuer des tests sur des éléments XML.

Il peut avoir comme valeur une expression Xpath ou une fonction.

Les fonctions sont présentées par la suite. Elles permettent de calculer la position d'un élément, le nombre d'éléments,…

Les expressions test= sont de la forme :


<xsl:if test="fonction(element) &gt; valeur">

<!-- si le test est vrai executer le code -->

</xsl:if>

Ou de la forme :


<xsl:if test="predicat='valeur'">

<!-- si le test est vrai executer le code -->

</xsl:if>

Opérateurs booléens

Les opérateurs booléens autorisés dans les expressions évaluées par l'attribut test sont :

= : égalité

!= : différent

&lt; : inférieur

&gt; : supérieur

&lt;= : inférieur ou égal

&gt;= : supérieur ou égal

not : négationne(!) l'expression

xsl:when/xsl:choose

Une autre structure conditionnelle disponible est la strucure xsl:choose.

Elle permet d'éxecuter un traitement en fonction du résultat d'un test.

Par rapport à xsl:if, xsl:choose présente l'avantage de permettre d'effectuer plusieurs tests à la suite.

Exemple :


<xsl:choose>

 <xsl:when
test="@type='domicile'">

 <p
style="background-color:yellow">Votre numéro de téléphone
<xsl:value-of select="./@type"/> est le <xsl:value-of
select="."/></p>

 </xsl:when>

 <xsl:otherwise>

 <p>Votre numéro
de téléphone <xsl:value-of select="./@type"/> est le
<xsl:value-of select="."/></p>

 </xsl:otherwise>

</xsl:choose>

xsl:otherwise indique le traitement à effectuer par défaut.

Tri d'une collection avec xsl:sort

Il est possible de trier des séries d'éléments.

Avant de faire l'expérience, créer le fichier suivant.

Fichier exemple2.xml



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

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

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

<ClubTarot>

 <Joueur niveau="bon">

 <Nom>Albert</Nom>

 <Tel type="domicile">04-56743678</Tel>

 <Tel
type="travail">04-45367624</Tel>

 <Couleur>Red</Couleur>

 </Joueur>

<Joueur niveau="moyen">

 <Nom>David</Nom>

 <Tel
type="domicile">04-74345678</Tel>

 <Tel type="travail">04-36763424</Tel>

 <Couleur>Yellow</Couleur>

 </Joueur>

<Joueur niveau="bon">

 <Nom>Ernest</Nom>

 <Tel
type="domicile">04-67743878</Tel>

 <Tel
type="travail">04-53667724</Tel>

 <Couleur>Green</Couleur>

 </Joueur>

</ClubTarot>

Pour trier une collection d'éléments, il faut se placer dans l'élément père et utiliser l'instruction xsl:sort pour trier les éléments choisis.

Fichier page2.xsl


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

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

 <xsl:output
method="html"/>

 <xsl:template
match="/">

<xsl:processing-instruction
name="cocoon-format">type="text/html"</xsl:processing-instruction>

 <html>
 <head>
<title>Bienvenue au club !</title>
 </head>
 <body>
<h1>Liste des membres</h1>
<xsl:for-each
select="/ClubTarot/Joueur">
 <xsl:sort
select="Nom" order="descending"/>

 <p><xsl:value-of
select="Nom"/></p>

</xsl:for-each>

 </body>

 </html>

 </xsl:template>

</xsl:stylesheet>

Créer la feuille de style page2.xsl et la tester.

Autres moyens d'accès aux données XML

Sélection des éléments en fonction de leur position

XSL offre la fonction position() pour calculer la position d'un élément.

Les fonctions last et first permettent 'également d'avoir une indication sur la position.

Sélection du premier

Exemple


<xsl:value-of
select="/ClubTarot/Joueur[1]/Name"/>

<xsl:value-of
select="/ClubTarot/Joueur[position()=1]/Nom"/>

Sélection du dernier

Exemple


<xsl:value-of
select="/ClubTarot/Joueur[last()]/Nom"/>

Sélection de tous sauf le dernier

Exemple


<xsl:for-each
select="/ClubTarot/Joueur[not(position()=last())]">

 <xsl:sort
select="Nom" order="descending"/>


<p><xsl:value-of select="Nom"/></p>

</xsl:for-each>

Sélection de tous sauf le premier

Exemple


<xsl:for-each select="/ClubTarot/Joueur[not(position()
&gt; 1)]">

 <xsl:sort
select="Nom" order="descending"/>

 <p><xsl:value-of
select="Nom"/></p>

</xsl:for-each>

Sélection de tous les petits fils d'un élément

Exemple


<xsl:for-each select="/ClubTarot/*/Nom">

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

</xsl:for-each>

Listes : xsl:number

L'élément XSL xsl:number renvoie le nombre correspondant à la position de l'élément courant (.) dans la sélection.

Exemple :


<xsl:number value="position()"
format="1"/><xsl:text>.</xsl:text><xsl:value-of
select="Nom"/>

Valeur de départ

La valeur de départ peut être modifiée.

Exemple :


<xsl:number value="position() - 1"
format="1"/>

Format

Plusieurs format sont disponibles :

Format="1" affiche la séquence 1,2,3,…

Format="01" affiche la séquence 01,02,03,…

Format="a" affiche la séquence a,b,c,…

Format="A" affiche la séquence A,B,C,…

Format="I" affiche la séquence I,II,III,…

Format="i" affiche la séquence i,ii,iii,…

Réaliser une liste numérotée en chiffres romains des noms des joueurs du club.

Variables ($variable)

L'élément xsl:variable permet de créer des variables qui conservent une valeur.

Déclaration

Exemple


<xsl:variable name="salutation" select="Bonjour
!"/>

Affichage de la variable


<xsl:value-of select="$salutation"/>

Autre exemple


<xsl:variable name="ancetres"
select="ancestor()"/>

Cet exemple crée une variable qui contient l'ensemble des ancétres de l'élément courant : une variable peut contenir des éléments (pas seuelement des chaînes).

Portée

Une variable n'a d'existence qu'à l'intérieur du modèle ou de la boucle où elle a été créee.

Il est possible de créer des variables globales en les déclarant à l'extérieur d'un modèle.

Valeurs multiples

Pour stocker plusieurs valeurs dans une variable il est possible de créer une variable à partir d'une liste d'éléments.

Exemple


<xsl:variable name="ma_variable">

<xsl:for-each
select="ClubTarot/Joueur">

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

 /
</xsl:for-each>

</xsl:variable>

<xsl:value-of select="$ma_variable"/>

Créer la variable précédente dans la feuille de style.

Chaînes

XSL met à la disposition des auteurs plusieurs fonctions de manipulation de chaîne.

Concatènation

Exemple


<xsl:for-each select="/ClubTarot/Joueur">


<p><xsl:value-of select="concat('Bonjour
',Nom)"/></p>

</xsl:for-each>

Comparaison de chaînes

Contains(chaîne à tester, chaîne test)

La fonction contains renvoie vrai si la chaîne à tester contient la chaîne test.

Exemple


<xsl:if test="contains($salutation,'jour')">

C'est donc qu'il fait jour !

</xsl:if>

Starts-with(chaîne à tester, expression test)

La fonction starts-with renvoie vrai si la chaîne à tester d'ébute par l'expression test.

Exemple


<xsl:if test="starts-with($salutation,'Bon')">

Cela commence donc par bon !

</xsl:if>

Extraction de chaînes

Substring-before(chaîne à tester, expression test)

La fonction substring-before renvoie la partie de la chaîne à tester située avant l'expression test.

Exemple


<xsl:variable name="prefixeTel"
select="substring-before(/ClubTarot/Joueur[Nom='Albert']/Tel[@type='domicile'],'-')"/>

<xsl:value-of select="$prefixeTel"/>

Substring-after(chaîne à tester, expression test)

La fonction substring-after renvoie la partie de la chaîne à tester située après l'expression test.

Exemple


<xsl:variable name="numTel"
select="substring-after(/ClubTarot/Joueur[Nom='Albert']/Tel[@type='domicile'],'-')"/>

<xsl:value-of select="$numTel"/>

Substring(chaîne à tester, index.longueur)

La fonction substring renvoie la partie de la chaîne à tester située entre l'index et l'index plus la longueur passée en argument.

Si la longueur n'est pas spécifiée, la chaîne est retournée de l'index à la fin.

Exemple


<xsl:variable name="milieuTel"
select="substring
(/ClubTarot/Joueur[Nom='Albert']/Tel[@type='domicile'],2,8)"/>

<xsl:value-of select="$milieuTel"/>

Longueur : string-length(chaîne)

La fonction string-length renvoie la taille de la ch4ine donnée en argument.

Translate(chaine,chainesource,chainecible)

Transforme une chaîne en fonction des chaînes indiquées en paramêtre.

Exemple


<xsl:variable
name="upperCaseChars" select=" 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
"/>

<xsl:variable
name="lowerCaseChars" select=" 'abcdefghijklmnopqrstuvwxyz'
"/>

translate(“Hello”,
$upperCaseChars, $lowerCaseChars)

Renvoie hello en minuscule.

Fonctions mathèmatiques

Les fonctions mathèmatiques de base des xsl sont les opérateurs : +,-,*, div et mod (reste d'une division).

Penser à encadrer le signe - par des espaces: les noms d'élements XML peuvent contenir ce caractère et il peut y avoir des risques de confusion par les parsers XML.

Sum(predicat)

Retourne la somme des valeurs des nœuds du prédicat

Floor(nombre)

Retourne le plus grand nombre entier qui ne dépasse pas le nombre.

Floor(3.5) retourne 3.

Ceiling(nombre)

Retourne le plus petit nombre entier qui n'est pas inférieur au nombre.

ceiling(3.5) retourne 4.

Round(nombre)

Retourne l'entier le plus proche du nombre.

Round(3.2) retourne 3.

Count(predicat)

Retourne le nombre d'él'éments du prédicat.

Fonctions d'acces aux elements / a d'autres documents

Name()

La fonction name() renvoie le nom de l'élément courant ou d'un de ses attributs.

Document()

La fonction document() permet d'insérer un document dans le document courant.

Exemple :


<xsl:variable name="menu"
select="document('map.xml')"/>

Il est ensuite possible d'itérer sur les éléments du document inséré.

Attributs xsl

Il est possible d'ajouter un attribut à la volée à un élément en cours de génération en utilisant l'instruction xsl:attribute.

Exemple


<TABLE
border="1" width="25%">

 <xsl:for-each select="/ClubTarot/Joueur">

 <TR>

 <xsl:if
test="position() mod 2 = 0">

 <xsl:attribute
name="bgcolor">yellow</xsl:attribute>


</xsl:if> 

 <TD><xsl:value-of
select="Nom"/></TD>

 </TR>

 </xsl:for-each>

</TABLE>

Insérer cet exemple dans la feuille de style et observer le résultat.

Passage de paramétres entre fonctions

(xsl:template + xsl:param + xsl:call-template)

L'exemple suivant montre comment utiliser les instructions xsl:param et xsl:call-template pour appeler un modèle XSL en lui passant des paramètres.

Exemple


<xsl:template
match="/">

 <HTML>

 <HEAD>

 <TITLE>Le club de Tarot</TITLE>

 </HEAD>

 <BODY>

 <xsl:call-template
name="displayNameWithFont">

 <xsl:with-param
name="fontFace" select="'Impact'"/>


<xsl:with-param name="name" 


select="/ClubTarot/Joueur[1]/Nom"/>


</xsl:call-template>

 <BR/>

 ...

 </BODY>

 </HTML>

 </xsl:template>

 <xsl:template
name="displayNameWithFont">

 <xsl:param
name="fontFace" select="'Braggadocio'"/> <!-- default
font -->

 <xsl:param
name="name"/>

 <FONT
face="{$fontFace}">

 <xsl:value-of
select="$name"/>

 </FONT>

 </xsl:template>

Valeur de retour d'une fonction

Il est possible de renvoyer une valeur de retour à la suite de l'appel d'un modèle.

La valeur doit être donnée par l'instruction xsl:value-of à l'intérieur de la fonction, sur le même principe que l'exemple précédent.

Créer une fonction qui renvoie le nombre passé en paramètre `à un modèle divisé par 2.

SVG : Generer une image a partir de texte(1/2h)

Générer une image à partir de donn'es XML consiste à passer une page avec des données dans une feuille de style qui transforme les éléments XML du document original en éléments SVG.

La principale différence avec les exemples précédents vient donc du jeu de balise employé.

Fichier svg-exemple.xml


<?xml version="1.0"?>

 

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

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



<page>


<title>Coucou</title>

 <content>

 <p>Une image en
SVG</p>

 </content>

</page>

Fichier svg-page.xsl


<?xml version="1.0"?>

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

<xsl:template
match="page">


<xsl:processing-instruction
name="cocoon-format">type="image/svg-xml"</xsl:processing-instruction>

 <svg
xml:space="preserve" width="360" height="160"
xmlns:xlink="http://www.w3.org/2000/xlink/namespace/">

 <defs>

 <filter
id="blur1"><feGaussianBlur
stdDeviation="3"/></filter>

 <filter
id="blur2"><feGaussianBlur
stdDeviation="1"/></filter>

 </defs>

 <g title="this
is a tooltip">

 <rect

style="fill:#0086B3;stroke:#000000;stroke-width:4;filter:url(#blur1);" x="30" y="30" rx="20" ry="20" width="300" height="100"/> <text style="fill:#FFFFFF;font-size:24;font-family:TrebuchetMS-Bold;filter:url(#blur2);" x="65" y="80"> <xsl:value-of select="content/p"/> </text> </g> </svg> </xsl:template> </xsl:stylesheet>

FO : transformer du XML en PDF (1/2h)

La technique pour FO (formatting Object) est identique à celle pour SVG.

Seul le format de sortie indiqué à Cocoon et les balises employées changent.

Se reporter aux exemples Cocoon pour la démonstration.

Réaliser une feuille de style FO pour les doucments du TP

c)      XML : utilisation sur la couche Application

Xinclude : construire un menu a partir d'une liste de documents(1/2h)

Xinclude est un sous-ensemble de XML qui permet d'inclure des documents dans un document XML.

Pour l'utiliser il faut déclarer une référence vers le jeu de balises Xinclude en début de document.

Dans le cas d'une utilisation avec Cocoon il faut également indiquer à Cocoon de traiter les instructions Xinclude avant le passage de la feuille de style XSL.

Fichier xinclude-exemple.xml

Fichier map.xml

Fichier xinclude-page.xsl

Se reporter à http://www.mycgiserver.com/~rastaman/projettv pour les sources de l'exemple.

Dériver l'exemple pour inclure les exemples traités aujourd'hui.

Les points suivants sont traités avec les exemples de Cocoon comme support.

XSP et JSP 1.2 : recuperer des informations envoyees par l'utilisateur (1/2h)

Objet request

d)     XML : utilisation sur la couche Donnees

Interrogation Bdd : afficher une table (1/2h)

Interrogation LDAP : afficher la fiche de quelqu'un (1/2h)