Initiation à XML et Delphi 6

TeamB-fr

Initiation à XML et Delphi 6 tout doucement, tout simplement…

- Titre : Initiation à XML et Delphi 6

- Auteur : TeamB-fr

- Parution : 23 mars 2002

- Mise à jour : 2 janvier 2020

- 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 ® 2013 TeamB-fr. 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. Introduction

- II. XML ?

- III. XML et Delphi 6

- IV. Un début à tout

- V. Créer la structure XML

- VI. L'expert Liaison de données

- VII. CONCLUSION

I - Introduction

XML par ci, XML par là, le futur est parmi nous… Le moins que l'on puisse dire, c'est que XML fait tapage dans le monde de l'informatique et qu'il fait bonne figure sur un CV.

Beaucoup de développements tournent aujourd'hui autour du web, des assistants de poche, des WAP et autres, il devenait nécessaire de définir une norme universelle de description des données, quelle que soit la plateforme cible. XML répond à cette exigence, en théorie du moins, car le phénomène a encore du chemin à parcourir sur la voie de la standardisation, les différents éditeurs intéressés n'ayant pas l'habitude de s'amouracher sur la question… :-)

II - XML ?

L'objectif n'est pas de refaire un cours sur XML d'autant que vous trouverez de quoi apprendre sur  xml.developpez.com . Mais il est toujours utile de proposer quelques rappels succincts.

XML n'a rien de révolutionnaire. XML est un langage qui permet de structurer des données à l'aide d'une norme de balisage, à l'instar du HTML. Cela permet aux applicatifs d'échanger des données, « formatées » XML. N'importe quel développeur peut en faire autant ceci dit, nul besoin de XML, il suffit de convenir d'un format entre le client et le serveur et d'interpréter en fonction.

L'intérêt de XML réside plutôt dans l'existence de bibliothèques qui implémentent les API standards d'XML (DOM, SAX, etc.) et ce sur de nombreuses plateformes. Même une technologie propriétaire comme Flash (de Macromédia) embarque un parseur XML. Du coup, il devient réellement intéressant de concevoir ses paquets de données au format XML, lorsqu'elles doivent être communiquées à un autre service ou système. Par exemple il était naturel pour tout Delphinaute d'utiliser les classes de Inifiles.pas pour gérer et structurer les fichiers *.ini. Nous allons garder le concept, mais « version Starwars »… avec XML. En général on extrait les données d'une base SQL, on les maquille XML et on les transmet. Mais attention, XML n'a pas vocation et ne peut pas remplacer une base SQL !!!

Avant de continuer, il est préférable que vous connaissiez les rudiments de XML, au moins le vocabulaire de base (« racine », « élément », « attribut », « nom », etc.).

Rappel :  xml.developpez.com

III - XML et Delphi 6

Nous verrons dans cet article comment créer, lire et parcourir un fichier XML grâce aux nouveaux composants et experts du nouveau-né  Delphi 6  (beau bébé !). Alors pour quel usage ? L'objectif est de créer un paquet de données organisées dans un format souple et reconnu par un maximum de plateformes (qui se chargeront ensuite de la mise en forme de ces données grâce à une lecture assistée via les bibliothèques XML des différents langages). XML est très souvent employé dans un mécanisme d'échange : les données pouvant être stockées physiquement dans un SGBD traditionnel, et converties en XML juste pour la transmission.

Exemples

Comme cité plus haut, on pourrait comparer un fichier INI à un fichier XML dans le cadre du stockage d'information : un fichier INI comporte des sections et des couples chaîne=valeur :

1. [SOCIETE]

2. NOM=4CENT AGENCY

3. [CONTACT]

4. NOM=JAMES Sylvain

5. ADRESSE=LA-BAS

6. EMAIL=sylvain.james@wanadoo.fr

Un fichier XML comporte des nœuds donc présente une structure arborescente, l'arborescence étant présentée par des indentations de lignes :

1. <Sylvain>

2. <Societe>4CENT AGENCY</Societe>

3. <Contact Nom="JAMES Sylvain" Adresse="LA-BAS" email="sylvain.james@wanadoo.fr"/> </Sylvain>

Un fichier XML conviendrait (pourquoi pas ?) pour stocker le registre de Windows, voire une image de l'explorateur de fichiers.

Sur le web, les fichiers XML sont très utilisés comme des conteneurs d'informations (Météo, News, Programmes télé, catalogues, etc.) sur lesquels viennent puiser quantité d'autres sites, qui ensuite ajoutent une couche de présentation (dans ce contexte, voir aussi du côté de SOAP).

On pourrait également utiliser la norme XML pour représenter le résultat d'une requête SQL (ce que font déjà certains SGBD comme Oracle ou SQLServer). Imaginons deux tables en relation maître détail, des participants à un stage par exemple.

Une requête comme :

1. SELECT stages.NOMSTAGE, stages.DATESTAGE, stagiaires.NOMSTAGIAIRE, stagiaires.AGESTAGIAIRE

2. FROM stages,stagiaires

3. WHERE stages.IDSTAGE = stagiaires.IDSTAGE

va retourner les données sous la forme suivante :

La représentation XML du même jeu de données sera la suivante :

1. <Stages>

2. <Stage Nom="WORD 2000 Initiation" Date="14/06/2001">

3. <Stagiaires>

4. <Stagiaire Nom="MAGIC Jordan" Age="35"/>

5. <Stagiaire Nom="ESSONCHA Jean-Roland" Age="38"/>

6. </Stagiaires>

7. </Stage>

8. <Stage Nom="SQL SERVER 7 Administration" Date="11/06/2001">

9. <Stagiaires>

10. <Stagiaire Nom="DERIEN Pepito" Age="26"/> </Stagiaires>

11. </Stage>

12. <Stage Nom="DELPHI 5 Perfectionnement" Date="01/06/2001">

13. <Stagiaires>

14. <Stagiaire Nom="SUSHI Okimi" Age="42"/>

15. </Stagiaires>

16. </Stage>

17. </Stages>

On n'ira pas dire qu'il y a économie d'espace avec le XML, mais la présentation des données est radicalement différente. Dans le cas de la requête SQL, la description des champs est fixe, mais les données se répètent pour chaque occurrence (NOMSTAGE, DATESTAGE).

Dans la représentation XML, les données ne se répètent pas, mais sont encadrées par leur description ce qui paraît plus souple. XML présente des données de façon arborescente en décrivant chaque élément et éventuellement ses attributs. Un élément représente une entité, comme <stagiaire> par exemple. Un attribut est comme une propriété d'un élément, « Age » est un attribut de <stagiaire>.

Il faut dire que le SQL n'est pas adapté lorsqu'il s'agit de définir des requêtes portant sur des données arborescentes. XML peut prendre le relai dans ces cas-là tout en gardant à l'esprit qu'en termes de performances, XML se révèlera nettement inférieur à un SGBD (ne succombez pas à la comparaison d'ailleurs, il n'y a pas lieu…).

Delphi 6 propose des outils pour « mapper » des données issues de Datasets (ClientDataSet, Query, Table ….) vers le format XML. Nous verrons cela dans un prochain topo, ici il s'agit de savoir comment construire un document XML à la mimine :

IV - Un début à tout

Jusque là, pas de quoi encenser XML. Mais XML et ses frangins comportent aussi des outils qui offrent la possibilité de lire et naviguer dans un document XML, l'intérêt est là. Si vous avez déjà entendu parler des parsers DOM et SAX, alors vous brûlez.

Ces parsers sont des outils implémentant des API standardisées (et/ou en cours de…) qui offrent des interfaces permettant de parcourir, de rechercher et d'éditer facilement une information au sein d'un document XML. Nous nous appuierons sur l'API standard DOM (Document Object Model) via l'implémentation de Microsoft dans msxml.dll (cette lib doit être enregistrée comme serveur COM au moyen de Regsvr32.exe) si elle ne l'est pas encore (rare, car installé avec IE).

C'est l'unité  XMLDOM.pas  qui décrit les interfaces implémentées dans les bibliothèques DOM selon les spécifications du W3C. Pour nous, le point de départ se situera avec le composant  XMLDocument  : palette de composants, onglet Internet :

Posez un composant XMLDocument sur une form vierge. Nommez-le XMLDoc (propriété Name). Sans rentrer dans les détails, paramétrez les propriétés de ce petit nouveau selon le screenshot suivant :

Les propriétés essentielles :

- DOMVendor  qui permet de spécifier la bibliothèque responsable de l'implémentation DOM

et si vous voulez travailler avec un document XML existant :

- XML  qui est une liste de chaînes stockant le document XML. À savoir que l'on n'est pas obligé d'affecter une liste de chaînes à la propriété XML, on peut également assigner un nom de fichier à la propriété FileName.

- Active  qui lorsqu'elle est à True permet au composant XMLDocument de créer et/ou parcourir l'arborescence des nœuds du document XML respectif. Tout document XML commence par <?xml version=« 1.0 » encoding=« UTF-8 »?> l'encodage pouvant varier. Le simple fait de passer la propriété Active à true sur un document XML vierge, va ajouter cette ligne descriptive.

V - Créer la structure XML

Le composant XMLDocument comporte une propriété  DocumentElement  de type  IXMLNode  comme chaque nœud de l'arborescence. DocumentElement a la particularité cependant d'être la racine (le root) de l'arborescence. Si on reprend notre exemple de document XML sur les Stages/Stagiaires, le root correspond au nœud <stages>. Le document doit comporter obligatoirement un root.

Nous allons créer un nœud (IXMLNode) et l'affecter à la propriété DocumentElement. Ce nœud sera le point de départ, la référence à partir de laquelle nous allons créer les autres nœuds, les nœuds enfants.

Rappel technique

IXMLNode est une classe d'interface et non une classe d'objet. À ce titre, sa fonction est de présenter une liste de méthodes, mais sans leur implémentation. Cette charge revient aux classes gérant les interfaces (le plus souvent héritées de TInterfacedObject). Une même classe peut implémenter plusieurs interfaces. Les classes XML n'échappent pas à la règle.

Par exemple la classe TXMLNode implémente - entre autres - l'interface IXMLNode. :

TXMLNode = class(TInterfacedObject, IXMLNode, IXMLNodeAccess)

Une variable peut être déclarée de type interface (comme IXMLNode), mais doit être instanciée avec une classe objet implémentant cette interface (comme la classe TXMLNode).

Placez un bouton et un memo sur la form, nommez-le btnCreation et implémentez son gestionnaire OnClick de la façon suivante :

1. procedure TForm1.btnCreationClick(Sender: TObject); var stage,stagiaires,stagiaire : IXMLNode; //Noeuds de référence begin memo1.Clear; //Création du premier noeud 'stages' et initialisation de DocumentElement XMLDoc.DocumentElement := XMLDoc.CreateElement('stages',''); //Création du premier noeud enfant, représentant le premier stage stage := XMLDoc.DocumentElement.AddChild('stage'); //Création des attributs de ce stage stage.Attributes['nom'] := 'WORD 2000 Initiation'; stage.Attributes['date'] := '14/06/2001'; //Création du noeud enfant de ce stage : stagiaires stagiaires := stage.AddChild('stagiaires'); //Création de chaque stagiaire stagiaire := stagiaires.AddChild('stagiaire'); stagiaire.Attributes['nom'] := 'MAGIC Jordan'; stagiaire.Attributes['age'] := '35'; //2è stagiaire stagiaire := stagiaires.AddChild('stagiaire'); stagiaire.Attributes['nom'] := 'ESSONCHA Jean-Roland'; stagiaire.Attributes['age'] := '38'; //Stage suivant stage := XMLDoc.DocumentElement.AddChild('stage'); //Création des attributs de ce stage stage.Attributes['nom'] := 'SQL SERVER 7 Administration'; stage.Attributes['date'] := '11/06/2001'; //et ainsi de suite //...à la fin on peut visualiser le résultat ! Simplissimo :-) memo1.Lines.Assign(XMLDoc.XML); end;

À cette étape, avec deux méthodes et une propriété, nous avons créé un document XML représentant une liste hiérarchisée de stages et leurs stagiaires respectifs. Il est aisé de compléter le code ci-dessus avec une interface proposant des champs d'édition et des boutons pour ajouter un stage ou un stagiaire.

- La fonction CreateElement renvoie le nœud de type IXMLNode qui est créé.

- La fonction AddChild retourne également le nœud IXMLNode qui est créé, mais il est créé à partir d'un autre nœud et non du document. Le nœud créé devient enfant du nœud qui a appelé cette fonction.

- La propriété Attributes permet de « mapper » un mot clé et de lui attribuer une valeur. Attributes ici s'applique à un nœud désigné.

Pour terminer cette première partie, enregistrez ce document XML dans le dossier de votre choix en appelant la méthode SaveToFile de l'objet XMLDocument :

1. XMLDoc.SaveToFile('stages.xml');

Pour un premier aperçu, vous pouvez relire ce document XML à l'aide de votre navigateur Web, vous verrez que ce dernier sait « présenter » le document avec une arborescence conforme à votre description.

VI - L'expert Liaison de données

Continuons notre exploration XML et Delphi 6 et voyons à présent l'expert [ Liaison de données XML ] et la navigation dans une structure XML :

Nous souhaitons lire un fichier XML existant. Delphi 6 propose un  expert saisissant  qui analyse la structure d'un document XML et crée des types interface qui « mappent » les éléments et attributs du document. Il suffit ensuite d'inclure la déclaration de ces types dans vos unités Delphi, et la magie opère…

Exemple, cliquez sur l'icône Nouveau et sélectionnez l'icône XML Data Binding :

Cet expert va ensuite vous demander quel fichier XML il doit analyser. Modifiez le type de fichiers de façon à ce que les *.xml soient filtrés puis spécifiez le chemin et le nom du fichier XML (on va prendre un exemple fourni avec Delphi : Delphi6\Demos\WebSnap\XSLProducer\recipes.xml ) et cliquez sur Suivant. Nous obtenons l'écran suivant

Ce document XML décrit une recette de cuisine, avec les ingrédients et les instructions.

Chaque nœud de l'arborescence a été mappé avec un type dédié et hérité des interfaces standard DOM. Vous pouvez cliquer sur chaque nœud et modifier les paramétrages respectifs. Ici nous laisserons la génération de l'assistant intacte. L'étape suivante permet de visualiser l'interface du code généré. Ensuite, cliquez sur le bouton Terminer.

Dès lors, une unité est générée. Tous les types nécessaires à la lecture du fichier XML sous-jacent sont déclarés et implémentent les interfaces IXMLNode et IXMLNodeCollection selon que les nœuds contiennent des éléments qui se répètent (stagiaires) ou non (stagiaire).
Trois méthodes utilitaires sont également déclarées et implémentées :

1. function GetRecipe(Doc: IXMLDocument): IXMLRecipeType;

2. function LoadRecipe(const FileName: WideString): IXMLRecipeType;

3. function NewRecipe: IXMLRecipeType;

GetRecipe  permet de linker le composant XMLDocument à la structure analysée, en gros d'initialiser la racine du document en instanciant une variable de type  IXMLRecipeType .
LoadRecipe  permet de charger un fichier existant.
NewRecipe  offre la possibilité de partir de zéro.

Dans les trois cas, nous obtenons en retour de fonction une variable de type IXMLRecipeType qui va être notre point de départ pour naviguer dans l'arborescence des données.

Voici un extrait de l'interface générée :

1. ...

2. { IXMLRecipeType }

3. IXMLRecipeType = interface(IXMLNode) ['{F93E8345-8F0D-472A-B9A3-17F365247A42}'] { Accesseurs de propriétés }

4. function Get_Name: WideString;

5. function Get_Description: WideString;

6. function Get_Ingredients: IXMLIngredientsType;

7. function Get_Instructions: IXMLInstructionsType;

8. procedure Set_Name(Value: WideString);

9. procedure Set_Description(Value: WideString);

10. { Méthodes & propriétés }

11. property Name: WideString read Get_Name write Set_Name;

12. property Description: WideString read Get_Description write Set_Description;

13. property Ingredients: IXMLIngredientsType read Get_Ingredients;

14. property Instructions: IXMLInstructionsType read Get_Instructions; end; { IXMLIngredientsType } IXMLIngredientsType = interface(IXMLNodeCollection) ['{BAB79B24-ED85-4141-B3C9-A36729D1FEA8}'] { Accesseurs de propriétés }

15. function Get_Ingredient(Index: Integer): IXMLIngredientType; { Méthodes & propriétés } function Add: IXMLIngredientType;

16. function Insert(const Index: Integer): IXMLIngredientType;

17. property Ingredient[Index: Integer]: IXMLIngredientType read Get_Ingredient; default; end; ...

Enregistrons cette unité et ajoutons-la dans les uses de notre application de départ et déclarons une variable de type IXMLRecipeType :

1. var recette : IXMLRecipeType; begin // Initialisons cette variable grâce à la fonction GetRecipe générée par l'expert recette := GetRecipe(XMLDoc);

Maintenant, la variable  recette est notre point de départ. Elle a été interfacée par l'assistant de façon à nous faciliter le plus possible son utilisation.
Après avoir chargé le fichier 'recipe.xml' dans le composant XMLDoc via la propriété FileName.

Essayez ceci dans un gestionnaire OnClick d'un bouton quelconque (prévoyez également un TMemo pour logger les messages).

1. var recette : IXMLRecipeType;

2. i: integer; begin recette := GetRecipe(XMLDoc);

3. for i := 0 to recette.Ingredients.Count - 1 do memo2.Lines.Add(recette.Ingredients[i].Item);

4. end;

ou alors :

1. memo2.Lines.Add(recette.Name); //... memo2.Lines.Add(recette.Ingredients[i].Qty[0].Attributes['unit']);

Ce dernier exemple montre que dans l'expert, on aurait dû décocher la coche [ Répéter ] pour l'attribut  Qty  (cf. schéma ci-dessous), car il s'agit d'un attribut seul et non d'une liste de même attribut dans le document recipe.xml. À vous de le préciser dans l'assistant, car ce dernier peut difficilement le deviner.
Il suffit d'effectuer un double clic sur le composant XMLDocument pour faire apparaître l'expert Liaison de données XML et cette fois-ci, nous sélectionnons le nœud  Qty  et décochons la case Répéter :

Vous générez à nouveau l'unité, et par rapport à l'unité générée, vous pourrez cette fois coder de la façon suivante :

- memo2.Lines.Add(recette.Ingredients[i].Qty.Attributes['unit']);  // au lieu de …

- memo2.Lines.Add(recette.Ingredients[i].Qty[0].Attributes['unit']);

car Qty implémentera IXMLNode et non IXMLNodeCollection .

VII - CONCLUSION

Bref, vous avez là un outil fantastique pour générer vos templates XML et il serait franchement dommage de passer à côté.
Nous n'avons fait que survoler ce que Delphi 6 nous apportait en termes de développement XML, il reste encore des découvertes intéressantes comme le XML Mapper, outil de transformation des données d'un Dataset vers XML et vice versa et bien d'autres choses encore.
J'y reviendrai bientôt, et en accumulant ce savoir-faire, nous serons à même d'utiliser XML à bon escient.
Pensez à votre CV… :-)))

Sylvain James
Développeur / Formateur

Livre recommandé  :  XML et les bases de données / Wrox édition Eyrolles

Liste de mes articles :

XMLRAD

XMLRAD : Création d'un modèle de page personnalisée

XMLRAD : Importer des flux RSS avec XMLRAD

XMLRAD : Composant XSL d'autocomplétion avec la YahooUI Lib

DELPHI

Communication Inter Process : Les Mailslots - en Delphi

Concepteurs de composants, simplifiez leur installation

Conférence Borland 2000

Conversions de mesures

Création d'un modèle de page personnalisée

Débogage de DLL ISAPI

Gérez les Compteurs AutoIncrémentés avec InterBase

Gestion des versions par héritage de Form

Initiation à XML et Delphi 6 tout doucement, tout simplement…

Objets Listes, collections en Delphi

Traiter des fichiers de grande taille