2010-09-23 1 views
1

Я использую expat для чтения xml-файла. Я хочу заполнить некоторые из моих переменных-членов класса из конфигурации, указанной в XML-файле. Я определил мой StartElement обработчик,using expat startelement handler C++

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

и это будет ссылаться следующим образом:

XML_SetElementHandler(parser,Start, NULL); 

В настоящее время я использую глобальную структуру, g_stConfigInfo хранить все значения в Start()

Например,

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]; 
      } 
      ......... 

Тогда я делаю ing myclass.sInputName = g_stConfigInfo.sInputname

Я бы предпочел не использовать глобальную переменную, вместо этого сделать это функцией-членом класса, чьи переменные-члены должны быть заполнены. Я также не хочу иметь экземпляр этого класса внутри Start(). Каков наилучший способ сделать это?

ответ

1

Ну, функция члена класса похожа на обычную функцию с неявным контекстом данных, прикрепленным к ней. Поэтому, если вы хотите избежать ссылки на глобальные данные, так или иначе вам нужно передать аргумент контекста, отличного от NULL, до Start.

идиоматических способ сделать это, как правило, так:

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

Другими словами, если ваш класс соответствует некоторому XML-элемент, это не неправильно передать его функции обработчика.

+0

Я обычно делал то же самое без шаблонов. Это делает его намного чище. +1 – Ferruccio

1

Я раньше не использовал Expat, но я думаю, что использование XML_SetUserData - это то, что вы хотите.

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 заставит парсер передать указатель вы даете его обработчиком обратных вызовов. http://www.xml.com/pub/a/1999/09/expat/index.html?page=3#setuserdata

 Смежные вопросы

  • Нет связанных вопросов^_^