Search code examples
c++pointersrecursionside-effectsrapidxml

recursion problem in parsing with RapidXML/C++ class pointers side-effect


I want to share this odd but interesting situation I stumbled upon recently while trying to use RapidXML for XML parsing in C++.

I wanted to write a recursive function to search and return a particular node among the children of a given node. My first try was:

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

It happened to work correctly only with the first children, but if you search for a node that is nested deeper in your XML file, the node is found (I see the cout's) but after the return statement the for cycle seems to run one (or some) more time (probably because of the call stack of the recursion), then exit and the pointer gets lost.

So I tried to fix it with a temporary variable, this way:

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

But nothing changed..

Unfortunately nodes in RapidXML are class pointers, so in this situation the side-effect prevents me from pulling out the correct result.

Anyone has found this situation, or has solved this problem in another way?


Solution

  • When you find a child by recursing, return it. If you don't find a child, return 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;
    }