You need to enable JavaScript to run this app. 基于Boost BGL将嵌套XML存储为无向图 以类替代struct实现
优惠活动
大模型
产品
解决方案
定价
更多

基于Boost BGL将嵌套XML存储为无向图 以类替代struct实现

实现思路

核心是将原有零散的结构化存储逻辑重构为类封装的BGL无向图存储,严格匹配提出的XML到图的映射规则:

  • 顶点层:所有<car>、<plane>元素作为图的独立顶点,顶点属性封装对应元素的全部XML字段,通过类型字段区分汽车、飞机两类节点,避免为不同车辆类型定义重复的结构体。
  • 边层:所有<spec>、<additions>、<utilities>子元素作为图的边载体,边属性封装对应子元素的全部XML字段,完全替代原代码中顶点内部嵌套存储子节点列表的冗余结构。
  • 图结构:采用BGL原生无向图容器,将顶点、边属性直接绑定到图的内置属性系统,无需额外维护外挂的属性列表。
核心类设计(替代原有零散struct)

用类封装所有数据结构,替代原有的Car、Spec结构体,兼顾类型可扩展性:

顶点属性类 VehicleVertex

class VehicleVertex {
private:
    std::string node_type;  // 标记节点类型:"car"/"plane"
    std::string name;       // 节点的name属性
    std::string extra_info;  // 存储非共有属性:car的weight、plane的id
public:
    // 构造函数
    VehicleVertex(std::string t, std::string n, std::string info)
        : node_type(std::move(t)), name(std::move(n)), extra_info(std::move(info)) {}
    
    // 友元打印函数
    friend std::ostream& operator<<(std::ostream& os, const VehicleVertex& v) {
        os << "顶点类型: " << v.node_type 
           << ", 名称: " << v.name 
           << ", 附加属性: " << v.extra_info;
        return os;
    }
};

边属性类 ChildNodeEdge

class ChildNodeEdge {
private:
    std::string edge_type;  // 标记边来源子节点类型:"spec"/"additions"/"utilities"
    std::map<std::string, std::string> attrs;  // 存储子节点的全部XML属性
public:
    // 构造函数
    ChildNodeEdge(std::string t, std::map<std::string, std::string> a)
        : edge_type(std::move(t)), attrs(std::move(a)) {}
    
    // 友元打印函数
    friend std::ostream& operator<<(std::ostream& os, const ChildNodeEdge& e) {
        os << "边类型: " << e.edge_type << ", 属性: {";
        for (auto it = e.attrs.begin(); it != e.attrs.end(); ++it) {
            if (it != e.attrs.begin()) os << ", ";
            os << it->first << "=" << it->second;
        }
        os << "}";
        return os;
    }
};
BGL无向图定义

基于上述两个类,直接定义符合要求的无向图类型:

#include <boost/graph/adjacency_list.hpp>
// 无向图配置:顶点存储VehicleVertex,边存储ChildNodeEdge
using VehicleGraph = boost::adjacency_list<
    boost::vecS,          // 边容器:动态数组
    boost::vecS,          // 顶点容器:动态数组
    boost::undirectedS,   // 无向图标记
    VehicleVertex,        // 绑定顶点属性
    ChildNodeEdge         // 绑定边属性
>;
XML到图的解析流程

严格匹配映射规则,解析过程分为三步:

  1. 初始化图的固定功能顶点:提前创建3个对应子节点类型的中心顶点(分别关联spec、additions、utilities类型),用于和车辆类顶点连边,满足无向图“边必须连接两个顶点”的结构要求。
  2. 遍历所有车辆类顶点:
    • 遍历root.type.cars下的所有<car>节点,解析name、weight属性,创建VehicleVertex加入图中
    • 遍历root.type.planes下的所有<plane>节点,解析name、id属性,创建VehicleVertex加入图中
  3. 遍历所有子节点生成边:对每个车辆类节点,遍历其下的子节点,收集子节点的全部XML属性,构造ChildNodeEdge对象,从当前车辆顶点连一条边到对应的功能中心顶点。
完整可运行代码示例
#include <boost/property_tree/xml_parser.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/range/adaptor/indexed.hpp>
#include <fstream>
#include <map>
#include <iostream>

using boost::property_tree::ptree;

// 顶点属性类
class VehicleVertex {
private:
    std::string node_type;
    std::string name;
    std::string extra_info;
public:
    VehicleVertex(std::string t, std::string n, std::string info)
        : node_type(std::move(t)), name(std::move(n)), extra_info(std::move(info)) {}
    friend std::ostream& operator<<(std::ostream& os, const VehicleVertex& v) {
        os << "顶点[类型:" << v.node_type << ", 名称:" << v.name << ", 附加:" << v.extra_info << "]";
        return os;
    }
};

// 边属性类
class ChildNodeEdge {
private:
    std::string edge_type;
    std::map<std::string, std::string> attrs;
public:
    ChildNodeEdge(std::string t, std::map<std::string, std::string> a)
        : edge_type(std::move(t)), attrs(std::move(a)) {}
    friend std::ostream& operator<<(std::ostream& os, const ChildNodeEdge& e) {
        os << "边[类型:" << e.edge_type << ", 属性:{";
        for (auto it = e.attrs.begin(); it != e.attrs.end(); ++it) {
            if (it != e.attrs.begin()) os << ",";
            os << it->first << "=" << it->second;
        }
        os << "}]";
        return os;
    }
};

// 图类型定义
using VehicleGraph = boost::adjacency_list<
    boost::vecS, boost::vecS, boost::undirectedS,
    VehicleVertex, ChildNodeEdge
>;

int main() {
    // 解析XML
    ptree pt;
    std::ifstream ifs("input.xml");
    read_xml(ifs, pt);

    VehicleGraph g;
    std::map<std::string, VehicleGraph::vertex_descriptor> func_vertex_map;

    // 初始化功能中心顶点
    func_vertex_map["spec"] = boost::add_vertex(
        VehicleVertex("feature", "spec", "中心节点"), g
    );
    func_vertex_map["additions"] = boost::add_vertex(
        VehicleVertex("feature", "additions", "中心节点"), g
    );
    func_vertex_map["utilities"] = boost::add_vertex(
        VehicleVertex("feature", "utilities", "中心节点"), g
    );

    // 解析car节点为顶点
    for (auto& [key, node] : pt.get_child("root.type.cars")) {
        if (key != "car") continue;
        std::string name = node.get<std::string>("<xmlattr>.name");
        std::string weight = node.get<std::string>("<xmlattr>.weight");
        auto vd = boost::add_vertex(VehicleVertex("car", name, "weight=" + weight), g);

        // 遍历该car的子节点生成边
        for (auto& [child_key, child_node] : node) {
            if (!func_vertex_map.count(child_key)) continue;
            // 收集子节点的所有属性
            std::map<std::string, std::string> attrs;
            for (auto& [attr_key, attr_val] : child_node.get_child("<xmlattr>")) {
                attrs[attr_key] = attr_val.data();
            }
            // 添加边
            boost::add_edge(vd, func_vertex_map[child_key],
                ChildNodeEdge(child_key, attrs), g
            );
        }
    }

    // 解析plane节点为顶点
    for (auto& [key, node] : pt.get_child("root.type.planes")) {
        if (key != "plane") continue;
        std::string name = node.get<std::string>("<xmlattr>.name");
        std::string id = node.get<std::string>("<xmlattr>.id");
        auto vd = boost::add_vertex(VehicleVertex("plane", name, "id=" + id), g);

        // 遍历该plane的子节点生成边
        for (auto& [child_key, child_node] : node) {
            if (!func_vertex_map.count(child_key)) continue;
            std::map<std::string, std::string> attrs;
            for (auto& [attr_key, attr_val] : child_node.get_child("<xmlattr>")) {
                attrs[attr_key] = attr_val.data();
            }
            boost::add_edge(vd, func_vertex_map[child_key],
                ChildNodeEdge(child_key, attrs), g
            );
        }
    }

    // 遍历打印图的内容
    std::cout << "=== 图顶点列表 ===" << std::endl;
    for (auto v : boost::vertices(g)) {
        std::cout << "顶点ID " << v << ": " << g[v] << std::endl;
    }
    std::cout << "\n=== 图边列表 ===" << std::endl;
    for (auto [ed, end] = boost::edges(g); ed != end; ++ed) {
        auto u = boost::source(*ed, g);
        auto v = boost::target(*ed, g);
        std::cout << g[u] << " <-> " << g[v] << " | " << g[*ed] << std::endl;
    }

    return 0;
}

代码适配说明:

  • 完全移除了原代码中硬编码的结构体定义,所有数据存储通过类实现
  • 保留了原有的XML解析逻辑,没有修改Boost.PropertyTree的解析接口
  • 图结构为标准BGL无向图,所有属性直接绑定到图内部存储,支持后续直接调用BGL的图算法接口

内容的提问来源于stack exchange,提问作者user12061536

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.03 07:15:00