Framework de présentation basé sur XML, XSL et .NET



e monde Java est (sur-)peuplé de frameworks de présentation, commerciaux ou gratuits. En particulier, nous avons déjà eu l’occasion de survoler Struts (basé sur les patterns MVC, singleton, médiateur, commande et mémento) que nous avions comparé à WebForms, framework intégré à la plate-forme .NET. A l’issue de cette présentation comparée, nous avions évoqué la possibilité de mettre en place un framework de présentation flexible et basé sur les langages XML et XSL.

C’est exactement l’objectif de cet article : essayer de bâtir avec vous, de manière progressive, un socle propre, évolutif et efficace de développement de sites Web. Nous procéderons par étapes, en nous attachant aux aspects incontournables d’un framework de présentation mais aussi en essayant d’apporter systématiquement une réponse cohérente en utilisant les technologies connexes à XML. Bien entendu, dans cette optique, nous justifierons nos éventuels « écarts de conduite ».

La motivation de cet article vient d’une conviction de l’auteur que l’utilisation intelligente de XML peut raccourcir considérablement les temps et les coûts de développement d’un site Web (mais tous les frameworks nous promettent déjà ce genre de choses) tout en améliorant la testabilité et la qualité de l'application. Le framework que nous allons élaborer ici n’existe pas, n’est pas à vendre, mais à construire. C’est un projet ambitieux, et nous invitons les lecteurs à donner leur avis et à partager leurs idées novatrices sur le site DotNetGuru au travers des commentaires et forums.

Introduction aux technologies utilisées

XML

XML est un langage textuel et arborescent permettant de décrire des données structurées. Le type d’informations que l’on décrit en XML va des images vectorielles en 2D (SVG) aux mondes virtuels 3D (X3D), en passant par les documents administratifs typiques tels que les bons de commande, factures, appels d’offres… Bref, XML nous offre un cadre, une syntaxe, pour bâtir de nouveaux langages. Il nous apporte également un outillage assez riche, à commencer par les outils de lecture/écriture de documents XML (parseurs), les outils de contraintes (schémas) et de transformation (XSL).

Dans cet article, nous allons créer quelques structures de données XML permettant de gérer présentation, internationalisation et personnalisation, et nous nous appuierons pour la partie visualisation sur des langages standards (également compatibles avec XML) tels que XHTML, XSLFO ou SVG.

Voici l’exemple sur lequel nous allons travailler: un système de recherche d’appartements à louer. La liste des appartements disponibles est décrite dans le document XML suivant :

<?xml version="1.0" encoding="iso-8859-1" ?>
<
Appartements>
  <Appartement type="f3" surface="60">
    <Loyer mensualité="750" charges="50" devise="EUROS" />
    <Adresse numéro="74" voie="rue" nomDeVoie="Turenne" ville="Paris" pays="France"/>
    <Description>
    Petit appartement sympa au 6ème étage
    d'un immeuble de standing. Proche
    commerces et transports, lumineux et agréable à vivre.
    </Description>
  </Appartement>
  <Appartement type="f2" surface="43">
    <!-- etc... -->
  </Appartement>
</
Appartements>

 

XML Schémas

Il existe de nombreux langages de contraintes permettant de fixer lexique et grammaire d’un langage basé sur XML, c’est-à-dire :

Nous retiendrons ici XML Schéma car il est standard, puissant, et écrit lui-même en XML. D’autant que l’outillage est aujourd’hui tout à fait adapté à ce langage : VisualStudio.NET permet, d’un simple clic, de « générer le XML Schéma » du document XML en cours d’édition. Le résultat est assez convaincant, et disponible sous format textuel ou graphique.

<?xml version="1.0" ?>
<
xs:schema id="Appartements" targetNamespace="http://tempuri.org/Apparts.xsd"
  
xmlns:mstns="http://tempuri.org/Apparts.xsd"
  
xmlns="http://tempuri.org/Apparts.xsd"
  
xmlns:xs="http://www.w3.org/2001/XMLSchema">
   
<xs:element name="Appartements">
     
<xs:complexType>
       
<xs:choice maxOccurs="unbounded">
         
<xs:element name="Appartement">
           
<xs:complexType>
             
<xs:sequence>
               
<xs:element name="Description" type="xs:string" minOccurs="0"/>
               
<xs:element name="Loyer" minOccurs="0" maxOccurs="unbounded">
                 
<xs:complexType>
                   
<xs:attribute name="mensualité" type="xs:string" />
                   
<xs:attribute name="charges" type="xs:string" />
                   
<xs:attribute name="devise" type="xs:string" />
                 
</xs:complexType>
               
</xs:element>
               
<xs:element name="Adresse" minOccurs="0" maxOccurs="unbounded">
                 
<xs:complexType>
                   
<xs:attribute name="numéro" type="xs:string" />
                   
<xs:attribute name="voie" form="unqualified" type="xs:string" />
                   
<xs:attribute name="nomDeVoie" type="xs:string" />
                   
<xs:attribute name="ville" type="xs:string" />
                   
<xs:attribute name="pays" type="xs:string" />
                 
</xs:complexType>
               
</xs:element>
             
</xs:sequence>
             
<xs:attribute name="type" type="xs:string" />
             
<xs:attribute name="surface" form="unqualified" type="xs:string" />
           
</xs:complexType>
         
</xs:element>
       
</xs:choice>
     
</xs:complexType>
  
</xs:element>
</
xs:schema
>

 

XSL

XSL est une norme double qui décrit à la fois

Ce chapitre utilise XSLT pour transformer, trier, filtrer des informations métier décrites en XML, mais aussi pour effectuer la fusion (la jointure) de plusieurs documents XML (usage typique de XSLT pour l’internationalisation). XSLT est un véritable langage de programmation, particulièrement adapté au traitement de données arborescentes.

Voici un exemple (simpliste) de transformation du document XML précédent en une page HTML.

<?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>
     
<body>
       
<xsl:apply-templates />
     
</body>
   
</html>
 
</xsl:template>


 
<xsl:template match="Appartement">
   
<h3>Location</h3>
   
<p><xsl:value-of select="Description" /></p>
   
<table border="1">
     
<tr>
       
<td>Type</td>
       
<td>Surface (m2)</td>
       
<td>Loyer (<xsl:value-of select="Loyer/@devise" />)</td>
       
<td>Charges (<xsl:value-of select="Loyer/@devise" />)</td>
     
</tr>
     
<tr>
       
<td><xsl:value-of select="@type" /></td>
       
<td><xsl:value-of select="@surface" /></td>
       
<td><xsl:value-of select="Loyer/@mensualité" /></td>
       
<td><xsl:value-of select="Loyer/@charges" /></td>
     
</tr>
   
</table>
 
</xsl:template>
</
xsl:stylesheet>

 

Pipeline de traitements

Une feuille de style est un organe de transformation qui travaille sur un (ou plusieurs) document XML en entrée et génère un (ou plusieurs) document en sortie. Si le document produit en sortie est un document XML bien formé, rien n’empêche de coupler la sortie d’une première feuille XSL à l’entrée d’une seconde… et ainsi de suite. On parle dès lors de pipeline de transformations. Cette technique est séduisante, car elle permet de bien répartir les responsabilités sur les différents étages du pipeline, au lieu de bâtir une feuille XSL qui traiterait à la fois de la présentation, de l’internationalisation, de la personnalisation, etc…

Etude de cas   

Comme nous l’avons mentionné plus haut, nous allons prendre l’exemple d’un site d’offres de locations d’appartements. L’utilisateur saisit dans un formulaire HTML les critères de sélection de sa recherche d’appartement, et le système sélectionne les offres correspondantes (dont la description est en XML bien entendu), puis les présente en HTML. Il serait également souhaitable que l’utilisateur membre authentifié du site puisse personnaliser sa page d’accueil, sa charte graphique, la disposition des différents éléments composant son interface graphique. Et, cela va sans dire, le site doit s’adapter aux préférences linguistiques de l’utilisateur.

Techniques de présentation     

Deux approches antithétiques

Il existe typiquement deux approches de la présentation de données : « push » et « pull ».

La plupart des frameworks Web tels que Apache Struts, Microsoft WebForms, PHP, adoptent une approche « pull » où les pages dynamiques doivent polluer leur code avec des instructions de code en Java, VB.NET ou C#, et PHP. Cette approche est simple, intuitive pour un développeur, mais rend difficile la création collégiale de pages Web par des développeurs ET des graphistes. Les efforts du type TagLibs et WebForms sont un élément de réponse, mais nécessitent toujours de comprendre un langage autre que HTML.

Autre technique, mise en œuvre par le framework XMLC de Enhydra, le « push ». Cette fois, les pages de présentation sont rédigées entièrement dans le langage que maîtrisent les graphistes : HTML. Ce n’est que plus tard que les pages seront traitées : lors de l’exécution d’une requête, XMLC permet au développeur Java de charger la page HTML sous la forme d’un graphe d’objets Java en mémoire, et de modifier ce modèle en ajoutant aux bons endroits les informations dynamiques. L’identification des zones « à remplacer » est triviale, elle s’appuie sur un attribut « id » que l’on place sur les éléments HTML.

Nous choisissons ici la deuxième approche, en utilisant XSL en lieu et place du Framework XMLC. Cette façon de faire nous paraît à la fois la plus propre et la plus respectueuse de la philosophie de XML : la séparation entre contenu et présentation.

 Framework de présentation en XSL

Nous souhaitons présenter en HTML la liste des offres de location d’appartement correspondant à une requête particulière. Le premier réflexe consiste à séparer l’exécution de la requête et la présentation de son résultat dans deux feuilles de style différentes. Dans cette section, nous allons nous focaliser sur   la deuxième feuille, qui se charge exclusivement de la présentation.

L’idée est de rédiger un document XHTML en utilisant l’outil graphique (WYSIWYG) de conception de pages Web de VisualStudio.NET. Cette page Web modèle (« template ») ne s’attache pas du tout aux données contenues mais décrit précisément l’apparence souhaitée ; elle représente le canevas graphique que l’on devra suivre pour présenter le résultat de la requête de l’utilisateur.

 

 

Pour simuler notre outil de présentation, supposons que le résultat de la requête de l’utilisateur soit le même que le premier exemple de document XML donné en introduction de cet article :

<?xml version="1.0" encoding="iso-8859-1" ?>
<
Appartements
>
 
<Appartement type="f3" surface="60">
   
<Loyer mensualité="750" charges="50" devise="EUROS" />
   
<Adresse numéro="74" voie="rue"
             
nomDeVoie="Turenne" ville="Paris" pays="France"/>
   
<Description>
    Petit appartement sympa au 6ème étage
    d'un immeuble de standing. Proche
    commerces et transports, lumineux et agréable à vivre.
   
</Description>
 
</Appartement>
 
<Appartement type="f2" surface="43">
   
<!-- etc... -->
  
</Appartement>
</
Appartements>

 

Il nous suffit alors de fusionner les données (XML) et leur template de présentation (XHTML) en utilisant une feuille de styles XSL.

 

<?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:variable name="données"
  
select="document('file:///D:/DotNetGuru/XML-Framework/appart.xml')" />

 
<xsl:template match="*">
   
<xsl:copy>
     
<xsl:copy-of select="@*" />
     
<xsl:apply-templates select="node()" />
   
</xsl:copy>
 
</xsl:template>


 
<xsl:template match="TABLE">
   
<TABLE>
     
<xsl:copy-of select="@*" />
     
<xsl:variable name="TR-model" select="TR[1]" />
     
<xsl:copy-of select="TR[1]" />
     
<xsl:for-each select="$données//Appartement">
       
<TR>
         
<xsl:copy-of select="$TR-model/@*" />
         
<TD><xsl:number format="001" /></TD>
         
<TD><xsl:value-of select="@type" /></TD>
         
<TD><xsl:value-of select="Loyer/@mensualité" /></TD>
         
<TD><xsl:value-of select="Loyer/@charges" /></TD>
         
<TD><xsl:value-of select="@surface" /></TD>
       
</TR>
     
</xsl:for-each>
   
</TABLE>
 
</xsl:template>
</
xsl:stylesheet
>

 

 

 

Quelques explications s’imposent toutefois : la feuille de style précédente copie à l’identique la plupart des éléments du modèle XHTML (attributs compris), à l’exception de la balise TABLE, dont on ne conserve que les attributs et la première ligne. Les lignes suivantes du tableau sont générées dynamiquement, en itérant sur la liste des offres de location (stockées dans le fichier file:///D:/DotNetGuru/XML-Framework/appart.xml').

Notez que cette approche fonctionne bien pour les cas très simples ; un cas réel utiliserait un modèle beaucoup plus complexe comportant plusieurs tableaux, et notre feuille de style ne conviendrait plus. Il faudrait, dans ce cas, associer un identifiant unique à chaque zone dynamique (en utilisant l’attribut ID des éléments XHTML par exemple) ; la feuille de style XSL s’attacherait à remplacer toutes les zones dynamiques par des données métier présentées en HTML.

Internationalisation (i18n)   

De même que pour la partie présentation, l’internationalisation peut être gérée par l’insertion dans une page Web de l’appel à un composant de traduction automatique de mots-clé abstraits en leur traduction dans la langue préférée de l’utilisateur courant (le header HTTP accept-langage nous informe de cette préférence). Même remarque que précédemment, cela vient polluer le code HTML de la page de présentation, et rend les choses plus complexes pour les graphistes qui ne disposent pas nécessairement de l’environnement d’exécution des pages dynamiques (éviter que chaque designer ait à développer ses pages et les tester au sein d’un serveur d’application…). De plus, ajouter des balises spécifiques rend difficile l’utilisation de certains outils graphiques de génération de pages Web.

L’alternative est la même que pour la présentation : au lieu de tirer l’information traduite dans la page Web, poussons-là grâce à une nouvelle feuille de style XSL. Mais cette fois-ci, il nous faudra un peu d’aide de la part des graphistes qui bâtissent les modèles HTML : notre feuille XSL d’internationalisation devra déterminer quelles zones sont à traduire, et à quel message abstrait l'application fait référence. Plusieurs techniques s’offrent à nous, par exemple :

L’exemple ci-dessus est partiel, bien entendu : il faudrait que notre feuille de style prenne en paramètre la langue préférée de l’utilisateur, et qu’elle recherche la traduction des mots-clés dans le fichier XML adéquat.

Une remarque toutefois concernant ces techniques : cela suffit à traduire le texte dans la langue préférée de l’utilisateur, mais en aucun cas à prendre en considération les problématiques culturelles : il faut également adapter les couleurs du site, les sons joués… qui peuvent avoir des sémantiques variées selon les pays.

D’autre part, nous avons parlé de traduction de texte vers des langues « proches » du français (au sens de l’écriture). Ces techniques sont inefficaces lorsque les langues cibles sont plus éloignées. L’arabe et le chinois sont de bons exemples, puisque leur sens ou direction d’écriture ne sont pas les mêmes qu’en français, ce qui implique généralement une re-conception complète de l’interface utilisateur.

Customiser le framework de présentation    

C’est le premier besoin auquel doit répondre un framework : être aisément adaptable aux souhaits des concepteurs de sites. Il faut typiquement que la mise en page, la charte graphique, l’agencement des éléments les uns par rapport aux autres… soient faciles à modifier.

La tendance actuelle pour maximiser la liberté des concepteurs est de rendre chaque partie du site modulaire : si chaque élément d’information est indépendant des autres, rien n’empêche de choisir les éléments à la carte, et de les organiser à notre guise. C’est typiquement ce que l’on retrouve dans un « portail » : chaque élément d’information est généré par une « portlet », que l’on peut activer ou désactiver à souhait.

XSL est l’outil idéal pour réaliser la fusion (ou l’agrégation) d’un ensemble de documents XHTML. Prenons l’exemple d’une feuille de styles qui organise dans un tableau un ensemble de pages atomiques (nos équivalents de « portlets ») :

 

Modifier l’agencement des portlets dans l’agrégat final revient dès lors à modifier le « portail XSL ». Cette approche est sensée pour celui qui connaît déjà la syntaxe XSL, mais gagnerait à être rendue descriptive. On peut tout à fait imaginer un document XML dans lequel on décrirait de manière abstraite l’agencement des portlets, et le « portail XSL » ne ferait que suivre les directives de ce fichier XML de configuration. Cela permettrait du même coup à l’utilisateur final de sélectionner lui-même (comme dans la plupart des portails) les composants qui l’intéresse.

Enfin, toujours concernant le paramétrage, mentionnons le fait que l’utilisation de XSL n’exclut absolument pas l’emploi simultané de feuilles de style CSS. Rien n’empêche en effet d’associer une feuille CSS à l’agrégat XHTML de manière à redéfinir globalement sa charte graphique. Les amateurs de chartes génériques et évolutives pourront également imaginer comment générer des feuilles de styles CSS dynamiquement en XSL…

Enfin, le risque de notre approche est que chaque portlet soit considérée comme un composant atomique, dont nous ne pouvons personnaliser la présentation. En réalité, XSL nous offre la même flexibilité que les langages de programmation Orientés Objet : il est tout à fait possible d’hériter d’une feuille de style XSL, de redéfinir certaines règles tout en conservant les autres intactes. La feuille fille peut bien entendu, lors de la redéfinition d’une règle, invoquer la règle équivalente de la feuille mère (l’équivalent du super() de java, ou du base() de C#).

Accès aux sources de données   

Jusqu’à présent, toutes les données dont nous avons parlé étaient à priori stockées dans des documents textuels XML. Rien n’empêche de charger ces informations depuis une base de données relationnelle, un annuaire LDAP (DSML aidant), ou tout autre type de source d’informations.

Le framework .NET nous facilite énormément la tâche sur cet aspect. Il permet de configurer :

La bonne nouvelle pour nous qui souhaitons obtenir des données au format XML est qu’un DataSet a deux facettes : certes, il peut charger ses données depuis n’importe quelle source (dont les bases de données relationnelles), mais il maintient également une représentation XML des informations ainsi chargées ! La structure d’un DataSet (qui peut contenir un ensemble de tables, colonnes et relations) est d’ailleurs décrite en XMLSchéma.

La démarche du développement de l’accès aux données est donc la suivante. Il faut tout d’abord, dans VisualStudio.NET, configurer la connexion à la source de données grâce à l’outil « Server explorer », ce qui se fait en deux étapes :

Puis nous ajoutons un DataSet au projet courant. Ceci nous amène à un environnement de conception d’une structure de données, sur lequel il suffit de glisser-déposer la table « Offres » de notre base de données. Immédiatement, VS.NET modifie le schéma du DataSet de manière à ce qu’il reflète la structure de la table Offres. Notez que le schéma d’un DataSet est manipulable graphiquement dans VS.NET, et qu’il est sauvegardé au format XMLSchéma :

 

 

Le DataSet doit être « chargé » à partir d’une source de données. Dans le cas d’une base de données relationnelle, il faut s’appuyer sur un objet de type « DataAdapter » qui déclenche une requête SQL sur la base de données, et copie les enregistrements résultants dans notre DataSet. Il suffit donc dans VS.NET de créer (graphiquement bien sûr) un DataAdapter en précisant :

Pour se faire une idée, voici les lignes de code C# générées par VS.NET et permettant de charger notre DataSet à partir de MSAccess :

(...)
oleDbConnection1 =
new OleDbConnection();
oleDbConnection1.ConnectionString = @"Provider=Data Source=OffresLocation.mdb;…"; 
oleDbSelectCommand1 =
new
OleDbCommand();
oleDbSelectCommand1.CommandText = @"SELECT Adresse, Charges, Description, Loyer, [N°], Surface, Type FROM Offres";
oleDbSelectCommand1.Connection = oleDbConnection1;
oleDbDataAdapter1 =
new OleDbDataAdapter();
oleDbDataAdapter1.SelectCommand = oleDbSelectCommand1;

OffresLocation données =
new OffresLocation();
oleDbDataAdapter1.Fill(données);
(...)

                              

Une fois le DataSet chargé, il nous faut récupérer ses données au format XML et leur appliquer une transformation ne pose aucun problème :

XPathDocument doc = new XpathDocument(new StringReader(données.GetXml()));
XslTransform trans =
new XslTransform();

trans.Load("feuille.xsl");
trans.Transform(doc,
null
, System.Console.Out);

Travailler sur des documents XML convient tout à fait en phase de mise au point du framework de présentation : il s’agit d’une sorte de bouchon (propre). Et comme nous venons de le voir, réaliser l’intégration du framework de présentation avec d’autres sources de données est assez simple (surtout si l’on s’appuie sur l’outillage fourni par VisualStudio.NET).

Gestion des requêtes utilisateur      

Bref rappel du mode de validation d’Apache Struts

Dans le monde Java, de nombreux développements d’applications Web se basent aujourd’hui sur le framework Apache Struts. Nous allons reprendre ici la philosophie de cet outil concernant la validation de surface des requêtes.

En deux mots :

 

 

Transposition en XSL

L’un des intérêts majeurs de XML est de pouvoir décrire très précisément des structures de données typées, et de pouvoir vérifier la validité d’un document par rapport à cette définition structurelle. Il est donc assez logique ici de traduire le modèle de validation d’Apache Struts en XML Schéma. Le synoptique (dans l’environnement .NET) devient le suivant :

 

 

La limite de notre système se trouve dans la partie applicative : « déclencher une action sur le système » (les « … » sur le diagramme précédent), qui sera probablement beaucoup plus simple à réaliser dans un langage de programmation traditionnel comme C# ou Java plutôt qu’en XSL.

Que manque-t-il à notre framework (pour aller plus loin) ?  

Navigation

Nous nous sommes inspirés de Apache Struts pour la validation de surface des requêtes utilisateur. Nous pouvons également reprendre l’approche de cet outil concernant la navigation : on peut tout à fait décrire en XML la navigation des utilisateurs dans notre application Web (le fichier correspondant dans le framework Struts s’appelle « struts-config.xml »).

Mais il faudrait aller un peu plus loin : en fonction des accréditations de nos utilisateurs, il serait intéressant de ne leur présenter que les zones du site auxquelles ils ont accès (certains liens hypertexte, certains portlets doivent disparaître si l’utilisateur n’a pas les droits nécessaires).

De même, si les utilisateur s’authentifient, on peut imaginer que l’on stocke leurs habitudes de navigation (en XML bien entendu), habitudes qu’il faut tracer au fur et à mesure de leur utilisation de notre système. Si notre base de connaissances concernant les utilisateurs est assez fine, rien ne nous empêche d’adapter l’interface aux habitudes de chaque utilisateur. Un exemple simple : dans la suite Office, les menus que vous n’utilisez pas fréquemment sont masqués (mais toujours disponibles). Nous pouvons faire de même dans une interface HTML (un hyperlien permettrait de « démasquer » les options disponibles que nous n’utilisons pas souvent).

Actions du système

En extrapolant un peu, le déclenchement des actions sur un système d’information peut également être décrit en XML. En effet, grâce aux WebServices, nous avons tous les langages nécessaires à :

Mais bien entendu, pour piloter les transformations XML, pour lancer les utilitaires basés sur XML, et pour transmettre les documents à travers un réseau, nous aurons toujours besoin de langages de programmation (C# ici) et de protocoles de communication (HTTP par exemple).

Multi-canal

Dans cet article, nous nous sommes attachés à la production de documents HTML. Langage XSL permettant de générer tout type de document, les mêmes principes peuvent être appliqués à la génération de documents XML (VoiceXML, SVG, X3D), ou de documents imprimables (PS, PDF, RTF…). Le framework que nous avons imaginé a donc tous les atouts pour gérer efficacement la diffusion « multi-canal » des informations et des services.

Conclusion                

XML et ses standards connexes sont d’excellents outils complémentaires des plate-formes .NET et J2EE. Ils permettent de développer des applications très flexibles, très modulaires, et qui plus est, portables sur n’importe quel environnement. Java est portable sur tous les OS, mais XML et XSL sont portables sur .NET, J2EE, Python, C… Nous gagnons donc un niveau d’abstraction, et pouvons parler, un peu pompeusement, de méta-framework.

Il faut toutefois tempérer notre enthousiasme concernant le framework imaginé par cet article, et ce pour plusieurs raisons :

Mais cette jeunesse ne doit pas vous empêcher suivre avec attention les évolutions des outils basés sur XML et XSL…

 

Auteur : Thomas GIL

Copyright : DotNetGuru Ó 2002