如何在xml树中反向行走节点,特别是libxml/c++

How can I reverse walk nodes in an xml tree, libxml/c++ specifically

本文关键字:节点 特别是 libxml c++ xml      更新时间:2023-10-16

我在一周前问过这个问题,虽然我得到了一个回复,但我从未更新过;我一开始也解释得很糟糕。所以,又来了。

<elementA>text</elementA>
    <elementF>text</elementF>
    <elementE>text</elementE>
        <elementD>text</elementD>   <-- This gets missed
    <elementC>text</elementC>
    <elementB>text</elementB>
        <elementA>text</elementA>   <-- xmlNodePtr node
        <elementA>text</elementA>
    <elementA>text</elementA>
    <elementA>text</elementA>
<elementA>text</elementA>

那么根据上面的情况,我如何向后走到达每个节点呢?为了向前走,我会使用这个函数(还没有测试过)。也许这是一个愚蠢的问题,但在我看来,如果我简单地把它倒过来,它就会跳过上面的内容,不是吗?我觉得我错过了一些明显的东西。

htmlNodePtr find_element_by_tag(htmlNodePtr startNode, string tagname)
{
    // Loop through all nodes
    for (htmlNodePtr node = startNode; node != NULL; node = node->next)
    {
        // Only
     interested in Element nodes
            if(node->type == XML_ELEMENT_NODE)
            {
                // Compare to search tagname
                if(xmlStrcasecmp(node->name, (const xmlChar*)tagname.c_str()) == 0)
                {
                    // If found return node pointer
                    return node;
                }
                // Recursively depth walk children nodes as well
                if(node->children != NULL)
                    {
                        this->find_element_by_tag(node->children);
                    }
            }
        }
        // If not found return NULL pointer
    return NULL;
}

一开始我看错了你的问题,所以我的第一个答案是错误的。我认为这可以工作(伪c++):

nodePtr reverse_find(nodePtr start, string tag)
{
    // check current node and previous siblings
    for (node = start; node != NULL; node = node->prev)
    {
        if (tag == node->name) { return node; }
        result = find_element_by_tag(node, tag);
        if (result) { return result; }
    }
    // not found, start looking at the parent nodes
    if (node->parent)
    {
        if (tag == node->parent->name) { return node->parent; }
        if (node->parent->prev)
        {
            if (tag == node->parent->prev->name) { return node->parent->prev; } 
            result = reverse_find(node->parent->prev, tag);
            if (result) { return result; }
        }
    }
    return NULL;
}

这是正向遍历递归解的简单转换。

考虑前向遍历的代码。它实际上是这样做的:

traverse_forward(node):
    for each node sibling in forward order:
        if sibling satisfies condition:
            do something with child
        if sibling has children:
            traverse_forward(first child of sibling)

您可以反转循环的顺序,并在处理节点本身之前递归调用处理子节点,从而产生以下算法:

traverse_backward(node):
    for each node sibling in reverse order:
        if sibling has children:
            traverse_backward(last child of sibling)
        if sibling satisfies condition:
            do something with child

以相反的顺序遍历兄弟节点,使用相同的循环,但使用->prev字段而不是->next字段。要获取最后一个子字段而不是第一个,您可以使用->last字段而不是->children字段。