проблема рекурсии при разборе с побочным эффектом указателей класса RapidXML / C ++ - PullRequest
0 голосов
/ 29 марта 2011

Я хочу поделиться этой странной, но интересной ситуацией, с которой я недавно столкнулся при попытке использовать RapidXML для синтаксического анализа XML в C ++.

Я хотел написать рекурсивную функцию для поиска и возврата определенного узла среди детей.данного узла.Моя первая попытка была:

xml_node<>* get_child(xml_node<> *inputNode, string sNodeFilter)
{
    // cycles every child
    for (xml_node<> *nodeChild = inputNode->first_node(); nodeChild; nodeChild = nodeChild->next_sibling())
    {
        if (nodeChild->name() == sNodeFilter)
        {
            cout << "node name " << nodeChild->name() << "\n";
            cout << "nodeChild " << nodeChild << endl;
            // returns the desired child
            return nodeChild;
        }
        get_child(nodeChild, sNodeFilter);
    }
}

Это работало корректно только с первыми дочерними элементами, но если вы ищете узел, который вложен глубже в ваш XML-файл, узел найден (я вижу, что cout) но после оператора return цикл for, кажется, запускается еще один (или несколько) раз (возможно, из-за стека вызовов рекурсии), затем завершается, и указатель теряется.

Поэтому я попытался исправитьэто с временной переменной, таким образом:

xml_node<>* get_child(xml_node<> *inputNode, string sNodeFilter)
{
    xml_node<> *outputNode;
    // cycles every child
    for (xml_node<> *nodeChild = inputNode->first_node(); nodeChild; nodeChild = nodeChild->next_sibling())
    {
        if (nodeChild->name() == sNodeFilter)
        {
            cout << "node name " << nodeChild->name() << "\n";
            cout << "nodeChild " << nodeChild << endl;
            outputNode = nodeChild;
            cout << "outputNode " << outputNode << endl;
            // returns the desired child
            return outputNode;
        }
        get_child(nodeChild, sNodeFilter);
    }
}

Но ничего не изменилось ..

К сожалению, узлы в RapidXML являются указателями классов, поэтому в этой ситуации побочный эффект мешает мне вывести правильный результат.

Кто-нибудь нашел эту ситуацию или решил эту проблему по-другому?

Ответы [ 2 ]

4 голосов
/ 29 марта 2011

Когда вы найдете ребенка по возвращении, верните его.Если вы не нашли ребенка, верните 0

xml_node<>* get_child(xml_node<> *inputNode, string sNodeFilter)
{
    // cycles every child
    for (xml_node<> *nodeChild = inputNode->first_node(); nodeChild; nodeChild = nodeChild->next_sibling())
    {
        if (nodeChild->name() == sNodeFilter)
        {
            cout << "node name " << nodeChild->name() << "\n";
            cout << "nodeChild " << nodeChild << endl;
            // returns the desired child
            return nodeChild;
        }
        xml_node<> * x = get_child(nodeChild, sNodeFilter);
        if (x) 
          return x;
    }
    return 0;
}
1 голос
/ 24 ноября 2014

Я знаю, что это не дает прямого ответа на вопрос, но я надеюсь, что это может помочь кому-то еще:

Эта функция полезна, когда вы хотите рекурсивно искать ВСЕ узлы с заданным именем в каком-либо родительском узле. Возвращает вектор с результатами:

vector<xml_node<>*> find_nodes(xml_node<>* parent, const char* name) {
    vector<xml_node<>*> ret;
    if (parent != 0) {
        if (strcmp(parent->name(), name) == 0) {
            ret.push_back(parent);
        }
        for (xml_node<>* it = parent->first_node(); it != 0; it = it->next_sibling()) {
            vector<xml_node<>*> tmp = find_nodes(it, name);
            ret.insert(ret.end(), tmp.begin(), tmp.end());
        }
    }
    return ret;
}

Пример использования:

vector<xml_node<>*> nodes = find_nodes(some_node, "link");

Также работает со всем документом!

xml_document<> doc;
doc.parse<0>(str);  // parse some string

vector<xml_node<>*> nodes = find_nodes(&doc, "link");
...