使用boost::Write_graphml在xml中写入/读取项向量

使用boost::Write_graphml在xml中写入/读取项向量,boost,Boost,我有一个邻接列表是boost::邻接列表 其中GraphData是包含名称的结构 struct GraphData { std::string Divison; std::vector<std::pair<std::string, int>> studentInfo; // Student info contains Name and age // Note I don't want to use anyother stucture

我有一个邻接列表是boost::邻接列表 其中GraphData是包含名称的结构

struct GraphData
{
     std::string Divison;
     std::vector<std::pair<std::string, int>> studentInfo;
     // Student info contains Name and age
     // Note I don't want to use anyother stucture inside GraphItem
}
对此,我有以下回应:

几种方法

不透明成员对象 一种方法是将
student
属性与
Name
财产:

dp.property("Name", boost::get(&GraphData::Name, graph));
dp.property("Student", boost::get(&GraphData::student, graph));
所需的只是告诉标准库如何进行流式处理
学生
对象:

inline static std::ostream& operator<<(std::ostream& os, Student const& s) {
    return os << s.roll_no << " " << std::quoted(s.division);
}
inline static std::istream& operator>>(std::istream& is, Student& s) {
    return is >> s.roll_no >> std::ws >> std::quoted(s.division);
}
获取(&GraphData::student,graph)); dp.property(“division”,boost::make_transform\u value\u property\u map(division, 获取(&GraphData::student,graph))

请注意,出于读取目的,需要左值属性映射,因此 需要写得稍微宽松一点:

Graph ReadGraph(std::string const &fileName) {
    Graph graph;
    boost::dynamic_properties dp;
    auto roll_no =  [](Student& s) ->auto& { return s.roll_no; };
    auto division = [](Student& s) ->auto& { return s.division; };

    dp.property("Name", get(&GraphData::Name, graph));
    dp.property("roll_no", boost::make_transform_value_property_map(roll_no,
获取(&GraphData::student,graph)); dp.property(“division”,boost::make_transform\u value\u property\u map(division, 获取(&GraphData::student,graph))

现在,您将获得类似于的XML


菲洛曼格林卡
科学
3.
菲洛梅娜·普里特
炼金术
84
约翰·哈巴库克
炼金术
19
欧内斯特·哈巴库克
哲学
31
约翰·布格隆
科学
44

简化 您可以不使用lambdas和 使用
std::mem\u fn
写/读走开:

static inline boost::dynamic_properties DynProps(Graph& g) {
    boost::dynamic_properties dp;

    dp.property("Name", get(&GraphData::Name, g));

    auto student = get(&GraphData::student, g);
    dp.property("roll_no",  make_transform_value_property_map(std::mem_fn(&Student::roll_no), 
学生),; dp.property(“除法”)、make_transform_value_property_map(std::mem_fn(&Student::division), 学生),

可用于
ReadGraph
WriteGraph
,如下所示:

Graph ReadGraph(std::string const &fileName) {
    Graph graph;
    auto dp = DynProps(graph);

    std::ifstream file(fileName);
    boost::read_graphml(file, graph, dp);

    return graph;
}

void WriteGraph(std::ostream &os, Graph &graph) {
    boost::write_graphml(os, graph, DynProps(graph), true);
}
您仍然可以得到相同的XML

完整列表

#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/graph/graphml.hpp>

struct Student {
    int roll_no;
    std::string division;
};

struct GraphData {
    std::string Name;
    Student student;
};

using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, GraphData>;

static inline boost::dynamic_properties DynProps(Graph& g) {
    boost::dynamic_properties dp;

    dp.property("Name", get(&GraphData::Name, g));

    auto student = get(&GraphData::student, g);
    dp.property("roll_no",  make_transform_value_property_map(std::mem_fn(&Student::roll_no), 
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphml.hpp>
#include <iostream>
#include <iomanip>

using StudentInfo = std::vector<std::pair<std::string, int>>;

namespace /*static*/ {
    struct Lit { char ch; };
    static inline std::istream& operator>>(std::istream& is, Lit expected) {
        char actual;
        if (is >> actual && actual != expected.ch)
            is.setstate(std::ios::failbit);
        return is;
    }

    static StudentInfo null_info;

    struct Wrapper {
        StudentInfo& _si;
        Wrapper(StudentInfo& si = null_info) : _si(si) {}
        operator StudentInfo&() const { return _si; }

        friend std::ostream& operator<<(std::ostream& os, const Wrapper sis) {
            for(auto& pair : sis._si)
                os << std::quoted(pair.first) << ", " << pair.second << ';';
            return os;
        }

        friend std::istream& operator>>(std::istream& is, const Wrapper sis) {
            StudentInfo::value_type pair;

            while (is >> std::skipws >> std::quoted(pair.first)) {
                if (is >> Lit{','} >> pair.second >> Lit{';'})
                    sis._si.push_back(pair);
                else 
                    return is; // error here is bad
            }
            if (!is.bad()) // just eof this point is ok
                is.clear();
            return is;
        }
    };

    template <typename T, typename Map> struct CoercePropertyMap : Map {
        CoercePropertyMap(Map map) : Map(map){}
        using value_type = T;
        using reference = T;
    };

    template <typename T, typename Map> 
        CoercePropertyMap<T, Map> coerce_map(Map map) { return map; }
}

struct GraphItem {
    std::string Division;
    StudentInfo studentInfo;
};

using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, GraphItem>;

static inline boost::dynamic_properties DynProps(Graph& g) {
    boost::dynamic_properties dp;

    dp.property("Division", get(&GraphItem::Division, g));
    dp.property("studentInfo", coerce_map<Wrapper>(get(&GraphItem::studentInfo, g)));

    return dp;
}

Graph ReadGraph(std::string const &fileName) {
    Graph graph;
    auto dp = DynProps(graph);

    std::ifstream file(fileName);
    boost::read_graphml(file, graph, dp);

    return graph;
}

void WriteGraph(std::ostream &os, Graph &graph) {
    boost::write_graphml(os, graph, DynProps(graph), true);
}

void WriteGraph(std::string const& fileName, Graph &graph) {
    std::ofstream ofs(fileName);
    WriteGraph(ofs, graph);
}

#include <boost/graph/graph_utility.hpp>

namespace Gen { Graph graph(); } // generate random data

int main() {
    {
        Graph g = Gen::graph();
        WriteGraph("input.txt", g);
    }

    Graph g = ReadGraph("input.txt");
    print_graph(g, get(&GraphItem::Division, g));

    // or as XML
    WriteGraph(std::cout << "==== XML version: ====\n\n", g);
}

/// generate data
#include <boost/graph/random.hpp>
#include <boost/random.hpp>
#include <random>

namespace Gen { 
    namespace {
        namespace R = boost::random;
        R::mt19937 engine {42}; // { std::random_device{}() };

        template <typename Range> auto sample(Range const &from) {
            return *std::next(boost::begin(from), R::uniform_int_distribution<>(1, boost::size(from))(engine) - 1);
        }

        int age() { return R::uniform_int_distribution<>(18, 27)(engine); }

        std::string division() {
            static std::string const d[] = { "science", "drama", "mathematics", "philosophy", "alchemy" };
            return sample(d);
        }

        std::string name() {
            static std::string const f[] = { "John", "Daisy", "Chuck", "Mary-Anne", "Ernest", "Philomena", "Joyce", "James" };
            static std::string const l[] = { "Joyce", "Habakuk", "Hornam", "Bufgloon", "Glinka", "Tarsinck", "Preet" };
            return sample(f) + " " + sample(l);
        }

        StudentInfo studentInfo() {
            StudentInfo si;
            auto const n = R::uniform_int_distribution<>(2,5)(engine);
            for (int i = 0; i < n; ++i) 
                si.emplace_back(name(), age());
            return si;
        }
    }

    Graph graph() {
        Graph g;
        boost::generate_random_graph(g, 5, 7, engine);
        for (auto vd: boost::make_iterator_range(vertices(g)))
            g[vd] = { division(), studentInfo() };
        return g;
    }

} // namespace Gen
注意,下面的代码在姓名和年龄之间添加了“
”,“

现在,出现了一些额外的障碍,因为例如,除非返回的值是可变引用,否则它不是一个左值属性映射

我选择执行一个简单的强制属性映射来“包装”具有包装类型的属性:

template <typename T, typename Map> struct CoercePropertyMap : Map {
    CoercePropertyMap(Map map) : Map(map){}
    using value_type = T;
    using reference = T;
};

template <typename T, typename Map> 
    CoercePropertyMap<T, Map> coerce_map(Map map) { return map; }
模板结构强制属性映射:映射{
强制属性映射(映射映射):映射(映射){}
使用值_type=T;
使用reference=T;
};
模板
强制属性映射强制映射(映射映射){return map;}
现在,我们可以把它们放在一起:

属性(“studentInfo”,强制映射(get(&GraphItem::studentInfo,g))

完整列表

#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/graph/graphml.hpp>

struct Student {
    int roll_no;
    std::string division;
};

struct GraphData {
    std::string Name;
    Student student;
};

using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, GraphData>;

static inline boost::dynamic_properties DynProps(Graph& g) {
    boost::dynamic_properties dp;

    dp.property("Name", get(&GraphData::Name, g));

    auto student = get(&GraphData::student, g);
    dp.property("roll_no",  make_transform_value_property_map(std::mem_fn(&Student::roll_no), 
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphml.hpp>
#include <iostream>
#include <iomanip>

using StudentInfo = std::vector<std::pair<std::string, int>>;

namespace /*static*/ {
    struct Lit { char ch; };
    static inline std::istream& operator>>(std::istream& is, Lit expected) {
        char actual;
        if (is >> actual && actual != expected.ch)
            is.setstate(std::ios::failbit);
        return is;
    }

    static StudentInfo null_info;

    struct Wrapper {
        StudentInfo& _si;
        Wrapper(StudentInfo& si = null_info) : _si(si) {}
        operator StudentInfo&() const { return _si; }

        friend std::ostream& operator<<(std::ostream& os, const Wrapper sis) {
            for(auto& pair : sis._si)
                os << std::quoted(pair.first) << ", " << pair.second << ';';
            return os;
        }

        friend std::istream& operator>>(std::istream& is, const Wrapper sis) {
            StudentInfo::value_type pair;

            while (is >> std::skipws >> std::quoted(pair.first)) {
                if (is >> Lit{','} >> pair.second >> Lit{';'})
                    sis._si.push_back(pair);
                else 
                    return is; // error here is bad
            }
            if (!is.bad()) // just eof this point is ok
                is.clear();
            return is;
        }
    };

    template <typename T, typename Map> struct CoercePropertyMap : Map {
        CoercePropertyMap(Map map) : Map(map){}
        using value_type = T;
        using reference = T;
    };

    template <typename T, typename Map> 
        CoercePropertyMap<T, Map> coerce_map(Map map) { return map; }
}

struct GraphItem {
    std::string Division;
    StudentInfo studentInfo;
};

using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, GraphItem>;

static inline boost::dynamic_properties DynProps(Graph& g) {
    boost::dynamic_properties dp;

    dp.property("Division", get(&GraphItem::Division, g));
    dp.property("studentInfo", coerce_map<Wrapper>(get(&GraphItem::studentInfo, g)));

    return dp;
}

Graph ReadGraph(std::string const &fileName) {
    Graph graph;
    auto dp = DynProps(graph);

    std::ifstream file(fileName);
    boost::read_graphml(file, graph, dp);

    return graph;
}

void WriteGraph(std::ostream &os, Graph &graph) {
    boost::write_graphml(os, graph, DynProps(graph), true);
}

void WriteGraph(std::string const& fileName, Graph &graph) {
    std::ofstream ofs(fileName);
    WriteGraph(ofs, graph);
}

#include <boost/graph/graph_utility.hpp>

namespace Gen { Graph graph(); } // generate random data

int main() {
    {
        Graph g = Gen::graph();
        WriteGraph("input.txt", g);
    }

    Graph g = ReadGraph("input.txt");
    print_graph(g, get(&GraphItem::Division, g));

    // or as XML
    WriteGraph(std::cout << "==== XML version: ====\n\n", g);
}

/// generate data
#include <boost/graph/random.hpp>
#include <boost/random.hpp>
#include <random>

namespace Gen { 
    namespace {
        namespace R = boost::random;
        R::mt19937 engine {42}; // { std::random_device{}() };

        template <typename Range> auto sample(Range const &from) {
            return *std::next(boost::begin(from), R::uniform_int_distribution<>(1, boost::size(from))(engine) - 1);
        }

        int age() { return R::uniform_int_distribution<>(18, 27)(engine); }

        std::string division() {
            static std::string const d[] = { "science", "drama", "mathematics", "philosophy", "alchemy" };
            return sample(d);
        }

        std::string name() {
            static std::string const f[] = { "John", "Daisy", "Chuck", "Mary-Anne", "Ernest", "Philomena", "Joyce", "James" };
            static std::string const l[] = { "Joyce", "Habakuk", "Hornam", "Bufgloon", "Glinka", "Tarsinck", "Preet" };
            return sample(f) + " " + sample(l);
        }

        StudentInfo studentInfo() {
            StudentInfo si;
            auto const n = R::uniform_int_distribution<>(2,5)(engine);
            for (int i = 0; i < n; ++i) 
                si.emplace_back(name(), age());
            return si;
        }
    }

    Graph graph() {
        Graph g;
        boost::generate_random_graph(g, 5, 7, engine);
        for (auto vd: boost::make_iterator_range(vertices(g)))
            g[vd] = { division(), studentInfo() };
        return g;
    }

} // namespace Gen
#包括
#包括
#包括
#包括
使用StudentInfo=std::vector;
名称空间/*静态*/{
结构Lit{char ch;};
静态内联std::istream&operator>>(std::istream&is,预期点亮){
实际字符;
如果(is>>实际值和&实际值!=expected.ch)
is.setstate(std::ios::failbit);
回报是;
}
静态StudentInfo null\u信息;
结构包装器{
学生资讯&(u si);
包装器(StudentInfo&si=null\u-info):\u-si(si){}
运算符StudentInfo&()常量{return\u si;}
friend std::ostream&operator std::quoted(成对优先)){
如果(是>>点亮{','}>>配对秒>>点亮{';'})
sis.向后推(成对);
其他的
return是;//这里的错误是错误的
}
如果(!is.bad())//这一点的eof是正确的
is.clear();
回报是;
}
};
模板结构强制属性映射:映射{
强制属性映射(映射映射):映射(映射){}
使用值_type=T;
使用reference=T;
};
模板
强制属性映射强制映射(映射映射){return map;}
}
结构石墨{
std::字符串除法;
学生信息学生信息;
};
使用Graph=boost::邻接列表;
静态内联boost::动态_属性DynProps(图形和g){
boost::动态_属性dp;
dp.property(“Division”,get(&GraphItem::Division,g));
属性(“studentInfo”,强制映射(get(&GraphItem::studentInfo,g));
返回dp;
}
Graph ReadGraph(标准::字符串常量和文件名){
图形;
自动dp=DynProps(图形);
std::ifstream文件(文件名);
boost::read_graphml(文件、图形、dp);
返回图;
}
void WriteGraph(std::ostream&os、Graph&Graph){
boost::write_graphml(操作系统,图形,动态操作(图形),true);
}
void WriteGraph(标准::字符串常量和文件名、图形和图形){
std::ofs流(文件名);
书写图(ofs,图形);
}
#包括
命名空间Gen{Graph Graph();}//生成随机数据
int main(){
{
图g=Gen::Graph();
WriteGraph(“input.txt”,g);
}
图g=ReadGraph(“input.txt”);
print_图(g,get(&GraphItem::Division,g));
//或者作为XML
写剧本
戏剧-->数学
戏剧哲学
数学哲学剧
戏剧-->哲学戏剧
==XML版本:====
哲学
“詹姆斯·乔伊斯”,18岁;“詹姆斯·塔辛克”,25岁;“黛西·乔伊斯”,20岁;“欧内斯特·哈巴库克”,27岁;
戏剧
“詹姆斯·乔伊斯”,18岁;“詹姆斯·塔辛克”,25岁;“黛西·乔伊斯”,20岁;“欧内斯特·哈巴库克”,27岁;“玛丽·安妮·乔伊斯”,23岁;“欧内斯特·霍纳姆”,18岁;“黛西·霍纳姆”,24岁;“詹姆斯·霍纳姆”,18岁;
戏剧
“詹姆斯·乔伊斯”,18岁;“詹姆斯·塔辛克”,25岁;“黛西·乔伊斯”,20岁;“欧内斯特·哈巴库克”,27岁;“玛丽·安妮·乔伊斯”,23岁;“欧内斯特·霍纳姆”,18岁;“黛西·霍纳姆”,24岁;“詹姆斯·霍纳姆”,18岁;“乔伊斯·乔伊斯”,22岁;“玛丽·安妮·哈巴库克”,24岁;
数学
“詹姆斯·乔伊斯”,18岁;“詹姆斯·塔辛克”,25岁;“黛西·乔伊斯”,20岁;“欧内斯特·哈巴库克”,27岁;“玛丽·安妮·乔伊斯”,23岁;“欧内斯特·霍纳姆”,18岁;“黛西·霍纳姆”,24岁;“詹姆斯·霍纳姆”,18岁;“乔伊斯·乔伊斯”,22岁;“玛丽·安妮·哈巴库克”,24岁;“约翰·布格隆”,23岁;“菲洛曼娜·格林卡”,26岁;“约翰·布格”
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/graph/graphml.hpp>

struct Student {
    int roll_no;
    std::string division;
};

struct GraphData {
    std::string Name;
    Student student;
};

using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, GraphData>;

static inline boost::dynamic_properties DynProps(Graph& g) {
    boost::dynamic_properties dp;

    dp.property("Name", get(&GraphData::Name, g));

    auto student = get(&GraphData::student, g);
    dp.property("roll_no",  make_transform_value_property_map(std::mem_fn(&Student::roll_no), 
    return dp;
}

Graph ReadGraph(std::string const &fileName) {
    Graph graph;
    auto dp = DynProps(graph);

    std::ifstream file(fileName);
    boost::read_graphml(file, graph, dp);

    return graph;
}

void WriteGraph(std::ostream &os, Graph &graph) {
    boost::write_graphml(os, graph, DynProps(graph), true);
}

void WriteGraph(std::string const& fileName, Graph &graph) {
    std::ofstream ofs(fileName);
    WriteGraph(ofs, graph);
}

#include <boost/graph/graph_utility.hpp>

namespace Gen { Graph graph(); } // generate random data

int main() {
    {
        Graph g = Gen::graph();
        WriteGraph("input.txt", g);
    }

    Graph g = ReadGraph("input.txt");
    print_graph(g, get(&GraphData::Name, g));

    // or as XML
    WriteGraph(std::cout << "==== XML version: ====\n\n", g);
}

/// generate data
#include <boost/graph/random.hpp>
#include <boost/random.hpp>
#include <random>

namespace Gen { 
    namespace {
        namespace R = boost::random;
        R::mt19937 engine {42}; // { std::random_device{}() };

        template <typename Range> auto sample(Range const &from) {
            return *std::next(boost::begin(from), R::uniform_int_distribution<>(1, boost::size(from))(engine) - 1);
        }

        int roll() { return R::uniform_int_distribution<>(1, 100)(engine); }

        std::string division() {
            static std::string const d[] = { "science", "drama", "mathematics", "philosophy", "alchemy" };
            return sample(d);
        }

        std::string name() {
            static std::string const f[] = { "John", "Daisy", "Chuck", "Mary-Anne", "Ernest", "Philomena", "Joyce", "James" };
            static std::string const l[] = { "Joyce", "Habakuk", "Hornam", "Bufgloon", "Glinka", "Tarsinck", "Preet" };
            return sample(f) + " " + sample(l);
        }

        Student student() { return { roll(), division() }; }
    }

    Graph graph() {
        Graph g;
        boost::generate_random_graph(g, 5, 7, engine);
        for (auto vd: boost::make_iterator_range(vertices(g)))
            g[vd] = { name(), student() };
        return g;
    }

} // namespace Gen
using StudentInfo = std::vector<std::pair<std::string, int>>;

struct Wrapper {
    StudentInfo& _si;

    friend std::ostream& operator<<(std::ostream& os, const Wrapper sis) {
        for(auto& pair : sis._si)
            os << std::quoted(pair.first) << pair.second << ';';
        return os;
    }

    friend std::istream& operator>>(std::istream& is, const Wrapper sis) {
        StudentInfo::value_type pair;
        while (is >> std::quoted(pair.first)) {
            char ch;
            if (is >> pair.second >> ch && ch == ';')
                sis._si.push_back(pair);
            else 
                return is;
        }
        if (!is.bad()) // eof this point is ok
            is.clear();
        return is;
    }
};
template <typename T, typename Map> struct CoercePropertyMap : Map {
    CoercePropertyMap(Map map) : Map(map){}
    using value_type = T;
    using reference = T;
};

template <typename T, typename Map> 
    CoercePropertyMap<T, Map> coerce_map(Map map) { return map; }
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphml.hpp>
#include <iostream>
#include <iomanip>

using StudentInfo = std::vector<std::pair<std::string, int>>;

namespace /*static*/ {
    struct Lit { char ch; };
    static inline std::istream& operator>>(std::istream& is, Lit expected) {
        char actual;
        if (is >> actual && actual != expected.ch)
            is.setstate(std::ios::failbit);
        return is;
    }

    static StudentInfo null_info;

    struct Wrapper {
        StudentInfo& _si;
        Wrapper(StudentInfo& si = null_info) : _si(si) {}
        operator StudentInfo&() const { return _si; }

        friend std::ostream& operator<<(std::ostream& os, const Wrapper sis) {
            for(auto& pair : sis._si)
                os << std::quoted(pair.first) << ", " << pair.second << ';';
            return os;
        }

        friend std::istream& operator>>(std::istream& is, const Wrapper sis) {
            StudentInfo::value_type pair;

            while (is >> std::skipws >> std::quoted(pair.first)) {
                if (is >> Lit{','} >> pair.second >> Lit{';'})
                    sis._si.push_back(pair);
                else 
                    return is; // error here is bad
            }
            if (!is.bad()) // just eof this point is ok
                is.clear();
            return is;
        }
    };

    template <typename T, typename Map> struct CoercePropertyMap : Map {
        CoercePropertyMap(Map map) : Map(map){}
        using value_type = T;
        using reference = T;
    };

    template <typename T, typename Map> 
        CoercePropertyMap<T, Map> coerce_map(Map map) { return map; }
}

struct GraphItem {
    std::string Division;
    StudentInfo studentInfo;
};

using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, GraphItem>;

static inline boost::dynamic_properties DynProps(Graph& g) {
    boost::dynamic_properties dp;

    dp.property("Division", get(&GraphItem::Division, g));
    dp.property("studentInfo", coerce_map<Wrapper>(get(&GraphItem::studentInfo, g)));

    return dp;
}

Graph ReadGraph(std::string const &fileName) {
    Graph graph;
    auto dp = DynProps(graph);

    std::ifstream file(fileName);
    boost::read_graphml(file, graph, dp);

    return graph;
}

void WriteGraph(std::ostream &os, Graph &graph) {
    boost::write_graphml(os, graph, DynProps(graph), true);
}

void WriteGraph(std::string const& fileName, Graph &graph) {
    std::ofstream ofs(fileName);
    WriteGraph(ofs, graph);
}

#include <boost/graph/graph_utility.hpp>

namespace Gen { Graph graph(); } // generate random data

int main() {
    {
        Graph g = Gen::graph();
        WriteGraph("input.txt", g);
    }

    Graph g = ReadGraph("input.txt");
    print_graph(g, get(&GraphItem::Division, g));

    // or as XML
    WriteGraph(std::cout << "==== XML version: ====\n\n", g);
}

/// generate data
#include <boost/graph/random.hpp>
#include <boost/random.hpp>
#include <random>

namespace Gen { 
    namespace {
        namespace R = boost::random;
        R::mt19937 engine {42}; // { std::random_device{}() };

        template <typename Range> auto sample(Range const &from) {
            return *std::next(boost::begin(from), R::uniform_int_distribution<>(1, boost::size(from))(engine) - 1);
        }

        int age() { return R::uniform_int_distribution<>(18, 27)(engine); }

        std::string division() {
            static std::string const d[] = { "science", "drama", "mathematics", "philosophy", "alchemy" };
            return sample(d);
        }

        std::string name() {
            static std::string const f[] = { "John", "Daisy", "Chuck", "Mary-Anne", "Ernest", "Philomena", "Joyce", "James" };
            static std::string const l[] = { "Joyce", "Habakuk", "Hornam", "Bufgloon", "Glinka", "Tarsinck", "Preet" };
            return sample(f) + " " + sample(l);
        }

        StudentInfo studentInfo() {
            StudentInfo si;
            auto const n = R::uniform_int_distribution<>(2,5)(engine);
            for (int i = 0; i < n; ++i) 
                si.emplace_back(name(), age());
            return si;
        }
    }

    Graph graph() {
        Graph g;
        boost::generate_random_graph(g, 5, 7, engine);
        for (auto vd: boost::make_iterator_range(vertices(g)))
            g[vd] = { division(), studentInfo() };
        return g;
    }

} // namespace Gen
philosophy --> drama 
drama --> mathematics 
drama --> philosophy 
mathematics --> philosophy drama 
drama --> philosophy drama 
==== XML version: ====

<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  <key id="key0" for="node" attr.name="Division" attr.type="string" />
  <key id="key1" for="node" attr.name="studentInfo" attr.type="string" />
  <graph id="G" edgedefault="directed" parse.nodeids="canonical" parse.edgeids="canonical" parse.order="nodesfirst">
    <node id="n0">
      <data key="key0">philosophy</data>
      <data key="key1">&quot;James Joyce", 18;"James Tarsinck", 25;"Daisy Joyce", 20;"Ernest Habakuk", 27;</data>
    </node>
    <node id="n1">
      <data key="key0">drama</data>
      <data key="key1">&quot;James Joyce", 18;"James Tarsinck", 25;"Daisy Joyce", 20;"Ernest Habakuk", 27;"Mary-Anne Joyce", 23;"Ernest Hornam", 18;"Daisy Hornam", 24;"James Hornam", 18;</data>
    </node>
    <node id="n2">
      <data key="key0">drama</data>
      <data key="key1">&quot;James Joyce", 18;"James Tarsinck", 25;"Daisy Joyce", 20;"Ernest Habakuk", 27;"Mary-Anne Joyce", 23;"Ernest Hornam", 18;"Daisy Hornam", 24;"James Hornam", 18;"Joyce Joyce", 22;"Mary-Anne Habakuk", 24;</data>
    </node>
    <node id="n3">
      <data key="key0">mathematics</data>
      <data key="key1">&quot;James Joyce", 18;"James Tarsinck", 25;"Daisy Joyce", 20;"Ernest Habakuk", 27;"Mary-Anne Joyce", 23;"Ernest Hornam", 18;"Daisy Hornam", 24;"James Hornam", 18;"Joyce Joyce", 22;"Mary-Anne Habakuk", 24;"John Bufgloon", 23;"Philomena Glinka", 26;"John Bufgloon", 19;"James Preet", 18;"Joyce Bufgloon", 27;</data>
    </node>
    <node id="n4">
      <data key="key0">drama</data>
      <data key="key1">&quot;James Joyce", 18;"James Tarsinck", 25;"Daisy Joyce", 20;"Ernest Habakuk", 27;"Mary-Anne Joyce", 23;"Ernest Hornam", 18;"Daisy Hornam", 24;"James Hornam", 18;"Joyce Joyce", 22;"Mary-Anne Habakuk", 24;"John Bufgloon", 23;"Philomena Glinka", 26;"John Bufgloon", 19;"James Preet", 18;"Joyce Bufgloon", 27;"Daisy Joyce", 18;"Mary-Anne Habakuk", 24;"Ernest Joyce", 24;</data>
    </node>
    <edge id="e0" source="n0" target="n2">
    </edge>
    <edge id="e1" source="n1" target="n3">
    </edge>
    <edge id="e2" source="n2" target="n0">
    </edge>
    <edge id="e3" source="n3" target="n0">
    </edge>
    <edge id="e4" source="n3" target="n2">
    </edge>
    <edge id="e5" source="n4" target="n0">
    </edge>
    <edge id="e6" source="n4" target="n1">
    </edge>
  </graph>
</graphml>