XML Tutorial/fr
│
Deutsch (de) │
English (en) │
español (es) │
français (fr) │
magyar (hu) │
Bahasa Indonesia (id) │
italiano (it) │
日本語 (ja) │
한국어 (ko) │
português (pt) │
русский (ru) │
中文(中国大陆) (zh_CN) │
Introduction
Le langage de balises extensible (eXtensible Markup Language) est un langage recommandé par le W3C 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.
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.
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 et un sous-ensemble du XML DOM 3.0 détaillé ici.
Exemples
Ci-dessous figure une série d'exemples de manipulations de données XML dont la complexité va en croissant.
Unités dans la clause uses : Unicode ou Ansi
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.
Les unités proposées par FPC pour le traitement du XML sont (chaînes encodées selon l'encodage du système) :
DOM XMLRead XMLWrite XMLCfg XMLUtils XMLStreaming
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) :
laz2_DOM laz2_XMLRead laz2_XMLWrite laz2_XMLCfg laz2_XMLUtils laz_XMLStreaming
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.
Lire un nœud de texte
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é.
Par exemple, considérez le XML suivant :
<?xml version="1.0"?>
<request>
<request_type>PUT_FILE</request_type>
<username>123</username>
<password>abc</password>
</request>
L'exemple de code suivant montre la bonne et la mauvaise façon d'obtenir la valeur du texte du nœud :
var
PassNode: TDOMNode;
Doc: TXMLDocument;
begin
// Lit le fichier xml depuis le disque
ReadXMLFile(Doc, 'c:\xmlfiles\test.xml');
// Récupère le nœud "password"
PassNode := Doc.DocumentElement.FindNode('password');
// Ecrit la valeur du nœud sélectionné
WriteLn(PassNode.NodeValue); // ce sera vide
// Le texte du nœud est réellement un nœud enfant distinct
WriteLn(PassNode.FirstChild.NodeValue); // affiche correctement "abc"
Afficher les noms des nœuds
L'exemple suivant montre comment afficher les noms des nœud dans un TMemo placé sur une fiche.
Ci-dessous le fichier XML appelé 'C:\Programs\test.xml' :
<?xml version="1.0"?>
<images directory="mydir">
<imageNode URL="graphic.jpg" title="">
<Peca DestinoX="0" DestinoY="0">Pecacastelo.jpg1.swf</Peca>
<Peca DestinoX="0" DestinoY="86">Pecacastelo.jpg2.swf</Peca>
</imageNode>
</images>
Et ci-après le code Pascal pour exécuter la tâche :
var
Document: TXMLDocument;
i, j: Integer;
begin
ReadXMLFile(Document, 'C:\Programs\test.xml');
Memo.Lines.Clear;
with Document.DocumentElement.ChildNodes do
begin
for i := 0 to (Count - 1) do
begin
Memo.Lines.Add(Item[i].NodeName + ' ' + Item[i].Attributes.Item[0].NodeValue);
for j := 0 to (Item[i].ChildNodes.Count - 1) do
begin
Memo.Lines.Add(Item[i].ChildNodes.Item[j].NodeName + ' '
+ Item[i].ChildNodes.Item[j].FirstChild.NodeValue);
end;
end;
end;
Document.Free;
end;
Ce qui affichera:
imageNode graphic.jpg Peca Pecacastelo.jpg1.swf Peca Pecacastelo.jpg1.swf
Peupler un TreeView avec XML
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.
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.
procedure TForm1.XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument);
var
iNode: TDOMNode;
procedure ProcessNode(Node: TDOMNode; TreeNode: TTreeNode);
var
cNode: TDOMNode;
s: string;
begin
if Node = nil then Exit; // Stoppe si on a atteint une feuille
// Ajoute un nœud à l'arbre s'il existe
if Node.HasAttributes and (Node.Attributes.Length>0) then
s := Node.Attributes[0].NodeValue
else
s := '';
TreeNode := tree.Items.AddChild(TreeNode, s);
// Va au nœud enfant
cNode := Node.ChildNodes.Item[0];
// Traite tous les nœuds enfants
while cNode <> nil do
begin
ProcessNoDe(cNode, TreeNode);
cNode := cNode.NextSibling;
end;
end;
begin
iNode := XMLDoc.DocumentElement.ChildNodes.Item[0];
while iNode <> nil do
begin
ProcessNode(iNode, nil); // Procédure récursive
iNode := iNode.NextSibling;
end;
end;
Modifier un document XML
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.
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.
Ci-dessous sont indiquées quelques méthodes particulièrement utiles de TDOMDocument :
function CreateElement(const tagName: DOMString): TDOMElement; virtual;
function CreateTextNode(const data: DOMString): TDOMText;
function CreateCDATASection(const data: DOMString): TDOMCDATASection;
virtual;
function CreateAttribute(const name: DOMString): TDOMAttr; virtual;
CreateElement crée un nouvel élément.
CreateTextNode crée un noeud texte.
CreateAttribute crée un noeud attribut.
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.
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) :
// these two statements are equivalent
Element.SetAttribute('name', 'value');
Element['name'] := 'value';
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 fonction XML2Tree.
procedure TForm1.actAddChildNode(Sender: TObject);
var
Posicao: Integer;
NovoNo: TDomNode;
begin
{*******************************************************************
* Détection de l'élément sélectionné
*******************************************************************}
if TreeView1.Selected = nil then Exit;
if TreeView1.Selected.Level = 0 then
begin
Posicao := TreeView1.Selected.Index;
NovoNo := XMLDoc.CreateElement('item');
TDOMElement(NovoNo).SetAttribute('nome', 'Item');
TDOMElement(NovoNo).SetAttribute('arquivo', 'Arquivo');
XMLDoc.DocumentElement.ChildNodes.Item[Posicao].AppendChild(NovoNo);
{*******************************************************************
* Mise à jour du TreeView
*******************************************************************}
TreeView1.Items.Clear;
XML2Tree(TreeView1, XMLDoc);
end
else if TreeView1.Selected.Level >= 1 then
begin
{*******************************************************************
* Cette fonction n'est opérante qu'au premier niveau de l'arbre,
* mais peut facilement être modifiée pour fonctionner avec plusieurs niveaux
*******************************************************************}
end;
end;
Créer un TXMLDocument à partir d'une chaîne
Étant donné un fichier XML dans MyXmlString, le code suivant va créer son DOM :
Var
S : TStringStream;
XML : TXMLDocument;
begin
S:= TStringStream.Create(MyXMLString);
Try
S.Position:=0;
XML:=Nil;
ReadXMLFile(XML,S); // Document XML complet
// Autre possibilité
ReadXMLFragment(AParentNode,S); // Lit uniquement un fragment XML.
Finally
S.Free;
end;
end;
Liens Externes
- W3Schools Tutoriel XML
- Thomas Zastrow article FPC et XML