Cette librairie peut etre trouvée à l'URL :http://www.jclark.com/xml/expatfaq.html. Elle est multiplateforme et propose une API simple à base de callback. C'est à dire des qu'un tag est trouvé , elle parse le contenu de ce tag et appele une fonction callback.
Vous devons tout d'abord initialiser le parseur xml (XML_Parser) :
XML_Parser parser = XML_ParserCreate(NULL); <code> Lors de l'appel du callback, le premier argument sera une variable définit par l'utilisateur ( userdata ). Pour positionner celle ci , apeller la fonction: XML_SetUserData(parser,userdata ); ou parser est de type XML_Parser et userdata de type void *. Deux fonctions callback peuvent etre appelees:
Il est important de preciser si le tag est a la fois nouveau et fermant les deux fonctions callback sont appelees. Lisez l'ensemble de votre document en memoire, puis appelé la fonction : XML_Parse Les fonctions callback seront alors automatiquement appelées. Voici un exemple:
void startElement(void *userData, const char *name, const char **atts)
{
int i;
char **tmp;
int *depthPtr = userData;
for (i = 0; i < *depthPtr; i++)
putchar('\t');
puts(name);
for (tmp=atts;*tmp!=NULL;tmp++)
puts(*tmp);
*depthPtr += 1;
}
void endElement(void *userData, const char *name)
{
int *depthPtr = userData;
*depthPtr -= 1;
printf("endElement %s \n",name);
}
nt main()
{
char buf[BUFSIZ];
XML_Parser parser = XML_ParserCreate(NULL);
int done;
int depth = 0;
XML_SetUserData(parser, );
XML_SetElementHandler(parser, startElement, endElement);
do {
size_t len = fread(buf, 1, sizeof(buf), stdin);
done = len < sizeof(buf);
if (!XML_Parse(parser, buf, len, done)) {
fprintf(stderr,
"%s at line %d\n",
XML_ErrorString(XML_GetErrorCode(parser)),
XML_GetCurrentLineNumber(parser));
return 1;
}
} while (!done);
XML_ParserFree(parser);
return 0;
}
On peut noter que l'ensemble des attributs d'un objet lui sont passé par un tableau atts dans la fonction callback StartElement.
l'API C n'apporte pas de simple agreable pour le developpement en C++. Effectivement ce n'est vraiment pas ideal lorsque l'object racine contient des object fils dont il doit garder la reference, qui eux meme ont des fils etc .... Assez rapidement il nous faudrait gérer les instances des objects créés pour les affilier à leur objets parents rendant la chose lourde. La seule solution était de créer les objets dans une seule fonction avec une imbriquation de test our savoir lequel instancier. En fin de compte les deux fonctions callbacks sont modifiés au cours du temps pour être affecté à l'objet conserné. Nous avons implementé un object le plus générique possible, celui ci gère la bonne affectation des fonctions de callback, ainsi que la bonne terminaison de la déclaration de l'objet par un tag fermant ( il conserve le nom du tag d'entree et sort si le nom du tag de sortie et le meme que celui d'entree ).
Pour faire l'interface entre le C et le C++ il y a deux fonctions :
Il a été aussi ajouté des méthodes de lectures et des sorties I/O pour les variables de l'object vers un fichier XML.
Voici l'API:
Variables:
Methodes
#include "stdio.h"
#include "OXML.h"
class SCENARIO: public OXML {
public:
SCENARIO(OXML *o,char *t,XML_Parser p,const char **atts): OXML(o,t,p,atts) {
printf("SCENARIO constructeur\n");
}
};
class ANTENNE: public OXML {
public:
ANTENNE(OXML *o,char *t,XML_Parser p,const char **atts): OXML(o,t,p,atts) {
printf("ANTENNE constructeur\n");
}
};
class TOPOLOGY: public OXML {
public:
int x;
int y;
SCENARIO *scenario;
ANTENNE *antenne;
TOPOLOGY(OXML *o,char *t,XML_Parser p,const char **atts): OXML(o,t,p,atts) {
printf("TOPOLOGY constructeur\n");
}
void OXMLendtag(const char *name) {
}
virtual void OXMLbegintag(const char *name,const char **atts) {
printf("TOPOLOGY OXMLbegintag %s \n",name);
if (!strcmp(name,"TOPOLOGY")) {
setValueAttrib(atts,"x",);
setValueAttrib(atts,"y",);
printf("X %d Y %d \n",x,y);
}
if (!strcmp(name,"SCENARIO")) {
scenario=new SCENARIO(this,(char*)name,parser,atts);
scenario->Init();
}
if (!strcmp(name,"ANTENNE")) {
antenne=new ANTENNE(this,(char*)name,parser,atts);
antenne->Init();
}
}
};
void main() {
FILE *f;
int done;
char buf[1024];
if ((f=fopen("topology.xml","r"))!=NULL) {
XML_Parser parser = XML_ParserCreate("ISO-8859-1");
/* Ajout des callback wrapper */
XML_SetElementHandler(parser, wrapperbegintag, wrapperendtag);
TOPOLOGY *res=new TOPOLOGY(NULL,"topology",parser,NULL);
res->Init();
do {
size_t len = fread(buf, 1, sizeof(buf), f);
done = len < sizeof(buf);
if (!XML_Parse(parser, buf, len, done)) {
fprintf(stderr,
"%s at line %d\n",
XML_ErrorString(XML_GetErrorCode(parser)),
XML_GetCurrentLineNumber(parser));
fclose(f);
return (NULL);
}
} while (!done);
XML_ParserFree(parser);
fclose(f);
}
}
<TOPOLOGY
x="10"
y="20"
>
<ANTENNE
toto="tutu"
/>
<SCENARIO
tutu="toto"
/>
$ ./topology OXML topology TOPOLOGY constructeur INIT OXML topology TOPOLOGY OXMLbegintag TOPOLOGY X 10 Y 20 TOPOLOGY OXMLbegintag ANTENNE OXML ANTENNE ANTENNE constructeur INIT OXML ANTENNE OXMLendtag ANTENNE TOPOLOGY OXMLbegintag SCENARIO OXML SCENARIO SCENARIO constructeur INIT OXML SCENARIO OXMLendtag SCENARIO