当前位置: 首页 > 知识库问答 >
问题:

pugiXML:如何在XML树中进行深度优先遍历

邢博涛
2023-03-14

我有以下XML文件,希望使用PugiXML库将其解析为C++:

<?xml version="1.0" encoding="UTF-8"?>
<graph id="g" edgedefault="undirected">
    <vertex id="1">
        <sensornode name="ESP32" room="1"/>
    </vertex>
    <vertex id="2">
        <sensornode name="Arduino" room="2"/>
    </vertex>
    <vertex id="3">
        <sensornode name="STM32" room="3"/>
    </vertex>
    <edge id="1" vertex1="1" vertex2="2" />
    <edge id="2" vertex1="1" vertex2="3" />
</graph>

我用C++创建了一个图结构。现在的任务是从XML文件到C++图结构。这是我目前为止最好的尝试:

int main()
{
    // String definitions: these are necessary for the string.compare() method.
    std::string graph_string ("graph");
    std::string edge_string ("edge");
    std::string vertex_string ("vertex");
    std::string sensornode_string("sensornode");

    // Pugi::xml initialization
    pugi::xml_document file;
    file.load_file("../graph.graphml");

    // Create an empty graph. This is needed due to the if statements that have nothing to do with 'if graph_string'.
    // For example, the 'if edge_string' does not know about graph g
    Graph g = Graph();

    // Make 'root' the root of the XML tree.
    pugi::xml_node root = file.child("graph"); // 'root' contains a list of graphs. But in reality, there is only one graph. Therefore, let's make this one graph the root.


    for(pugi::xml_node xml_node = root.first_child(); xml_node; xml_node = root.next_sibling())
    {
        std::cout << "XML node: " << xml_node << std::endl;

        if(graph_string.compare(xml_node.name())) {
            g = createGraphFromXML(xml_node);
            std::cout << "Graph g overwritten" << std::endl; // This should be the first output in the console!
        }
        else if(edge_string.compare(xml_node.name())) {
            Edge e = Edge();
            e = createEdgeFromXML(xml_node, &g);
            std::cout << "Edge id: " << e.getId() << std::endl;
            // TODO: add e to g
        }
        else if (vertex_string.compare(xml_node.name()) == 0) {
            Vertex v = Vertex();
            v = createVertexFromXML(xml_node);
            std::cout << "Vertex id: " << v.getId() << std::endl;
            // TODO: add v to g
        }
        else if (sensornode_string.compare(xml_node.name()) == 0) {
            std::cout << "Sensornode: skip to next iteration" << std::endl;
            continue; // Skip this since it is already handled in 'createVertexFromXML'.
        }
        else {
            std::cout << "ERROR KUT" << std::endl;
            throw std::invalid_argument("TODO: zet hier iets nuttigs");
        }

        std::cout << std::endl;
    }
    std::cout << std::endl;

    std::cin.get();
    return 0;
}

double randomDouble(double lower, double upper)
{
    /*
     * This function generates a random double value that
     * is between lower and upper bounds.
     * Source: https://stackoverflow.com/a/9324796
     */

    std::uniform_real_distribution<double> unif(lower, upper);
    std::default_random_engine re;
    return unif(re);
}

Graph createGraphFromXML(pugi::xml_node xml_node) {
    /*
     * This function takes the XML node as input. It then processes
     * this information, taking the XML attributes into account.
     * Finally, it returns the Graph object.
     *
     * Note: to keep it as simplea as possible, we will not process the extra graph information (e.g. if directed).
     */

    // Create and return the graph
    Graph g = Graph();
    return g;
}

Edge createEdgeFromXML(pugi::xml_node xml_node, Graph *g) {
    /*
    * This function takes the XML node as input. It then processes
    * this information, taking the XML attributes into account.
    * Finally, it returns the Edge object.
    */

    // Note: you have to append this to the graph's edge list!

    // String definitions: these are necessary for the string.compare() method.
    std::string id_string ("id");
    std::string vertex1_string ("vertex1");
    std::string vertex2_string ("vertex2");

    // Create a new edge e
    Edge e = Edge(); // Use the default constructor that has no input parameters. This way, we can add the id, vertex1 and vertex2 later.

    // // Iterate over the attributes of 'xml_node'.
    for(pugi::xml_attribute attr = xml_node.first_attribute(); attr; attr = attr.next_attribute())
    {
        std::cout << " " << attr.name() << "=" << attr.value() << std::endl; // Print the attribute name and value.

        if(id_string.compare(attr.name()) == 0) {
            //const char_t *id = attr.value();
            unsigned short id = (unsigned short) *attr.value();
            e.addId(id);
        }
        else if(vertex1_string.compare(attr.name()) == 0) {
            unsigned short id_vertex1 = (unsigned short) *attr.value();

            // Iterate over the list of vertices to get a pointer to the correct vertex.
            std::list<Vertex*> vertexList = g->getVertices(); // Get the list of vertices
            std::list<Vertex*>::iterator iter; // Create the iterator
            for (iter = vertexList.begin(); iter != vertexList.end(); ++iter) {
                if((**iter).getId() == id_vertex1) {
                    e.addVertex1(*iter); // *iter points to the first vertex.
                }
            }
        }
        else if(vertex2_string.compare(attr.name()) == 0) {
            unsigned short id_vertex2 = (unsigned short) *attr.value();

            // Iterate over the list of vertices to get a pointer to the correct vertex.
            std::list<Vertex*> vertexList = g->getVertices(); // Get the list of vertices
            std::list<Vertex*>::iterator iter; // Create the iterator
            for (iter = vertexList.begin(); iter != vertexList.end(); ++iter) {
                if((**iter).getId() == id_vertex2) {
                    e.addVertex2(*iter); // *iter points to the second vertex.
                }
            }
        }
    }
    // Return the edge e
    return e; // TODO: make this a pointer?
}

Vertex createVertexFromXML(pugi::xml_node xml_node) { // , Graph *g
    // String definitions: these are necessary for the string.compare() method.
    std::string id_string ("id");
    std::string name_string ("name");
    std::string room_string ("room");

    // Create an empty Vertex and an empty SensorNode. These will be filled later on.
    Vertex v = Vertex();
    SensorNode sensorNode;
    sensorNode.temperature = randomDouble(18.0, 24.0); // degrees Celsius
    sensorNode.humidity = randomDouble(0.3, 0.7); // %, TODO: optimize this.
    sensorNode.co2 = randomDouble(400, 800); // ppm, TODO: optimize this.

    // Iterate over the attributes of 'xml_node'.
    for(pugi::xml_attribute attr = xml_node.first_attribute(); attr; attr = attr.next_attribute()) {
        std::cout << " " << attr.name() << "=" << attr.value() << std::endl; // Print the attribute name and value.

        if (id_string.compare(attr.name()) == 0) {
            //const char_t *id = attr.value();
            unsigned short id = (unsigned short) *attr.value();
            v.addId(id);
        }
    }

    // Get the XML child. For a vertex, this is <sensornode/>.
    pugi::xml_node xml_child = xml_node.child("sensornode");

    // Iterate over the attributes of 'xml_child'
    for(pugi::xml_attribute attr = xml_child.first_attribute(); attr; attr = attr.next_attribute()) {
        std::cout << " " << attr.name() << "=" << attr.value() << std::endl; // Print the attribute name and value.

        if (name_string.compare(attr.name()) == 0) {
            //const char_t *id = attr.value();
            sensorNode.name = (std::string) reinterpret_cast<const char *>(*attr.value()); // TODO: what's this???
        }
        else if (room_string.compare(attr.name()) == 0) {
            sensorNode.room = (std::string) reinterpret_cast<const char *>(*attr.value());
        }
    }

    // Add sensorNode to vertex v
    v.addSensorNode(&sensorNode);

    // Return the vertex v
    return v;
}

这段代码的问题在于它只处理XML节点“graph”。并不是所有的孩子都能接受。我发现一个可能的解决方案是使用深度优先遍历XML树。您可以在这里找到相应的文档(查找“Simple Walker”示例)。现在我被困住了,我不知道如何实现“简单的walker”结构,以一种简单易懂的方式处理XML树。

关于如何使用pugixml实现深度优先的树遍历,有没有人可以帮助我或者给我指明正确的方向?提前道谢。

共有1个答案

松灿
2023-03-14

在assimp中,我编写了一个XML-NodeIterator,它将遍历整个树。您可以在这里找到它:Assimp-XmlNodeIterator

 类似资料:
  • 主要内容:src/runoob/binary/Traverse.java 文件代码:二分搜索树遍历分为两大类,深度优先遍历和层序遍历。 深度优先遍历分为三种:先序遍历(preorder tree walk)、中序遍历(inorder tree walk)、后序遍历(postorder tree walk),分别为: 1、前序遍历:先访问当前节点,再依次递归访问左右子树。 2、中序遍历:先递归访问左子树,再访问自身,再递归访问右子树。 3、后序遍历:先递归访问左右子树,再访问自身节

  • 本文向大家介绍手写代码:二叉树深度优先遍历相关面试题,主要包含被问及手写代码:二叉树深度优先遍历时的应答技巧和注意事项,需要的朋友参考一下 参考回答: //深度优先搜索 //利用栈,现将右子树压栈再将左子树压栈

  • 主要内容:非连通图的生成森林,深度优先生成森林,广度优先生成森林前面已经给大家介绍了有关 生成树和生成森林的有关知识,本节来解决对于给定的无向图,如何构建它们相对应的生成树或者生成森林。 其实在对无向图进行遍历的时候,遍历过程中所经历过的图中的顶点和边的组合,就是图的生成树或者生成森林。 图 1 无向图   例如,图 1 中的无向图是由 V1~V7 的顶点和编号分别为 a~i 的边组成。当使用 深度优先搜索算法时,假设 V1 作为遍历的起始点,涉及到的顶点和边

  • 深度优先搜索(DFS)算法以向深运动的方式遍历图形,并使用堆栈记住在任何迭代中发生死角时获取下一个顶点以开始搜索。 如在上面给出的示例中,DFS算法首先从S到A到D到G到E到B,然后到F,最后到C.它使用以下规则。 Rule 1 - 访问相邻的未访问顶点。 将其标记为已访问。 显示它。 将其推入堆栈。 Rule 2 - 如果未找到相邻顶点,则从堆栈中弹出一个顶点。 (它将弹出堆栈中的所有顶点,这些

  • 我们不会在C编程语言中看到Depth First Traversal(或Depth First Search)的实现。 出于参考目的,我们将遵循我们的示例并将其作为我们的图形模型 - 用C实现 (Implementation in C) #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define MAX 5 struct

  • 本文向大家介绍解释下深度优先遍历和广度优先遍历的区别及如何实现相关面试题,主要包含被问及解释下深度优先遍历和广度优先遍历的区别及如何实现时的应答技巧和注意事项,需要的朋友参考一下 1、深度优先采用堆栈结构,先进后出,所占的空间较小,执行时间较长; 2、广度优先采用队列结构先进先出,所占空间较大,执行时间短,空间换时间;