Chris@16
|
1 // Copyright (C) 2006 Tiago de Paula Peixoto <tiago@forked.de>
|
Chris@16
|
2 // Copyright (C) 2004 The Trustees of Indiana University.
|
Chris@16
|
3 //
|
Chris@16
|
4 // Use, modification and distribution is subject to the Boost Software
|
Chris@16
|
5 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
6 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
7 //
|
Chris@16
|
8 // Authors: Douglas Gregor
|
Chris@16
|
9 // Andrew Lumsdaine
|
Chris@16
|
10 // Tiago de Paula Peixoto
|
Chris@16
|
11
|
Chris@16
|
12 #ifndef BOOST_GRAPH_GRAPHML_HPP
|
Chris@16
|
13 #define BOOST_GRAPH_GRAPHML_HPP
|
Chris@16
|
14
|
Chris@16
|
15 #include <boost/config.hpp>
|
Chris@16
|
16 #include <boost/lexical_cast.hpp>
|
Chris@16
|
17 #include <boost/any.hpp>
|
Chris@16
|
18 #include <boost/type_traits/is_convertible.hpp>
|
Chris@16
|
19 #include <boost/graph/dll_import_export.hpp>
|
Chris@16
|
20 #include <boost/graph/graphviz.hpp> // for exceptions
|
Chris@16
|
21 #include <typeinfo>
|
Chris@16
|
22 #include <boost/mpl/bool.hpp>
|
Chris@16
|
23 #include <boost/mpl/vector.hpp>
|
Chris@16
|
24 #include <boost/mpl/find.hpp>
|
Chris@16
|
25 #include <boost/mpl/for_each.hpp>
|
Chris@16
|
26 #include <boost/property_tree/detail/xml_parser_utils.hpp>
|
Chris@16
|
27 #include <boost/throw_exception.hpp>
|
Chris@16
|
28 #include <exception>
|
Chris@16
|
29 #include <sstream>
|
Chris@16
|
30
|
Chris@16
|
31 namespace boost
|
Chris@16
|
32 {
|
Chris@16
|
33
|
Chris@16
|
34 /////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
35 // Graph reader exceptions
|
Chris@16
|
36 /////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
37 struct parse_error: public graph_exception
|
Chris@16
|
38 {
|
Chris@16
|
39 parse_error(const std::string& err) {error = err; statement = "parse error: " + error;}
|
Chris@16
|
40 virtual ~parse_error() throw() {}
|
Chris@16
|
41 virtual const char* what() const throw() {return statement.c_str();}
|
Chris@16
|
42 std::string statement;
|
Chris@16
|
43 std::string error;
|
Chris@16
|
44 };
|
Chris@16
|
45
|
Chris@16
|
46
|
Chris@16
|
47 class mutate_graph
|
Chris@16
|
48 {
|
Chris@16
|
49 public:
|
Chris@16
|
50 virtual ~mutate_graph() {}
|
Chris@16
|
51 virtual bool is_directed() const = 0;
|
Chris@16
|
52
|
Chris@16
|
53 virtual boost::any do_add_vertex() = 0;
|
Chris@16
|
54 virtual std::pair<boost::any,bool> do_add_edge(boost::any source, boost::any target) = 0;
|
Chris@16
|
55
|
Chris@16
|
56 virtual void
|
Chris@16
|
57 set_graph_property(const std::string& name, const std::string& value, const std::string& value_type) = 0;
|
Chris@16
|
58
|
Chris@16
|
59 virtual void
|
Chris@16
|
60 set_vertex_property(const std::string& name, boost::any vertex, const std::string& value, const std::string& value_type) = 0;
|
Chris@16
|
61
|
Chris@16
|
62 virtual void
|
Chris@16
|
63 set_edge_property(const std::string& name, boost::any edge, const std::string& value, const std::string& value_type) = 0;
|
Chris@16
|
64 };
|
Chris@16
|
65
|
Chris@16
|
66 template<typename MutableGraph>
|
Chris@16
|
67 class mutate_graph_impl : public mutate_graph
|
Chris@16
|
68 {
|
Chris@16
|
69 typedef typename graph_traits<MutableGraph>::vertex_descriptor vertex_descriptor;
|
Chris@16
|
70 typedef typename graph_traits<MutableGraph>::edge_descriptor edge_descriptor;
|
Chris@16
|
71
|
Chris@16
|
72 public:
|
Chris@16
|
73 mutate_graph_impl(MutableGraph& g, dynamic_properties& dp)
|
Chris@16
|
74 : m_g(g), m_dp(dp) { }
|
Chris@16
|
75
|
Chris@16
|
76 bool is_directed() const
|
Chris@16
|
77 {
|
Chris@16
|
78 return is_convertible<typename graph_traits<MutableGraph>::directed_category,
|
Chris@16
|
79 directed_tag>::value;
|
Chris@16
|
80 }
|
Chris@16
|
81
|
Chris@16
|
82 virtual any do_add_vertex()
|
Chris@16
|
83 {
|
Chris@16
|
84 return any(add_vertex(m_g));
|
Chris@16
|
85 }
|
Chris@16
|
86
|
Chris@16
|
87 virtual std::pair<any,bool> do_add_edge(any source, any target)
|
Chris@16
|
88 {
|
Chris@16
|
89 std::pair<edge_descriptor,bool> retval = add_edge(any_cast<vertex_descriptor>(source),
|
Chris@16
|
90 any_cast<vertex_descriptor>(target), m_g);
|
Chris@16
|
91 return std::make_pair(any(retval.first), retval.second);
|
Chris@16
|
92 }
|
Chris@16
|
93
|
Chris@16
|
94 virtual void
|
Chris@16
|
95 set_graph_property(const std::string& name, const std::string& value, const std::string& value_type)
|
Chris@16
|
96 {
|
Chris@16
|
97 bool type_found = false;
|
Chris@16
|
98 try
|
Chris@16
|
99 {
|
Chris@16
|
100 mpl::for_each<value_types>(put_property<MutableGraph,value_types>
|
Chris@16
|
101 (name, m_dp, m_g, value, value_type, m_type_names, type_found));
|
Chris@16
|
102 }
|
Chris@16
|
103 catch (bad_lexical_cast)
|
Chris@16
|
104 {
|
Chris@16
|
105 BOOST_THROW_EXCEPTION(
|
Chris@16
|
106 parse_error("invalid value \"" + value + "\" for key " +
|
Chris@16
|
107 name + " of type " + value_type));
|
Chris@16
|
108 }
|
Chris@16
|
109 if (!type_found)
|
Chris@16
|
110 {
|
Chris@16
|
111 BOOST_THROW_EXCEPTION(
|
Chris@16
|
112 parse_error("unrecognized type \"" + value_type +
|
Chris@16
|
113 "\" for key " + name));
|
Chris@16
|
114 }
|
Chris@16
|
115
|
Chris@16
|
116 }
|
Chris@16
|
117
|
Chris@16
|
118 virtual void
|
Chris@16
|
119 set_vertex_property(const std::string& name, any vertex, const std::string& value, const std::string& value_type)
|
Chris@16
|
120 {
|
Chris@16
|
121 bool type_found = false;
|
Chris@16
|
122 try
|
Chris@16
|
123 {
|
Chris@16
|
124 mpl::for_each<value_types>(put_property<vertex_descriptor,value_types>
|
Chris@16
|
125 (name, m_dp, any_cast<vertex_descriptor>(vertex),
|
Chris@16
|
126 value, value_type, m_type_names, type_found));
|
Chris@16
|
127 }
|
Chris@16
|
128 catch (bad_lexical_cast)
|
Chris@16
|
129 {
|
Chris@16
|
130 BOOST_THROW_EXCEPTION(
|
Chris@16
|
131 parse_error("invalid value \"" + value + "\" for key " +
|
Chris@16
|
132 name + " of type " + value_type));
|
Chris@16
|
133 }
|
Chris@16
|
134 if (!type_found)
|
Chris@16
|
135 {
|
Chris@16
|
136 BOOST_THROW_EXCEPTION(
|
Chris@16
|
137 parse_error("unrecognized type \"" + value_type +
|
Chris@16
|
138 "\" for key " + name));
|
Chris@16
|
139 }
|
Chris@16
|
140
|
Chris@16
|
141 }
|
Chris@16
|
142
|
Chris@16
|
143 virtual void
|
Chris@16
|
144 set_edge_property(const std::string& name, any edge, const std::string& value, const std::string& value_type)
|
Chris@16
|
145 {
|
Chris@16
|
146 bool type_found = false;
|
Chris@16
|
147 try
|
Chris@16
|
148 {
|
Chris@16
|
149 mpl::for_each<value_types>(put_property<edge_descriptor,value_types>
|
Chris@16
|
150 (name, m_dp, any_cast<edge_descriptor>(edge),
|
Chris@16
|
151 value, value_type, m_type_names, type_found));
|
Chris@16
|
152 }
|
Chris@16
|
153 catch (bad_lexical_cast)
|
Chris@16
|
154 {
|
Chris@16
|
155 BOOST_THROW_EXCEPTION(
|
Chris@16
|
156 parse_error("invalid value \"" + value + "\" for key " +
|
Chris@16
|
157 name + " of type " + value_type));
|
Chris@16
|
158 }
|
Chris@16
|
159 if (!type_found)
|
Chris@16
|
160 {
|
Chris@16
|
161 BOOST_THROW_EXCEPTION(
|
Chris@16
|
162 parse_error("unrecognized type \"" + value_type +
|
Chris@16
|
163 "\" for key " + name));
|
Chris@16
|
164 }
|
Chris@16
|
165 }
|
Chris@16
|
166
|
Chris@16
|
167 template <typename Key, typename ValueVector>
|
Chris@16
|
168 class put_property
|
Chris@16
|
169 {
|
Chris@16
|
170 public:
|
Chris@16
|
171 put_property(const std::string& name, dynamic_properties& dp, const Key& key,
|
Chris@16
|
172 const std::string& value, const std::string& value_type,
|
Chris@16
|
173 const char** type_names, bool& type_found)
|
Chris@16
|
174 : m_name(name), m_dp(dp), m_key(key), m_value(value),
|
Chris@16
|
175 m_value_type(value_type), m_type_names(type_names),
|
Chris@16
|
176 m_type_found(type_found) {}
|
Chris@16
|
177 template <class Value>
|
Chris@16
|
178 void operator()(Value)
|
Chris@16
|
179 {
|
Chris@16
|
180 if (m_value_type == m_type_names[mpl::find<ValueVector,Value>::type::pos::value])
|
Chris@16
|
181 {
|
Chris@16
|
182 put(m_name, m_dp, m_key, lexical_cast<Value>(m_value));
|
Chris@16
|
183 m_type_found = true;
|
Chris@16
|
184 }
|
Chris@16
|
185 }
|
Chris@16
|
186 private:
|
Chris@16
|
187 const std::string& m_name;
|
Chris@16
|
188 dynamic_properties& m_dp;
|
Chris@16
|
189 const Key& m_key;
|
Chris@16
|
190 const std::string& m_value;
|
Chris@16
|
191 const std::string& m_value_type;
|
Chris@16
|
192 const char** m_type_names;
|
Chris@16
|
193 bool& m_type_found;
|
Chris@16
|
194 };
|
Chris@16
|
195
|
Chris@16
|
196 protected:
|
Chris@16
|
197 MutableGraph& m_g;
|
Chris@16
|
198 dynamic_properties& m_dp;
|
Chris@16
|
199 typedef mpl::vector<bool, int, long, float, double, std::string> value_types;
|
Chris@16
|
200 static const char* m_type_names[];
|
Chris@16
|
201 };
|
Chris@16
|
202
|
Chris@16
|
203 template<typename MutableGraph>
|
Chris@16
|
204 const char* mutate_graph_impl<MutableGraph>::m_type_names[] = {"boolean", "int", "long", "float", "double", "string"};
|
Chris@16
|
205
|
Chris@16
|
206 void BOOST_GRAPH_DECL
|
Chris@16
|
207 read_graphml(std::istream& in, mutate_graph& g, size_t desired_idx);
|
Chris@16
|
208
|
Chris@16
|
209 template<typename MutableGraph>
|
Chris@16
|
210 void
|
Chris@16
|
211 read_graphml(std::istream& in, MutableGraph& g, dynamic_properties& dp, size_t desired_idx = 0)
|
Chris@16
|
212 {
|
Chris@16
|
213 mutate_graph_impl<MutableGraph> mg(g,dp);
|
Chris@16
|
214 read_graphml(in, mg, desired_idx);
|
Chris@16
|
215 }
|
Chris@16
|
216
|
Chris@16
|
217 template <typename Types>
|
Chris@16
|
218 class get_type_name
|
Chris@16
|
219 {
|
Chris@16
|
220 public:
|
Chris@16
|
221 get_type_name(const std::type_info& type, const char** type_names, std::string& type_name)
|
Chris@16
|
222 : m_type(type), m_type_names(type_names), m_type_name(type_name) {}
|
Chris@16
|
223 template <typename Type>
|
Chris@16
|
224 void operator()(Type)
|
Chris@16
|
225 {
|
Chris@16
|
226 if (typeid(Type) == m_type)
|
Chris@16
|
227 m_type_name = m_type_names[mpl::find<Types,Type>::type::pos::value];
|
Chris@16
|
228 }
|
Chris@16
|
229 private:
|
Chris@16
|
230 const std::type_info &m_type;
|
Chris@16
|
231 const char** m_type_names;
|
Chris@16
|
232 std::string &m_type_name;
|
Chris@16
|
233 };
|
Chris@16
|
234
|
Chris@16
|
235
|
Chris@16
|
236 template <typename Graph, typename VertexIndexMap>
|
Chris@16
|
237 void
|
Chris@16
|
238 write_graphml(std::ostream& out, const Graph& g, VertexIndexMap vertex_index,
|
Chris@16
|
239 const dynamic_properties& dp, bool ordered_vertices=false)
|
Chris@16
|
240 {
|
Chris@16
|
241 typedef typename graph_traits<Graph>::directed_category directed_category;
|
Chris@16
|
242 typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
Chris@16
|
243 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
Chris@16
|
244
|
Chris@16
|
245 using boost::property_tree::xml_parser::encode_char_entities;
|
Chris@16
|
246
|
Chris@16
|
247 BOOST_STATIC_CONSTANT(bool,
|
Chris@16
|
248 graph_is_directed =
|
Chris@16
|
249 (is_convertible<directed_category*, directed_tag*>::value));
|
Chris@16
|
250
|
Chris@16
|
251 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
Chris@16
|
252 << "<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\">\n";
|
Chris@16
|
253
|
Chris@16
|
254 typedef mpl::vector<bool, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, float, double, long double, std::string> value_types;
|
Chris@16
|
255 const char* type_names[] = {"boolean", "int", "int", "int", "int", "long", "long", "long", "long", "float", "double", "double", "string"};
|
Chris@16
|
256 std::map<std::string, std::string> graph_key_ids;
|
Chris@16
|
257 std::map<std::string, std::string> vertex_key_ids;
|
Chris@16
|
258 std::map<std::string, std::string> edge_key_ids;
|
Chris@16
|
259 int key_count = 0;
|
Chris@16
|
260
|
Chris@16
|
261 // Output keys
|
Chris@16
|
262 for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i)
|
Chris@16
|
263 {
|
Chris@16
|
264 std::string key_id = "key" + lexical_cast<std::string>(key_count++);
|
Chris@16
|
265 if (i->second->key() == typeid(Graph*))
|
Chris@16
|
266 graph_key_ids[i->first] = key_id;
|
Chris@16
|
267 else if (i->second->key() == typeid(vertex_descriptor))
|
Chris@16
|
268 vertex_key_ids[i->first] = key_id;
|
Chris@16
|
269 else if (i->second->key() == typeid(edge_descriptor))
|
Chris@16
|
270 edge_key_ids[i->first] = key_id;
|
Chris@16
|
271 else
|
Chris@16
|
272 continue;
|
Chris@16
|
273 std::string type_name = "string";
|
Chris@16
|
274 mpl::for_each<value_types>(get_type_name<value_types>(i->second->value(), type_names, type_name));
|
Chris@16
|
275 out << " <key id=\"" << encode_char_entities(key_id) << "\" for=\""
|
Chris@16
|
276 << (i->second->key() == typeid(Graph*) ? "graph" : (i->second->key() == typeid(vertex_descriptor) ? "node" : "edge")) << "\""
|
Chris@16
|
277 << " attr.name=\"" << i->first << "\""
|
Chris@16
|
278 << " attr.type=\"" << type_name << "\""
|
Chris@16
|
279 << " />\n";
|
Chris@16
|
280 }
|
Chris@16
|
281
|
Chris@16
|
282 out << " <graph id=\"G\" edgedefault=\""
|
Chris@16
|
283 << (graph_is_directed ? "directed" : "undirected") << "\""
|
Chris@16
|
284 << " parse.nodeids=\"" << (ordered_vertices ? "canonical" : "free") << "\""
|
Chris@16
|
285 << " parse.edgeids=\"canonical\" parse.order=\"nodesfirst\">\n";
|
Chris@16
|
286
|
Chris@16
|
287 // Output graph data
|
Chris@16
|
288 for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i)
|
Chris@16
|
289 {
|
Chris@16
|
290 if (i->second->key() == typeid(Graph*))
|
Chris@16
|
291 {
|
Chris@16
|
292 // The const_cast here is just to get typeid correct for property
|
Chris@16
|
293 // map key; the graph should not be mutated using it.
|
Chris@16
|
294 out << " <data key=\"" << graph_key_ids[i->first] << "\">"
|
Chris@16
|
295 << encode_char_entities(i->second->get_string(const_cast<Graph*>(&g))) << "</data>\n";
|
Chris@16
|
296 }
|
Chris@16
|
297 }
|
Chris@16
|
298
|
Chris@16
|
299 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
|
Chris@16
|
300 vertex_iterator v, v_end;
|
Chris@16
|
301 for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v)
|
Chris@16
|
302 {
|
Chris@16
|
303 out << " <node id=\"n" << get(vertex_index, *v) << "\">\n";
|
Chris@16
|
304 // Output data
|
Chris@16
|
305 for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i)
|
Chris@16
|
306 {
|
Chris@16
|
307 if (i->second->key() == typeid(vertex_descriptor))
|
Chris@16
|
308 {
|
Chris@16
|
309 out << " <data key=\"" << vertex_key_ids[i->first] << "\">"
|
Chris@16
|
310 << encode_char_entities(i->second->get_string(*v)) << "</data>\n";
|
Chris@16
|
311 }
|
Chris@16
|
312 }
|
Chris@16
|
313 out << " </node>\n";
|
Chris@16
|
314 }
|
Chris@16
|
315
|
Chris@16
|
316 typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
|
Chris@16
|
317 edge_iterator e, e_end;
|
Chris@16
|
318 typename graph_traits<Graph>::edges_size_type edge_count = 0;
|
Chris@16
|
319 for (boost::tie(e, e_end) = edges(g); e != e_end; ++e)
|
Chris@16
|
320 {
|
Chris@16
|
321 out << " <edge id=\"e" << edge_count++ << "\" source=\"n"
|
Chris@16
|
322 << get(vertex_index, source(*e, g)) << "\" target=\"n"
|
Chris@16
|
323 << get(vertex_index, target(*e, g)) << "\">\n";
|
Chris@16
|
324
|
Chris@16
|
325 // Output data
|
Chris@16
|
326 for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i)
|
Chris@16
|
327 {
|
Chris@16
|
328 if (i->second->key() == typeid(edge_descriptor))
|
Chris@16
|
329 {
|
Chris@16
|
330 out << " <data key=\"" << edge_key_ids[i->first] << "\">"
|
Chris@16
|
331 << encode_char_entities(i->second->get_string(*e)) << "</data>\n";
|
Chris@16
|
332 }
|
Chris@16
|
333 }
|
Chris@16
|
334 out << " </edge>\n";
|
Chris@16
|
335 }
|
Chris@16
|
336
|
Chris@16
|
337 out << " </graph>\n"
|
Chris@16
|
338 << "</graphml>\n";
|
Chris@16
|
339 }
|
Chris@16
|
340
|
Chris@16
|
341
|
Chris@16
|
342 template <typename Graph>
|
Chris@16
|
343 void
|
Chris@16
|
344 write_graphml(std::ostream& out, const Graph& g, const dynamic_properties& dp,
|
Chris@16
|
345 bool ordered_vertices=false)
|
Chris@16
|
346 {
|
Chris@16
|
347 write_graphml(out, g, get(vertex_index, g), dp, ordered_vertices);
|
Chris@16
|
348 }
|
Chris@16
|
349
|
Chris@16
|
350 } // boost namespace
|
Chris@16
|
351
|
Chris@16
|
352 #endif // BOOST_GRAPH_GRAPHML_HPP
|