XML/XSL

Jean-Philippe BEMPEL

- Titre : XML/XSL

- Auteur : Jean-Philippe BEMPEL

- Parution : 14 octobre 2001

- Mise à jour : 25 décembre 2019

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2001 Jean-Philippe BEMPEL. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Présentation

- II. Fonctionnement

- III. Syntaxe

- IV. Exemple

- V. WebSnap

- VI. Création de l'application WebSnap

- VII. Création du DataModule et configuration de l'accès à la base de données

- VIII. Création de la page ListDepartment

- IX. Ajout d'un lien

- X. Création de la page FormDepartment

- XI. Conclusion

I - Présentation

Il n'est plus besoin de présenter, je crois, ce qu'est XML, tout le monde en a entendu parler au moins une fois. Si ce n'est pas le cas, je vous conseille de lire l'article de Sylvain James. Pour ma part je vais m'attarder sur un langage s'appuyant sur ce dernier : XSL.

L'acronyme XSL signifie eXtensible Stylesheet Language. C'est un langage standardisé par le W3C dont vous pouvez prendre connaissance de la norme à cette adresse : http://www.w3.org/TR/xsl/. XSL permet de décrire une feuille de style, c'est-à-dire la manière dont vont être représentées les données. Ces dernières sont au format XML et le XSL exploite la structuration qu'apporte le XML pour appliquer les styles. On va ainsi pouvoir mettre en gras certaines données extraites provenant du flux XML au niveau du code HTML, c'est-à-dire encadrer la donnée de balises <b>

II - Fonctionnement

Pour comprendre comment marche le XSL, imaginez des cartes perforées (Eh oui… rappelez-vous… bon moi je suis trop jeune je n'ai pas connu;-), que l'on introduisait dans un ordinateur ou un orgue de barbarie. Dès que le mécanisme rencontre un trou dans la carte, un levier est activé (en gros…). Maintenant, considérons un fichier XSL comme une carte perforée et notre fichier XML représentant les leviers. Lorsqu'on rencontre un trou dans le fichier XSL, on le remplit avec la donnée correspondante qui provient du fichier XML :

À la sortie, on peut produire… tout ce que l'on veut. En général on génère du HTML, mais il est tout à fait possible de générer un autre fichier XML. On peut alors imaginer un convertisseur de format XML. En effet chacun structure ses fichiers XML comme il l'entend. Il pourrait être intéressant de convertir une représentation dans une autre. Pour ce faire, il suffit d'un fichier XSL. On peut ainsi transformer un fichier XML en autant de formats que l'on souhaite, pour chaque format on aura un fichier XSL. De plus, on externalise par rapport à l'application : pas besoin de la recompiler pour ajouter un nouveau format qui est, de plus, modifiable à volonté. Il est aussi possible de produire des fichiers binaires par exemple un fichier PDF ou bien de transformer un fichier XML en un fichier ini. Bref, les possibilités du XSL sont infinies ! C'est un outil d'extraction et de transformation de données. On va pouvoir extraire de notre fichier XML que les données qui nous intéressent à un moment donné.

Concrètement, que vous apporte le XSL ? Avant toutes choses, c'est un standard ! Il n'est pas propriétaire comme pourrait l'être l'ASP ou autre langage de script. Autre avantage : la maintenabilité. En effet, en plus d'être une ressource externe par rapport à votre application Web, il est possible de créer des templates réutilisables à volonté, voire de créer des sortes de composants XSL.

III - Syntaxe

Je vais présenter brièvement certains éléments de syntaxe essentiels pour faire un fichier XSL.

Les éléments XSL sont des balises XML préfixées par le namespace xsl.

Exemple :

<xsl:template>

Un fichier XSL minimal se présente sous la forme suivante :

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/TR/WD-xsl">
</xsl:stylesheet>

À l'intérieur des balises xsl:stylesheet, on va insérer des templates qui vont être appliquées quand elles matchent avec un nœud XML.

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

L'élément xsl:apply-templates permet de continuer l'application des templates pour les nœuds fils du nœud courant de l'arbre des données XML.

L'élément xsl:value-of permet de récupérer la valeur contenue entre les balises XML de l'arbre de données.

IV - Exemple

Voici un fichier de données XML :

<LIVRES>
<LIVRE>
<TITRE>Fondation</TITRE>
<AUTEUR>
<NOM>ASIMOV</NOM>
<PRENOM>Isaac</PRENOM>
</AUTEUR>
<GENRE>Science-Fiction</GENRE>
</LIVRE>
<LIVRE>
<TITRE>Les Robots</TITRE>
<AUTEUR>
<NOM>ASIMOV</NOM>
<PRENOM>Isaac</PRENOM>
</AUTEUR>
<GENRE>Science-Fiction</GENRE>
</LIVRE>
</LIVRES>

Je vais lui appliquer le fichier XSL suivant :

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl: template match="/">
<xsl:apply-templates select="LIVRES"/>
</xsl:template>
<xsl: template match="LIVRES">
<html>
<body>
<xsl:apply-templates select="LIVRE"/>
</body>
</hmtl>
</xsl:template>
<xsl: template match="LIVRE">
Titre: <b><xsl:value-of select="TITRE"/></b><br/>
Auteur: <b><xsl:value-of select="AUTEUR/NOM"/></b> <b><xsl:value-of select="AUTEUR/PRENOM"/></b><br/>
Genre: <b><xsl:value-of select="GENRE"/></b><br/><br/>
</xsl:template>
</xsl:stylesheet>

Ce qui donne à la sortie le fichier HTML suivant :

<hmtl>
<body>
Titre: <b>Fondation</b><br/>
Auteur: <b>ASMIOV</b> <b>Isaac</b><br/>
Genre: <b>Science-Fiction</b><br/><br/>

Titre: <b>Les Robots</b><br>
Auteur: <b>ASMIOV</b> <b>Isaac</b><br/>
Genre: <b>Science-Fiction</b><br/><br/>
</body>
</html>

Description pas à pas de ce qui s'est passé :

1. Au départ on se trouve à la racine (/) de l'arbre de données. La template matchant sur / est alors activée ;

2. Cette template m'indique que je dois appliquer les templates à partir de LIVRES. On sélectionne donc tous les nœuds LIVRES qui sont fils de / ;

3. On matche sur un nœud LIVRES et on applique la template correspondante ;

4. La template LIVRES génère les tags html et body ;

5. On applique ensuite les templates en sélectionnant les nœuds LIVRE. Dans notre cas on en a deux nœuds, on appliquera donc deux fois la template ;

6. On génère le contenu de la template et entre les balises b on récupère la valeur de la balise TITRE du fichier XML. On fait de même pour AUTEUR/NOM et AUTEUR/PRENOM. Il est a noté ici, que l'on spécifie un XPath, qui est chemin pour accéder aux éléments ;

7. On fait de même pour le deuxième nœud LIVRE ;

8. On a fini d'appliquer les templates pour le nœud LIVRE, on remonte donc d'un niveau jusqu'à la template LIVRES ;

9. On génère les deux tags de fin body et html ;

10. On remonte à la template /. On a terminé de parcourir l'arbre des données.

V - WebSnap

Avec la technologie WebSnap de Borland, introduite avec Delphi 6, il est possible relativement simplement de mettre en place une architecture fondée sur XML/XSL. WebSnap est une évolution par rapport au simple DLL ISPAPI (et le WebBroker), car auparavant il fallait gérer à peu près tout à la main : création du code HTML parfois codé en dur, remplacement dynamique à faire soi-même, etc. WebSnap permet de pallier ces problèmes et ouvre plusieurs nouvelles perspectives pour développer plus rapidement des applications web. On commence à déporter le dynamisme des pages dans des ressources externes pour la maintenabilité tout en conservant la rapidité d'un code compilé. Il faut considérer WebSnap comme une surcouche à la DLL ISAPI.

L'emploi du XML/XSL pour faire une application web a l'avantage de bien séparer les données (le XML) de leur représentation (XSL). Ceci permet une maintenance plus aisée : on peut changer seulement les données (changement de base de données, de connectivité, etc.) ou bien changer seulement l'apparence, pour cela on a seulement un fichier XSL à changer, sans recompiler, voire à la volée.

Pour ceux qui ne sont pas encore familiarisés avec WebSnap, je vous conseille d'aller jeter un coup d'œil sur le tutoriel de JP Lamon.

Pour ce tutoriel, j'utilise un serveur Interbase 6 (fourni sur le CD de Delphi6) sur la base de données exemple employee.gdb. (C:\Program Files\Borland\Interbase\examples\database\employee.gdb).

VI - Création de l'application WebSnap

Menu Fichier | Nouveau | Autre, onglet WebSnap, sélectionnez Application WebSnap. Une boite de dialogue s'affiche :

Sélectionnez Executable autonome CGI pour le type de serveur, histoire de ne pas avoir de problèmes pour le déploiement, mais une DLL ISAPI sera de toute façon conseillée pour le développement d'une vraie application. J'ai choisi Module de données pour les composants du module d'application. En effet je ne veux pas de page par défaut lorsque l'on ne spécifie pas d'action dans l'URL.

Après validation, Delphi génère un WebModule (TWebAppDataModule) que je renomme en wmMain (wm = WebModule). Cliquez sur tout enregistrer et sauvegardez les fichiers : Main_wm.pas et Department.dpr

VII - Création du DataModule et configuration de l'accès à la base de données

Nous allons maintenant créer un DataModule qui contiendra les composants d'accès à la base de données. Faites Fichier | Nouveau | Autre, onglet WebSnap, Module de données WebSnap. Laissez par défaut les options de la boite de dialogue. Renommez-le wdmMain (wdm = Web Data Module) et sauvegardez-le en Main_wdm.pas.

Sur ce DataModule on va maintenant poser un composant IBDatabase (renommez en Database), un composant IBTransaction (renommez en Transaction). Connectez la propriété DefaultTransaction du composant Database sur Transaction, indiquez les paramètres de connexion à la base employée. Indiquez bien une connexion distante par TCP pour ne pas avoir de problème de database unvailable.

Connectez la propriété DefaultDatabase du composant Transaction au composant Database. Connectez le tout : propriété Connected à True pour Database et propriété Active à True pour Transaction.

Maintenant nous allons préparer les données à afficher pour notre première page : La liste des départements.

Posez un composant IBQuery (renommez en qryListDepartment). Connectez-le à la database et à la transaction par l'intermédiaire des propriétés Database et Transaction. Entrez ensuite le code SQL suivant :

SELECT DEPT_NO, DEPARTMENT
FROM DEPARTMENT

Puis la propriété Active à True. Les enregistrements correspondant à la requête sont ainsi récupérés. Nous voulons maintenant les transformer au format XML. Pour cela on va passer par le composant XMLBroker (onglet InternetExpress, renommez brkListDepartment) et le composant DataSetProvider (onglet AccèsBD, renommez dspListDepartment). Connectez la propriété DataSet du composant dspListDepartment au composant qryListDepartment. Puis la propriété ProviderName du composant brkListDepartment au composant dspListDepartment. Passez enfin la propriété Connected de brkListDepartment à True.

VIII - Création de la page ListDepartment

Fichier | Nouveau | Autre, onglet WebSnap, Module de Page WebSnap.

Sélectionnez pour le type du Générateur XSLPageProducer. Ceci nous permettra de générer une page HTML à partir d'un fichier XSL et d'un flux XML. Sélectionnez Modèle Standard pour le XSL. Le nom de la page est très important, car ce sera le nom de l'action à invoquer dans l'URL. Ici on met ListDepartment. Validez.

Sauvegardez le page module sous ListDepartment_pgm.pas (pgm = PageModule). Rajoutez à la clause uses, le DataModule Main_wdm (Alt + F11). Indiquez dans la propriété XMLData du composant XSLPageProducer wdmMain.brkListDepartment. Passez la propriété Active du XSLPageProducer à True.

Remarquez dans la partie basse de l'éditeur de code différents Tabs. Sélectionnez le tab pour l'arborescence XML. Vous devez voir le flux de données XML qui provient de notre XMLBroker.

Sélectionnez maintenant l'onglet ListDepartment_pgm.xsl. Vous pouvez éditer directement le code XSL dans l'éditeur de Delphi ou bien passer par un éditeur externe. La dernière option est conseillée, surtout s'il s’agit du très bon XMLSpy (http://www.xmlspy.com).

Pour configurer l'appel à l'éditeur externe, allez dans le menu Outils | Options d'environnement, onglet Internet. Sélectionnez XML.

Cliquez sur Modifier… et sélectionnez l'action appropriée. Pour XMLSpy, l'action apparaît après l'installation du logiciel.

Pour lancer l'éditeur, allez dans le menu Outils | Éditeur Externe. Ci-dessous un aperçu de la visualisation hiérarchique très pratique de XMLSpy.

Quel que soit votre mode d'édition, votre fichier XSL doit ressembler à cela :

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="DATAPACKET/ROWDATA"/>
</body>
</html>
</xsl:template>
<xsl:template match="ROWDATA">
<table border="1">
<tr>
<td>
<b>DEPT_NO</b>
</td>
<td>
<b>DEPARTMENT</b>
</td>
</tr>
<xsl:apply-templates select="ROW"/>
</table>
</xsl:template>
<xsl:template match="ROW">
<tr>
<td>
<xsl:value-of select="@DEPT_NO"/>
</td>
<td>
<xsl:value-of select="@DEPARTMENT"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>

Vous pouvez vérifier dans l'onglet Résultat HTML la génération du code HTML résultant de la fusion XML/XSL, puis la prévisualisation du HTML.

Vous pouvez sauvegarder votre projet et le compiler. Nous allons le tester avec le serveur IIS. Auparavant nous allons créer un nouvel alias pour notre application. Dans le gestionnaire de service Internet, sélectionnez votre site web par défaut. Dans le menu contextuel sélectionnez Nouveau | Répertoire virtuel. Un assistant apparait alors. Le nom de notre alias sera DepartmentBin et le répertoire associé est le chemin d'accès à l'application compilée. N'oubliez pas de mettre les droits d'exécution sur l'alias.

Vous pouvez maintenant invoquer votre CGI de la manière suivante : http://localhost/DepartmentBin/Department.exe/ListDepartment. Vous devriez obtenir l'écran suivant :

IX - Ajout d'un lien

Nous allons maintenant rajouter un lien sur les numéros de département (colonne DEPT_NO). Ce lien va pointer sur une autre page détaillant les départements. Nous allons donc dans cette URL passer un paramètre qui va être le numéro département correspondant.

Pour cela il nous suffit de modifier le fichier XSL (donc pas besoin de recompiler !) de la manière suivanteš: dans la template ROW on va rajouter un élément a, et construire dynamiquement son attribut href (xsl:attribute).

<xsl:template match="ROW">
<tr>
<td>
<a>
<xsl:attribute name="href">FormDepartment?DEPT_NO=<xsl:value-of select="@DEPT_NO"/></xsl:attribute>
<xsl:value-of select="@DEPT_NO"/>
</a>
</td>
<td>
<xsl:value-of select="@DEPARTMENT"/>
</td>
</tr>
</xsl:template>

Vous pouvez maintenant retester votre application et constatez que le lien à été rajouté. Notez dans la barre d'état l'URL :

Celle-ci indique en paramètre le numéro du DEPT_NO correspondant. Il ne nous reste plus qu'à créer La page FormDepartment détaillant l'enregistrement.

X - Création de la page FormDepartment

Créer un nouvel Web Page Module nommé FormDepartment :

Enregistrez-le en tant que FormDepartment_pgm.pas. Revenons au Web Data Module Main_wdm. Déposez les trois composants IBquery, DataSetProvider et XMLBroker renommés respectivement qryFormDepartment, dspFormDepartment et brkFormDepartment. Configurez les composants comme pour ListDepartment. Dans le composant IBQuery entrez le code SQL suivant :

SELECT *
FROM DEPARTMENT
WHERE DEPT_NO = :DEPT_NO

:DEPT_NO est un paramètre qui est parsé automatiquement par le composant. dans la propriété Params vérifiez que le paramètre DEPT_NO a été ajouté automatiquement. Pour tester le fonctionnement à la conception, indiquer la valeur 621 dans la propriété Value du paramètre.

Revenez sur la page FormDepartment et rajoutez à la clause uses Main_wdm et connectez la propriété XMLData du composant XSLPageProducer (vérifiez bien que toute la chaîne de données est connectée ou active). Vérifiez dans l'onglet Arborescence XML que les données sont bien extraites et transformées :

Voici le contenu du fichier XSL :

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="DATAPACKET/ROWDATA"/>
</body>
</html>
</xsl:template>
<xsl:template match="ROWDATA">
<table border="1">
<xsl:apply-templates select="ROW"/>
</table>
</xsl:template>
<xsl:template match="ROW">
<tr>
<td>
<b>DEPT_NO:</b>
</td>
<td>
<xsl:value-of select="@DEPT_NO"/>
</td>
</tr>
<tr>
<td>
<b>DEPARTMENT:</b>
</td>
<td>
<xsl:value-of select="@DEPARTMENT"/>
</td>
</tr>
<tr>
<td>
<b>HEAD_DEPT:</b>
</td>
<td>
<xsl:value-of select="@HEAD_DEPT"/>
</td>
</tr>
<tr>
<td>
<b>BUDGET:</b>
</td>
<td>
<xsl:value-of select="@BUDGET"/>
</td>
</tr>
<tr>
<td>
<b>LOCATION:</b>
</td>
<td>
<xsl:value-of select="@LOCATION"/>
</td>
</tr>
<tr>
<td>
<b>PHONE_NO:</b>
</td>
<td>
<xsl:value-of select="@PHONE_NO"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>

Il nous faut pouvoir récupérer le paramètre passé dans l'URL. Pour cela, on va créer un gestionnaire d'événement sur le OnBeforeDispatch du Web PageModule FormDepartment. Tapez le code suivant pour ce gestionnaire :

procedure TFormDepartment.WebPageModuleBeforeDispatchPage(Sender: TObject;
const PageName: String; var Handled: Boolean);
var
DEPT_NO: string;
begin
DEPT_NO := Request.QueryFields.Values['DEPT_NO'];
wdmMain.qryFormDepartment.ParamByName('DEPT_NO').Value := DEPT_NO;
end;

Vous pouvez maintenant recompiler votre application et la tester à nouveau. Lancez-la sur la liste des départements et sélectionnez-en un. Vous devez maintenant pouvoir avoir les informations détaillées de chacun des départements !

XI - Conclusion

Nous avons vu ce qu'était le XSL, et comment le mettre en pratique pour la création d'applications web maintenables et évolutives. Remarquez cependant qu'il faut quand même un Web page Module par page ! Au bout d'une dizaine de pages, ça commence à devenir lourd… La description de la page Web est externe, il est donc facile de la modifier (fichier XSL) sans recompiler. La connexion et l'extraction des données sont par contre codées en dur. Il serait judicieux aussi d'externaliser cela. (Requête dans un fichier XML externe…) Il est donc possible de pousser encore la technologie pour qu'elle soit encore plus souple.

Je vous invite, d'ailleurs si le XML/XSL pour les applications web vous intéresse à jeter un œil sur les XMLComponents (http://xmlcomponents.com). C'est un framework basé sur XML/XSL permettant de développer des applications web client/serveur.

Merci à Sylvain James pour les remarques et la relecture de cet article.