递归使用TinyXML生成常规树时的分段错误?

时间:2016-07-04 19:11:40

标签: c++ recursion tree tinyxml

我正在尝试使用TinyXML解析XML文件以构建常规树。我试图递归地做这件事。问题是,我每次都会遇到分段错误。

以下是摘录:

void buildTree() {
        // Loading XML file and getting rootNode
        string filename = "generalTree.xml";
        TiXmlDocument doc(filename);
        bool loadOkay = doc.LoadFile();
        if (!loadOkay) {
            cout << "Could not load file " << filename << endl;
            cout << "Error='" << doc.ErrorDesc() <<"'. Exiting.\n";
        }
        TiXmlNode* generalTreeNode = doc.FirstChild("GeneralTree");
        TiXmlNode* rootNode = generalTreeNode->FirstChild();
        int key = stoi(rootNode->ToElement()->Attribute("key"));
        Type data = rootNode->ToElement()->GetText();
        root = new TreeNode<Type>("General", key, data);
        // Populating the rest of the tree via recursive function
        recFunction(rootNode);
    }

这是recFunction:

  void recFunction(TiXmlNode *node) {
        if(node->FirstChildElement() == NULL) {
            cout << "First child element is null" << endl;
        } else {
            int key = stoi(node->ToElement()->Attribute("key"));
            Type data = node->ToElement()->GetText();
            TreeNode<Type> *treeNode = new TreeNode<Type>("General", key, data);
            cout << "Right BEFORE recursive activates" << endl;
            return recFunction(node->FirstChild());
        }
        cout << "After recursiveness done" << endl;
        // After recursiveness is finished
        while(node->NextSibling() != NULL) {
            if(!node) {
                cout << "Node is null, breaking" << endl;
                break;
            }
            // Converting XML node to TreeNode
            cout << "DOING NODE TO ELEMENT" << endl;
            cout << node->ToText()->Value() << endl;
            cout << "Node is of type: " << typeid(node).name() << endl;
            cout << node->ToElement()->Attribute("key") << endl;
            cout << "DONE WITH NODE TO ELEMENT" << endl;
            int key = stoi(node->ToElement()->Attribute("key"));
            cout << "Key 1 is: " << key << endl;
            Type data = node->ToElement()->GetText();
            cout << "Data 1 is: " << data << endl;
            TreeNode<Type> *prev = new TreeNode<Type>("General", key, data);
            int key2 = stoi(node->NextSibling()->ToElement()->Attribute("key"));
            Type data2 = node->ToElement()->GetText();
            TreeNode<Type> *cur = new TreeNode<Type>("General", key2, data2);
            // Create linked list of siblings
            prev->setSibling(cur);
            node = node->NextSibling();
        }
        cout << "End of while loop reached" << endl;
    }

这是XML文件:

<?xml version="1.0"?>
<GeneralTree>
    <Node key="1"> Genres
        <Node key="2">Thriller</Node>
        <Node key="3">Action</Node>
        <Node key="4">Romance
            <Node key="7">A Walk To Remember</Node>
            <Node key="8">The Notebook</Node>
            <Node key="9">Safe Haven</Node>
        </Node>
        <Node key="5">Anime
            <Node key="9">Full Metal Alchemist</Node>
            <Node key="10">Pokemon 2000: The Movie</Node>
        </Node>
    </Node>
    <Node key="12">Genre Sister</Node>
</GeneralTree>

现在,我已将问题分离到recFunction中的以下行:

    cout << "DOING NODE TO ELEMENT" << endl;
    cout << node->ToText()->Value() << endl;
    cout << "Node is of type: " << typeid(node).name() << endl;
    cout << node->ToElement()->Attribute("key") << endl;
    cout << "DONE WITH NODE TO ELEMENT" << endl;

所以我假设节点在递归函数的某个点变为null。问题是我一次又一次地看着这个,我似乎无法弄清楚为什么。检查到位应该防止节点变为空。

这是我收到的输出(包括打印语句,以便您可以看到它发生的位置)。

Right BEFORE recursive activates
First child element is null
After recursiveness done
DOING NODE TO ELEMENT
Genres
Node is of type: P9TiXmlNode

提前致谢!

编辑:这是当我运行gdb并在

使用断点时会发生什么
    cout << node->ToText()->Value() << endl;

和             cout&lt;&lt; node-&gt; ToElement() - &gt;属性(“key”)&lt;&lt; ENDL;

Right BEFORE recursive activates
First child element is null
After recursiveness done
DOING NODE TO ELEMENT

Breakpoint 1, GeneralTree<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::recFunction (this=0x100300040, node=0x1003005c0)
    at ./GeneralTree.h:70
70              cout << node->ToText()->Value() << endl;
(gdb) c
Continuing.
Genres
Node is of type: P9TiXmlNode

Breakpoint 2, GeneralTree<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::recFunction (this=0x100300040, node=0x1003005c0)
    at ./GeneralTree.h:72
72              cout << node->ToElement()->Attribute("key") << endl;
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
TiXmlAttributeSet::Find (this=0x60, name=0x100018ede "key") at tinyxml.cpp:1527
1527        for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )

1 个答案:

答案 0 :(得分:0)

有许多事情,但它们都归结为同样的概念错误。

XML节点包括文本,空格和属性,而不仅仅是元素。

因此,如果你打算对所有元素进行递归,那就错了:

 return recFunction(node->FirstChild());

相反它应该是这样的:

 return recFunction(node->FirstChildElement());

同样,您要求NextSibling,您可能需要NextSiblingElement

例如:

int key2 = stoi(node->NextSibling()->ToElement()->Attribute("key"));

如果NextSibling返回文本节点,则ToElement将返回null。

查看SEGV信息:

TiXmlAttributeSet::Find (this=0x60, name=0x100018ede "key") at tinyxml.cpp:1527

这显示this指针值为0x60,这不太可能有效。获取此类指针的最可能方法是在空指针的类型转换中进行未经检查的指针调整。即您在某些时候使用了空指针,并且您的代码或库代码已将其转换为相关类型。

在这种情况下,由于node->ToText()成功,因此node->ToElement()必然会返回null,因为节点是文本节点或元素节点。因此ToElement的返回值为null,并且在其上调用Attribute是错误的。