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'.