XML Tutorial/fr: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: XML Tutorial/fr
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## Introduction | |
| 2 | + | ||
| 3 | + | Le langage de balises extensible (*eXtensible Markup Language*) est un langage recommandé par le [W3C](http://www.w3.org/) créé pour l'échange d'informations entre différents systèmes. Il propose le stockage d'informations sous forme de texte. Les langages modernes d'échanges de données comme le XHTML, tout comme la plupart des technologies WebServices, sont fondés sur le XML. | |
| 4 | + | ||
| 5 | + | Il existe actuellement un ensemble d'unités qui offrent le support du XML à Free Pascal. Ces unités appelées *XMLRead*, *XMLWrite* et *DOM* font partie de la *Free Component Library* (FCL) du compilateur Free Pascal. La FCL est déjà sur le chemin de recherche par défaut du compilateur de Lazarus : vous n'avez donc qu'à ajouter ces unités à votre clause *uses* pour obtenir l'accès au XML. La FCL n'étant que partiellement documentée à ce jour (mai 2015), ce petit tutoriel vise à introduire l'utilisation minimale du XML en utilisant ces unités. | |
| 6 | + | ||
| 7 | + | Le DOM XML (*Document Object Model*) est un ensemble d'objets standardisés offrant une interface similaire pour l'utilisation du XML avec différents langages et systèmes. Le standard spécifie uniquement les méthodes, propriétés et autres parties d'interface de l'objet, laissant l'implémentation libre pour les différents langages. La FCL supporte totalement le [XML DOM 2.0](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/) et un sous-ensemble du [XML DOM 3.0](http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/) détaillé [[dom|ici]]. | |
| 8 | + | ||
| 9 | + | ## Exemples | |
| 10 | + | ||
| 11 | + | Ci-dessous figure une série d'exemples de manipulations de données XML dont la complexité va en croissant. | |
| 12 | + | ||
| 13 | + | ## Unités dans la clause *uses* : Unicode ou Ansi | |
| 14 | + | ||
| 15 | + | FPC est accompagné d'unités XML fondées sur des routines dont le codage correspond à la norme ANSI si bien que les résultats sur différentes plateformes peuvent ne pas être homogènes et en particulier non Unicode. Lazarus fournit un ensemble complémentaire d'unités XML avec le paquet *LazUtils* qui supporte totalement le codage Unicode UTF-8 pour toutes les plateformes. Toutes ces unités sont compatibles : pour passer de l'une à l'autre, il suffit d'adapter la clause *uses* en conséquence. | |
| 16 | + | ||
| 17 | + | Les unités proposées par FPC pour le traitement du XML sont (chaînes encodées selon l'encodage du système) : | |
| 18 | + | ||
| 19 | + | ` `*`DOM`*\ | |
| 20 | + | ` `*`XMLRead`*\ | |
| 21 | + | ` `*`XMLWrite`*\ | |
| 22 | + | ` `*`XMLCfg`*\ | |
| 23 | + | ` `*`XMLUtils`*\ | |
| 24 | + | ` `*`XMLStreaming`*` ` | |
| 25 | + | ||
| 26 | + | Les unités proposées par Lazarus pour le traitement du XML sont (chaînes avec support de l'Unicode UTF-8 sur toutes les plateformes) : | |
| 27 | + | ||
| 28 | + | ` `*`laz2_DOM`*\ | |
| 29 | + | ` `*`laz2_XMLRead`*\ | |
| 30 | + | ` `*`laz2_XMLWrite`*\ | |
| 31 | + | ` `*`laz2_XMLCfg`*\ | |
| 32 | + | ` `*`laz2_XMLUtils`*\ | |
| 33 | + | ` `*`laz_XMLStreaming`*` ` | |
| 34 | + | ||
| 35 | + | Toutes ces unités ne sont pas nécessaires pour chacun des exemples qui suivent. Vous aurez toutefois toujours besoin de l'unité *DOM* (ou *laz2_DOM*) dans la mesure où elle définit plusieurs types dont *TXMLDocument*. | |
| 36 | + | ||
| 37 | + | ### Lire un nœud de texte | |
| 38 | + | ||
| 39 | + | Pour les programmeurs Delphi : notez que lorsque vous travaillez avec *TXMLDocument*, le texte à l'intérieur d'un nœud est considéré comme un nœud de texte séparé. Vous devez donc accéder à une valeur texte d'un nœud comme à un nœud séparé. | |
| 40 | + | ||
| 41 | + | Par exemple, considérez le XML suivant : | |
| 42 | + | ||
| 43 | + | ``` xml | |
| 44 | + | <?xml version="1.0"?> | |
| 45 | + | <request> | |
| 46 | + | <request_type>PUT_FILE</request_type> | |
| 47 | + | <username>123</username> | |
| 48 | + | <password>abc</password> | |
| 49 | + | </request> | |
| 50 | + | ``` | |
| 51 | + | ||
| 52 | + | L'exemple de code suivant montre la bonne et la mauvaise façon d'obtenir la valeur du texte du nœud : | |
| 53 | + | ||
| 54 | + | ``` pascal | |
| 55 | + | var | |
| 56 | + | PassNode: TDOMNode; | |
| 57 | + | Doc: TXMLDocument; | |
| 58 | + | begin | |
| 59 | + | // Lit le fichier xml depuis le disque | |
| 60 | + | ReadXMLFile(Doc, 'c:\xmlfiles\test.xml'); | |
| 61 | + | // Récupère le nœud "password" | |
| 62 | + | PassNode := Doc.DocumentElement.FindNode('password'); | |
| 63 | + | // Ecrit la valeur du nœud sélectionné | |
| 64 | + | WriteLn(PassNode.NodeValue); // ce sera vide | |
| 65 | + | // Le texte du nœud est réellement un nœud enfant distinct | |
| 66 | + | WriteLn(PassNode.FirstChild.NodeValue); // affiche correctement "abc" | |
| 67 | + | ``` | |
| 68 | + | ||
| 69 | + | ### Afficher les noms des nœuds | |
| 70 | + | ||
| 71 | + | L'exemple suivant montre comment afficher les noms des nœud dans un *TMemo* placé sur une fiche. | |
| 72 | + | ||
| 73 | + | Ci-dessous le fichier XML appelé 'C:\Programs\test.xml' : | |
| 74 | + | ||
| 75 | + | ``` xml | |
| 76 | + | <?xml version="1.0"?> | |
| 77 | + | <images directory="mydir"> | |
| 78 | + | <imageNode URL="graphic.jpg" title=""> | |
| 79 | + | <Peca DestinoX="0" DestinoY="0">Pecacastelo.jpg1.swf</Peca> | |
| 80 | + | <Peca DestinoX="0" DestinoY="86">Pecacastelo.jpg2.swf</Peca> | |
| 81 | + | </imageNode> | |
| 82 | + | </images> | |
| 83 | + | ``` | |
| 84 | + | ||
| 85 | + | Et ci-après le code Pascal pour exécuter la tâche : | |
| 86 | + | ||
| 87 | + | ``` pascal | |
| 88 | + | var | |
| 89 | + | Document: TXMLDocument; | |
| 90 | + | i, j: Integer; | |
| 91 | + | begin | |
| 92 | + | ReadXMLFile(Document, 'C:\Programs\test.xml'); | |
| 93 | + | Memo.Lines.Clear; | |
| 94 | + | with Document.DocumentElement.ChildNodes do | |
| 95 | + | begin | |
| 96 | + | for i := 0 to (Count - 1) do | |
| 97 | + | begin | |
| 98 | + | Memo.Lines.Add(Item[i].NodeName + ' ' + Item[i].Attributes.Item[0].NodeValue); | |
| 99 | + | for j := 0 to (Item[i].ChildNodes.Count - 1) do | |
| 100 | + | begin | |
| 101 | + | Memo.Lines.Add(Item[i].ChildNodes.Item[j].NodeName + ' ' | |
| 102 | + | + Item[i].ChildNodes.Item[j].FirstChild.NodeValue); | |
| 103 | + | end; | |
| 104 | + | end; | |
| 105 | + | end; | |
| 106 | + | Document.Free; | |
| 107 | + | end; | |
| 108 | + | ``` | |
| 109 | + | ||
| 110 | + | Ce qui affichera: | |
| 111 | + | ||
| 112 | + | imageNode graphic.jpg | |
| 113 | + | Peca Pecacastelo.jpg1.swf | |
| 114 | + | Peca Pecacastelo.jpg1.swf | |
| 115 | + | ||
| 116 | + | ### Peupler un TreeView avec XML | |
| 117 | + | ||
| 118 | + | Une utilisation courante des fichers XML est de les analyser et d'afficher leur contenu sous forme d'arborescence. Pour ce faire, vous pouvez utiliser le composant *TTreeView* présent sous l'onglet *Common Controls* de Lazarus. | |
| 119 | + | ||
| 120 | + | La procédure ci-dessous va prendre un document XML précédemment chargé depuis un fichier ou généré par code, avant de peupler un *TreeView* avec son contenu. La légende de chaque nœud de l'arbre sera le contenu du premier attribut de chaque nœud du document XML. | |
| 121 | + | ||
| 122 | + | ``` pascal | |
| 123 | + | procedure TForm1.XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument); | |
| 124 | + | var | |
| 125 | + | iNode: TDOMNode; | |
| 126 | + | ||
| 127 | + | procedure ProcessNode(Node: TDOMNode; TreeNode: TTreeNode); | |
| 128 | + | var | |
| 129 | + | cNode: TDOMNode; | |
| 130 | + | s: string; | |
| 131 | + | begin | |
| 132 | + | if Node = nil then Exit; // Stoppe si on a atteint une feuille | |
| 133 | + | ||
| 134 | + | // Ajoute un nœud à l'arbre s'il existe | |
| 135 | + | if Node.HasAttributes and (Node.Attributes.Length>0) then | |
| 136 | + | s := Node.Attributes[0].NodeValue | |
| 137 | + | else | |
| 138 | + | s := ''; | |
| 139 | + | TreeNode := tree.Items.AddChild(TreeNode, s); | |
| 140 | + | ||
| 141 | + | ||
| 142 | + | // Va au nœud enfant | |
| 143 | + | cNode := Node.ChildNodes.Item[0]; | |
| 144 | + | ||
| 145 | + | // Traite tous les nœuds enfants | |
| 146 | + | while cNode <> nil do | |
| 147 | + | begin | |
| 148 | + | ProcessNoDe(cNode, TreeNode); | |
| 149 | + | cNode := cNode.NextSibling; | |
| 150 | + | end; | |
| 151 | + | end; | |
| 152 | + | ||
| 153 | + | begin | |
| 154 | + | iNode := XMLDoc.DocumentElement.ChildNodes.Item[0]; | |
| 155 | + | while iNode <> nil do | |
| 156 | + | begin | |
| 157 | + | ProcessNode(iNode, nil); // Procédure récursive | |
| 158 | + | iNode := iNode.NextSibling; | |
| 159 | + | end; | |
| 160 | + | end; | |
| 161 | + | ``` | |
| 162 | + | ||
| 163 | + | ### Modifier un document XML | |
| 164 | + | ||
| 165 | + | La première chose à se rappeler est que *TDOMDocument* est le "handle" vers le *DOM*. Vous pouvez obtenir une instance de cette classe en créant ou en chargeant un document XML. | |
| 166 | + | ||
| 167 | + | D'un autre côté, les nœuds ne peuvent être créés comme des objets classiques. Vous *devez* utiliser les méthodes mises à disposition par *TDOMDocument* pour les créer puis utiliser d'autres méthodes pour les placer correctement dans l'arbre. Cela est dû au fait que les nœuds doivent être "possédés" par un document spécifique du *DOM*. | |
| 168 | + | ||
| 169 | + | Ci-dessous sont indiquées quelques méthodes particulièrement utiles de *TDOMDocument* : | |
| 170 | + | ||
| 171 | + | ``` pascal | |
| 172 | + | function CreateElement(const tagName: DOMString): TDOMElement; virtual; | |
| 173 | + | function CreateTextNode(const data: DOMString): TDOMText; | |
| 174 | + | function CreateCDATASection(const data: DOMString): TDOMCDATASection; | |
| 175 | + | virtual; | |
| 176 | + | function CreateAttribute(const name: DOMString): TDOMAttr; virtual; | |
| 177 | + | ``` | |
| 178 | + | ||
| 179 | + | *CreateElement* crée un nouvel élément. | |
| 180 | + | ||
| 181 | + | *CreateTextNode* crée un noeud texte. | |
| 182 | + | ||
| 183 | + | *CreateAttribute* crée un noeud attribut. | |
| 184 | + | ||
| 185 | + | *CreateCDATASection* crée une section *CDATA* : les caractères de marquage particuliers à XML tels que \<\> ne sont pas intrepréts au sein d'une section *CDATA*. | |
| 186 | + | ||
| 187 | + | Une façon plus facile de manipuler les attributs consiste à utiliser la méthode *TDOMElement.SetAttribute* (elle est par ailleurs la propriété par défaut de *TDOMElement*) : | |
| 188 | + | ||
| 189 | + | ``` pascal | |
| 190 | + | // these two statements are equivalent | |
| 191 | + | Element.SetAttribute('name', 'value'); | |
| 192 | + | Element['name'] := 'value'; | |
| 193 | + | ``` | |
| 194 | + | ||
| 195 | + | Et ci-après un exemple de méthode qui localise l'élément sélectionné dans un *TTreeView* avant d'insérer un nœud enfant au document XML qu'il représente. Le *TreeView* doit être précédement rempli avec le contenu du fichier XML en utilisant la [[XML Tutorial|fonction XML2Tree]]. | |
| 196 | + | ||
| 197 | + | ``` pascal | |
| 198 | + | procedure TForm1.actAddChildNode(Sender: TObject); | |
| 199 | + | var | |
| 200 | + | Posicao: Integer; | |
| 201 | + | NovoNo: TDomNode; | |
| 202 | + | begin | |
| 203 | + | {******************************************************************* | |
| 204 | + | * Détection de l'élément sélectionné | |
| 205 | + | *******************************************************************} | |
| 206 | + | if TreeView1.Selected = nil then Exit; | |
| 207 | + | ||
| 208 | + | if TreeView1.Selected.Level = 0 then | |
| 209 | + | begin | |
| 210 | + | Posicao := TreeView1.Selected.Index; | |
| 211 | + | ||
| 212 | + | NovoNo := XMLDoc.CreateElement('item'); | |
| 213 | + | TDOMElement(NovoNo).SetAttribute('nome', 'Item'); | |
| 214 | + | TDOMElement(NovoNo).SetAttribute('arquivo', 'Arquivo'); | |
| 215 | + | XMLDoc.DocumentElement.ChildNodes.Item[Posicao].AppendChild(NovoNo); | |
| 216 | + | ||
| 217 | + | {******************************************************************* | |
| 218 | + | * Mise à jour du TreeView | |
| 219 | + | *******************************************************************} | |
| 220 | + | TreeView1.Items.Clear; | |
| 221 | + | XML2Tree(TreeView1, XMLDoc); | |
| 222 | + | end | |
| 223 | + | else if TreeView1.Selected.Level >= 1 then | |
| 224 | + | begin | |
| 225 | + | {******************************************************************* | |
| 226 | + | * Cette fonction n'est opérante qu'au premier niveau de l'arbre, | |
| 227 | + | * mais peut facilement être modifiée pour fonctionner avec plusieurs niveaux | |
| 228 | + | *******************************************************************} | |
| 229 | + | end; | |
| 230 | + | end; | |
| 231 | + | ``` | |
| 232 | + | ||
| 233 | + | ### Créer un TXMLDocument à partir d'une chaîne | |
| 234 | + | ||
| 235 | + | Étant donné un fichier XML dans *MyXmlString*, le code suivant va créer son *DOM* : | |
| 236 | + | ||
| 237 | + | ``` pascal | |
| 238 | + | Var | |
| 239 | + | S : TStringStream; | |
| 240 | + | XML : TXMLDocument; | |
| 241 | + | ||
| 242 | + | begin | |
| 243 | + | S:= TStringStream.Create(MyXMLString); | |
| 244 | + | Try | |
| 245 | + | S.Position:=0; | |
| 246 | + | XML:=Nil; | |
| 247 | + | ReadXMLFile(XML,S); // Document XML complet | |
| 248 | + | // Autre possibilité | |
| 249 | + | ReadXMLFragment(AParentNode,S); // Lit uniquement un fragment XML. | |
| 250 | + | Finally | |
| 251 | + | S.Free; | |
| 252 | + | end; | |
| 253 | + | end; | |
| 254 | + | ``` | |
| 255 | + | ||
| 256 | + | ## Liens Externes | |
| 257 | + | ||
| 258 | + | - [W3Schools](http://www.w3schools.com/xml/default.asp) Tutoriel XML | |
| 259 | + | ||
| 260 | + | - [Thomas Zastrow article](http://www.thomas-zastrow.de/texte/fpcxml/index.php) FPC et XML | |
| 261 | + | ||
| 262 | + | --- | |
| 263 | + | *From the Free Pascal wiki, page "XML Tutorial/fr", as it stood on 2020-03-02 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
