Next Previous Contents

2. la librairie Expat

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.

2.1 l'API C

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.

2.2 l'API C++

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

Lecture des attributs.

Methodes d'entree sortie.

2.3 Exemple d'un objet lisant du XML


#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);

        }
}

Lisant ce fichier xml.
<TOPOLOGY
        x="10"
        y="20"
>
<ANTENNE
        toto="tutu"
        />
<SCENARIO
        tutu="toto"
        />

A l'execution cela nous donne:
$ ./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 


Next Previous Contents