V. Concepts avancés▲
V-A. La classe TDOMParser▲
Pour utiliser des concepts plus avancés tels que la validation d'un document XML ou l'utilisation des espaces de noms, nous aurons recours à un objet TDOMParser. Cette classe permet aussi de mettre en œuvre une gestion avancée des erreurs pouvant survenir lors du traitement d'un document XML.
TDOMParser = class(TObject)
private
{...}
public
constructor Create;
destructor Destroy; override;
procedure Parse(Src: TXMLInputSource; out ADoc: TXMLDocument);
procedure ParseUri(const URI: WideString; out ADoc: TXMLDocument);
function ParseWithContext(Src: TXMLInputSource; Context: TDOMNode; Action: TXMLContextAction): TDOMNode;
property Options: TDOMParseOptions read FOptions;
property OnError: TXMLErrorEvent read FOnError write FOnError;
end;
Un objet TDOMParser pour être utilisé, doit être l'attribut d'une classe donnée afin de mettre en œuvre
la gestion des erreurs.
La propriété onError definit la fonction à appeler quand une erreur survient lors du traitement du
document XML. Options définit les paramètres qui vont permettre la validation d'un document XML ainsi
que l'utilisation des espaces de noms.
Nous allons construire une classe qui nous permettra de parser et de valider un document XML contenu dans un fichier à l'aide de la classe TDOMParser.
type myParseur=class
private
error : boolean;
errMessage : String;
path : string;
validate : boolean;
ns : boolean;
procedure onError(Err: EXMLReadError);
public
constructor init(pth : String);
procedure setValidate(b : boolean);
procedure setNameSpace(b: boolean);
function doParse(): TXMLDocument;
function isError() : boolean;
function getErrorMessage() : String;
end;
constructor myParseur.init(pth : String);
begin
self.path:=pth;
error:=false;
errMessage:='';
validate:=false;
ns:=false;
end;
procedure myParseur.setValidate(b : boolean);
begin
validate:=b;
end;
procedure myParseur.setNameSpace(b: boolean);
begin
ns:=b;
end;
function myParseur.doparse() : TXMLDocument;
var fichier : textFile;
source : TXMLInputSource;
sourceFic : TFileStream;
doc : TXMLDocument;
parseur : TDOMParser;
begin
try
sourceFic:= TFileStream.Create(path, fmOpenRead);
source:= TXMLInputSource.create(sourceFic);
except
doParse:=nil;
error:=true;
errMessage:='Impossible de lire le fichier '+path;
exit;
end ;
doc:=nil;
parseur:= TDOMParser.Create;
parseur.OnError:=@onError;
parseur.Options.Validate:=validate;
parseur.Options.Namespaces:=ns;
try
parseur.Parse(source, doc);
except
end;
doParse:=doc;
end;
function myParseur.isError() : boolean;
begin
isError:=error;
end;
function myParseur.getErrorMessage() : String;
begin
getErrorMessage:=errMessage;
end;
procedure myParseur.onError(Err: EXMLReadError);
begin
error:=true;
errMessage:=err.ErrorMessage;
end;La méthode onError() est la méthode qui sera appelée dynamiquement par le programme quand une erreur survient lors du traitement du document. Une référence vers cette fonction doit être passée à l'attribut onError de la classe TDOMParser.
parseur.OnError:=@onError;Le reste du code peut se passer de tout commentaire puisque je suppose que vous avez déjà acquis les bases de la programmation objet.
V-B. La validation▲
Vous savez sans doute qu'en XML il n'y a pas de balises prédéfinies. On peut donc définir les balises comme on le souhaite et les placer n'importe où dans un document. Mais pour être sûr qu'un document XML soit compris par une autre application, nous devons définir un protocole de communication qui servira à valider le document XML.
Pour valider un document XML, on peut soit utiliser un DTD (Document Type Definition) ou un document XSD (XML Schema Definition). A ma connaissance, l'API que nous utilisons supporte uniquement l'utilisation de DTD pour la validation d'un document XML.
Pour valider un document XML, nous allons utiliser la classe TDOMParser, mais nous allons modifier le paramètre Options
TDOMParseOptions = class(TObject)
private
{...}
public
property Validate: Boolean read FValidate write FValidate;
property PreserveWhitespace: Boolean read FPreserveWhitespace write FPreserveWhitespace;
property ExpandEntities: Boolean read FExpandEntities write FExpandEntities;
property IgnoreComments: Boolean read FIgnoreComments write FIgnoreComments;
property CDSectionsAsText: Boolean read FCDSectionsAsText write FCDSectionsAsText;
property ResolveExternals: Boolean read FResolveExternals write FResolveExternals;
property Namespaces: Boolean read FNamespaces write FNamespaces;
end;Le paramètre qui nous interesse ici est Options.Validate. Sa valeur à true indique qu'on desire valider le document à parser à l'aide d'un DTD. Nous allons parser et valider le document XML suivant :
<?xml version="1.0" ?>
<!DOCTYPE developpez
[
<!ELEMENT developpez (membre*)>
<!ELEMENT membre (pseudo, message, status)>
<!ATTLIST membre id ID #REQUIRED>
<!ELEMENT pseudo (#PCDATA)>
<!ELEMENT message (#PCDATA)>
<!ELEMENT status (#PCDATA)>
]
>
<developpez>
<membre id="n1">
<pseudo >darrylsite</pseudo>
<message>500</message>
<status>redacteur</status>
</membre>
<membre id="m2">
<pseudo>mbr</pseudo>
<message>1500</message>
<status>moderateur</status>
</membre>
</developpez>Voici un exemple qui fait le travail voulu :
program validation;
{$mode objfpc}{$H+}
uses dom, xmlRead, xmlWrite, classes;
type myParseur=class
{...}
end;
var
parseur : myParseur;
doc : TXMLDocument;
begin
parseur:= MyParseur.init('test.xml');
parseur.setValidate(true);//on indique ici qu'on veut valider le xml
doc:=parseur.doParse();
if(parseur.isError()) then
begin
writeln('Erreur : '+parseur.getErrorMessage())
end
else
writeln('Le document xml est conforme');
readln;
end.En exécutant ce code, vous aurez un message disant que le document est conforme. Mais si on change, par exemple, la première balise membre par membres, une erreur survient avec le message Using undeclared attribute 'id' on element 'membres'.


