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>
Fonctionnement
Pour comprendre comment marche le XSL, imaginez des cartes
perforées (Eh oui... rappelez vous... bon moi je suis trop jeune j'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
A 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 ces fichiers
XML comme il l'entend. Il pourrait être intéressant de convertir
une représentation dans une autre. Pour ce faire il suffit juste 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.
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>
A l'intérieur des balises xsl:stylesheet, on va
insérer des templates qui vont être appliquées quand elles
matchent avec un noeud XML.
<xsl:template match="NAME">
</xsl:template>
L'élément xsl:apply-templates permet de continuer
l'application des templates pour les noeuds fils du noeud 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
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é:
- Au départ on se trouve à la racine (/)
de l'arbre de données. La template matchant sur / est alors
activée.
- cette template m'indique que je dois appliquer les
templates à partir de LIVRES. On sélectionne donc tous les noeuds
LIVRES qui sont fils de /.
- On matche sur un noeud LIVRES et on applique la
template correspondante.
- La template LIVRES génére les tags
html et body.
- On applique ensuite les templates en
sélectionnant les noeuds LIVRE. Dans notre cas on en a 2 noeuds, on
appliquera donc 2 fois la template.
- 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 élements.
- On fait de même pour le deuxième noeud
LIVRE.
- On a fini d'appliquer les templates pour le noeud
LIVRE, on remonte donc d'un niveau jusqu'a la template LIVRES
- On génère les 2 tags de fin
body et
html.
- On remonte à la template /. On a terminé
de parcourir l'arbre des données.
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
soit meme, 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 maitenabilité 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'oeil 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)
Création de l'application WebSnap
Menu Fichier | Nouveau | autre, obglet WebSnap,
sélectionnez Application WebSnap. Un 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 toutes façons 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
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 Transcation,
indiquez les paramètres de connexion à la base employee. 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
departments. 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 DEAPRTMENT
|
Puis la propriété Active à True. Les
enregistrements correspondant à la requêtes sont ainsi
récupérées. 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.
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 editer 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 sagit 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 |
Editeur Externe. Ci-dessous un aperçu de la visualisation
hiérarchique très pratique de XMLSpy.
Quelque 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:
Ajout d'un lien
Nous allons maintenant rajouter un lien sur les numeros de
département (colonne DEPT_NO). Ce lien va pointer sur une autre page
détaillant les departements. Nous allons donc dans cette URL passer un
paramètre qui va être le numéro départment
correspondant.
Pour cela il nous suffit juste de modifier le fichier XSL
(donc pas besoin de recompiler !) de la manière suivante: dans la
template ROW on va rajouter un élement a, et contruire
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.
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 3 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 chaine de
données est connectée ou active). Vérifiez dans l'onglet Arborescence
XML que les données sont bien extraite 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 passer 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 departments et
sélectionnez-en un. Vous devez maintenant pouvoir avoir les informations
détaillées de chacun des departments !
Conclusion
Nous avons vu ce qu'était le XSL, et comment le
mettre en pratique pour la création d'application web maintenable et
évolutive. Remarquez cependant qu'il faut quand meme un Web page Module
par page ! Au bout d'une dizaine de pages, ca 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é 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 oeil 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.
|