【问题标题】:C++ libxml xmlNode->childrenC++ libxml xmlNode->children
【发布时间】:2013-03-26 21:30:33
【问题描述】:

好的,我一直在研究一个类来遍历 html 文档中的所有节点并返回我需要的数据。这非常简单,我已经在 Bash 中实现了这一点,但现在我正在尝试将其移植到 C++。

我从 libxml 站点上的示例开始,但我已逐个节点地逐步执行此功能,但我无法理解它是如何工作的。

函数如下:

    static void
print_element_names(xmlNode * a_node)
{
    xmlNode *cur_node = NULL;

    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
        if (cur_node->type == XML_ELEMENT_NODE) {
            printf("node type: Element, name: %s\n", cur_node->name);
        }

        print_element_names(cur_node->children);
    }
}

所以基本上,这个函数将一个节点分配给一个指针,并开始循环遍历所有兄弟节点,但如果当前节点有子节点,它会调用该函数并在该子节点上重新开始。这一切都很好理解。

所以它会降低文档结构,但它如何导航回结构呢?

xmlNode->children 找到 NULL 时是否返回下一个父节点?据我所知,这不是真的,但我就是不知道它是如何工作的。

我成功地创建了一个类来做我想做的事,但它比这要复杂得多,而且要长约 10 行。实际上,我必须检查下一个节点是否为空,如果它有子节点,则向下导航,如果没有,则向上导航到下一个节点。

这个例子要简单得多,我想了解如何使我的代码更好。

【问题讨论】:

    标签: c++ xml-parsing libxml2


    【解决方案1】:
    1. 所以它会降低 doc 结构,但它如何导航回结构呢?
      您发布的是递归函数。从您的问题的性质来看,我假设您不太了解递归是什么/它是如何工作的。快速的谷歌搜索应该会给你一些很好的信息/例子。

    2. xmlNode->children 找到NULL时是否返回下一个父节点?
      我假设 xmlNode->children 返回一个指向包含当前节点的所有子节点的链表的指针。如果当前节点没有子节点,它可能会返回 NULL。

    3. 这个例子要简单得多,我想了解如何使我的代码更好。
      我假设您编写的课程纯粹是迭代的。递归函数可以极大地简化代码,但在性能方面它们可能会在更大的数据集上引起问题。我肯定会推荐阅读它们;他们可以很有趣。

    【讨论】:

    • 感谢您的回复。是的,我的课程纯粹是迭代的。在我问这个问题之前,我已经阅读了很多关于递归的内容。也许我仍然不明白,但这就是我问这个问题的原因。根据我的阅读,我对递归的使用普遍持否定态度,这就是我避免使用它的原因。
    【解决方案2】:

    迭代解决问题本质上是树遍历。您将需要一个堆栈来完成此操作。堆栈可能最容易实现为单链表。

    // interface to be implemented
    typedef void* Stack;
    Stack stack_new();  // creates a new stack
    void stack_add(Stack stack, xmlNode *element); // adds an element to the stack
    int stack_size(); // returns the number of elements currently in the stack
    xmlNode* stack_remove(Stack stack); // pops an element from the stack
    void stack_free(Stack stack); // frees up resources used by the stack
    
    // printing code
    static void print_element_names(xmlNode *a_node)
    {
        Stack stack = stack_new();
        stack_add(stack, a_node);
    
        while(stack_size(stack))
        {
                xmlNode *cur_node = stack_remove(stack);
                if(cur_node->children) stack_add(cur_node->children);
                xmlNode *iter_node = NULL;
                for (iter_node = cur_node; iter_node; iter_node = iter_node->next)
                {
                    if (iter_node->type == XML_ELEMENT_NODE) 
                        printf("node type: Element, name: %s\n", iter_node->name);
                }
        }
    
        stack_free(stack);
    }
    

    【讨论】:

    • 这很有趣。没有想过使用堆栈。尝试编译但在 stack_add 函数上遇到太多参数错误。我确信这是我做错的事情。我会弄清楚。只看这个,我有点困惑,为什么要将不是 xml_element 的节点添加回堆栈。这不会导致永无止境的循环吗?
    • 再看一遍我相信你是对的,我的代码有一个错误。我很抱歉。我会立即修复它。
    猜你喜欢
    • 1970-01-01
    • 2017-08-27
    • 2017-01-07
    • 1970-01-01
    • 1970-01-01
    • 2020-12-24
    • 2015-11-27
    • 1970-01-01
    • 2010-11-21
    相关资源
    最近更新 更多