2010-09-23 12 views
1

J'utilise expat pour lire un fichier xml. Je veux remplir certaines variables de mes membres de classe à partir de la configuration spécifiée dans le fichier .xml. J'ai défini mon gestionnaire de startElement,en utilisant expat startelement handler C++

void Start(void *data,const XML_Char *el, const XML_Char **attr) 

et ce sera référencé comme suit:

XML_SetElementHandler(parser,Start, NULL); 

À l'heure actuelle, je me sers d'une structure globale, g_stConfigInfo pour stocker toutes les valeurs dans Start()

Par exemple,

void Start(void *data,const XML_Char *el, const XML_Char **attr) 
{ 
    if(_tcscmp(el,_T("blah"))==0) 
    { 
     for (int i=0; attr[i]; i+=2) 
     { 
      if(_tcscmp(attr[i],_T("name"))==0) 
      { 
       g_stConfigInfo.sInputName = attr[i+1]; 
      } 
      ......... 

Puis-je faire Je préférerais ne pas utiliser la variable globale, pour pouvoir en faire une fonction membre de la classe dont les variables membres doivent être remplies. Je ne veux pas avoir une instance de cette classe dans Start() non plus. Quelle est la meilleure façon de faire cela?

Répondre

1

Eh bien, une fonction de membre de classe est juste comme la fonction régulière avec un contexte de données implicite attaché à elle. Donc, si vous voulez éviter de référencer des données globales, vous devez passer un argument de contexte non-NULL à Start.

façon idiomatiques de le faire est généralement comme ceci:

class MyHandler { 
public: 
    void Start(const XML_Char *el, const XML_Char **attr) { 
     // ...dispatch on "el" here. 
     // e.g. a map of strings to member function pointers 
    } 
}; 
... 

template<T> 
void 
Start(void *data, const XML_Char *el, const XML_Char **attr) 
{ 
    T *handler = static_cast<T*>(data); 
    handler->Start(el, attr); 
} 

MyHandler handler; 
XML_SetUserData(parser, handler); 
XML_SetElementHandler(parser, Start<MyHandler>, NULL); 

En d'autres termes, si votre classe correspond à un élément XML, il n'a pas tort de le transmettre à la fonction de gestionnaire.

+0

J'ai généralement fait la même chose sans modèles. Cela le rend beaucoup plus propre. +1 – Ferruccio

1

Je n'ai jamais utilisé Expat auparavant, mais je pense que l'utilisation de XML_SetUserData est ce que vous voulez.

class my_data 
{ 
    public: 
    static void start_callback(void *data, const XML_Char *el, const XML_Char **attr) 
    { 
     static_cast<my_data*>(data)->start(el, attr); 
    } 

    void start(const XML_Char *el, const XML_Char **attr); 
}; 

//... 
my_data data; 
XML_SetUserData(parser, &data); 
XML_SetElementHandler(parser, my_data::start_callback, NULL); 

setUserData fera l'analyseur pour passer le pointeur que vous donnez à tous les callbacks de gestionnaire. http://www.xml.com/pub/a/1999/09/expat/index.html?page=3#setuserdata