использование обработчика начала экспата C ++ - PullRequest
1 голос
/ 23 сентября 2010

Я использую Expat для чтения XML-файла.Я хочу заполнить некоторые из моих переменных-членов класса из конфигурации, указанной в XML-файле.Я определил свой обработчик начального элемента,

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

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

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

Ответы [ 2 ]

1 голос
/ 23 сентября 2010

Я раньше не использовал 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

1 голос
/ 23 сентября 2010

Ну, функция-член класса похожа на обычную функцию с неявным контекстом данных, прикрепленным к ней.Поэтому, если вы хотите избежать ссылки на глобальные данные, вам так или иначе необходимо передать ненулевой контекстный аргумент 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, не ошибочно передавать его в функцию-обработчик.

...