使用boost :: write_graphml在xml中写入/读取项目的向量

时间:2018-03-07 16:29:21

标签: boost

我有一个邻接列表是boost :: adjacency_list 其中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
}

如何使用动态属性读取和写入此学生信息?

void WriteGraph()
{
   boost::dynamic_properties dp;
   dp.property("Division", boost::get(&GraphItem::Division, graph));
   boost::write_graphml(filename, graph, dp, true); 
}

void ReadGraph()
{
   boost::dynamic_properties dp;
   std::ifstream file(fileName);
   boost::read_graphml(file, graph, dp);
}

1 个答案:

答案 0 :(得分:1)

回应the older question我有这个:

  

一些方法

     

不透明的成员对象

     

一种方法是像student一样对待Name属性   属性:

dp.property("Name", boost::get(&GraphData::Name, graph));
dp.property("Student", boost::get(&GraphData::student, graph));
     

所需要的就是告诉标准库如何流式传输   Student个对象:

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);
}
     

您将获得类似 Live On Wandbox 的XML。

     
<?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 =&#34; HTTP://graphml.graphdrawing.org/xmlns   http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd&#34;&GT;                                                   玛丽 - 安妮·霍纳姆             80&#34;炼金术&#34;                                   Mary-Anne Bufgloon             57&#34;戏剧&#34;                                   乔伊斯普雷特             8&#34;戏剧&#34;                                   Philomena Joyce             3&#34;戏剧&#34;                                   詹姆斯塔辛克             78&#34;科学&#34;                                                                                                                                                                                     

     

单独属性

     

如果你真的想要单独的GraphML属性roll_no和   division,然后您返回transform_value_property_map

void WriteGraph(std::ostream &os, Graph &graph) {
    boost::dynamic_properties dp;
    auto roll_no =  [](Student const& s) { return s.roll_no; };
    auto division = [](Student const& s) { return s.division; };

    dp.property("Name", get(&GraphData::Name, graph));
    dp.property("roll_no", boost::make_transform_value_property_map(roll_no,
     

get(&amp; GraphData :: student,graph)));           dp.property(&#34; division&#34;,boost :: make_transform_value_property_map(division,   get(&amp; GraphData :: student,graph)));

    boost::write_graphml(os, graph, dp, true);
}
     

请注意,出于阅读目的,需要LvaluePropertyMap,因此它是必需的   需要写得稍微宽松一点:

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,
     

get(&amp; GraphData :: student,graph)));           dp.property(&#34; division&#34;,boost :: make_transform_value_property_map(division,   get(&amp; GraphData :: student,graph)));

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

    return graph;
}
     

现在,您将获得类似 Live On Wandbox 的XML。

     
<?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 =&#34; HTTP://graphml.graphdrawing.org/xmlns   http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd&#34;&GT;                                                            Philomena Glinka             科学             3                                   Philomena Preet             炼金术             84                                   约翰哈巴库克             炼金术             19                                   欧内斯特·哈巴库克             哲学             31                                   John Bufgloon             科学             44                                                                                                                                                                                     

     

简化

     

你可以不用lambdas和它们之间做出区别   使用std::mem_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(&#34; division&#34;,make_transform_value_property_map(std :: mem_fn(&amp; Student :: division),   学生));

    return dp;
}
     

可用于ReadGraphWriteGraph的内容如下:

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。

     

完整列表

     

<强> Live On Wandbox

#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), 
     

学生));           dp.property(&#34; division&#34;,make_transform_value_property_map(std :: mem_fn(&amp; Student :: division),   学生));

    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

当你有一个矢量会员时

您当前的问题会将vector添加到混音中。这里有相关的帖子:read boost graph (boost::read_graphviz) where vertex contains vector

您可能会operator<< / operator>> std::vector<T>进入ADL陷阱。

如果上述内容尚未解决您遇到的问题,我今晚稍后会添加一个演示。

示范

这比我希望的要复杂,因为在命名空间operator<<内重载operator>> / ::std只是品味不佳,所以我们需要一个包装类型:

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;
    }
};
  

注意,下面的代码会在名称和年龄之间添加", "

现在,出现了一些额外的障碍,例如TransformValuePropertyMap不是LValuePropertyMap,除非返回的值是可变引用。

我选择做一个简单的CoercePropertyMap来&#34; wrap&#34;包装类型的属性:

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; }

现在,我们可以把它们放在一起:

dp.property(&#34; studentInfo&#34;,coerce_map(get(&amp; GraphItem :: studentInfo,g)));

完整列表

<强> Live On Wandbox

#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>