1 // Copyright (C) 2006 Tiago de Paula Peixoto <tiago@forked.de>
2 // Copyright (C) 2004 The Trustees of Indiana University.
4 // Use, modification and distribution is subject to the Boost Software
5 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
8 // Authors: Douglas Gregor
10 // Tiago de Paula Peixoto
12 #ifndef BOOST_GRAPH_GRAPHML_HPP
13 #define BOOST_GRAPH_GRAPHML_HPP
15 #include <boost/config.hpp>
16 #include <boost/lexical_cast.hpp>
17 #include <boost/any.hpp>
18 #include <boost/type_traits/is_convertible.hpp>
19 #include <boost/graph/dll_import_export.hpp>
20 #include <boost/graph/graphviz.hpp> // for exceptions
22 #include <boost/mpl/bool.hpp>
23 #include <boost/mpl/vector.hpp>
24 #include <boost/mpl/find.hpp>
25 #include <boost/mpl/for_each.hpp>
26 #include <boost/property_tree/detail/xml_parser_utils.hpp>
27 #include <boost/throw_exception.hpp>
34 /////////////////////////////////////////////////////////////////////////////
35 // Graph reader exceptions
36 /////////////////////////////////////////////////////////////////////////////
37 struct parse_error: public graph_exception
39 parse_error(const std::string& err) {error = err; statement = "parse error: " + error;}
40 virtual ~parse_error() throw() {}
41 virtual const char* what() const throw() {return statement.c_str();}
42 std::string statement;
50 virtual ~mutate_graph() {}
51 virtual bool is_directed() const = 0;
53 virtual boost::any do_add_vertex() = 0;
54 virtual std::pair<boost::any,bool> do_add_edge(boost::any source, boost::any target) = 0;
57 set_graph_property(const std::string& name, const std::string& value, const std::string& value_type) = 0;
60 set_vertex_property(const std::string& name, boost::any vertex, const std::string& value, const std::string& value_type) = 0;
63 set_edge_property(const std::string& name, boost::any edge, const std::string& value, const std::string& value_type) = 0;
66 template<typename MutableGraph>
67 class mutate_graph_impl : public mutate_graph
69 typedef typename graph_traits<MutableGraph>::vertex_descriptor vertex_descriptor;
70 typedef typename graph_traits<MutableGraph>::edge_descriptor edge_descriptor;
73 mutate_graph_impl(MutableGraph& g, dynamic_properties& dp)
74 : m_g(g), m_dp(dp) { }
76 bool is_directed() const
78 return is_convertible<typename graph_traits<MutableGraph>::directed_category,
82 virtual any do_add_vertex()
84 return any(add_vertex(m_g));
87 virtual std::pair<any,bool> do_add_edge(any source, any target)
89 std::pair<edge_descriptor,bool> retval = add_edge(any_cast<vertex_descriptor>(source),
90 any_cast<vertex_descriptor>(target), m_g);
91 return std::make_pair(any(retval.first), retval.second);
95 set_graph_property(const std::string& name, const std::string& value, const std::string& value_type)
97 bool type_found = false;
100 mpl::for_each<value_types>(put_property<MutableGraph *,value_types>
101 (name, m_dp, &m_g, value, value_type, m_type_names, type_found));
103 catch (bad_lexical_cast)
105 BOOST_THROW_EXCEPTION(
106 parse_error("invalid value \"" + value + "\" for key " +
107 name + " of type " + value_type));
111 BOOST_THROW_EXCEPTION(
112 parse_error("unrecognized type \"" + value_type +
113 "\" for key " + name));
119 set_vertex_property(const std::string& name, any vertex, const std::string& value, const std::string& value_type)
121 bool type_found = false;
124 mpl::for_each<value_types>(put_property<vertex_descriptor,value_types>
125 (name, m_dp, any_cast<vertex_descriptor>(vertex),
126 value, value_type, m_type_names, type_found));
128 catch (bad_lexical_cast)
130 BOOST_THROW_EXCEPTION(
131 parse_error("invalid value \"" + value + "\" for key " +
132 name + " of type " + value_type));
136 BOOST_THROW_EXCEPTION(
137 parse_error("unrecognized type \"" + value_type +
138 "\" for key " + name));
144 set_edge_property(const std::string& name, any edge, const std::string& value, const std::string& value_type)
146 bool type_found = false;
149 mpl::for_each<value_types>(put_property<edge_descriptor,value_types>
150 (name, m_dp, any_cast<edge_descriptor>(edge),
151 value, value_type, m_type_names, type_found));
153 catch (bad_lexical_cast)
155 BOOST_THROW_EXCEPTION(
156 parse_error("invalid value \"" + value + "\" for key " +
157 name + " of type " + value_type));
161 BOOST_THROW_EXCEPTION(
162 parse_error("unrecognized type \"" + value_type +
163 "\" for key " + name));
167 template <typename Key, typename ValueVector>
171 put_property(const std::string& name, dynamic_properties& dp, const Key& key,
172 const std::string& value, const std::string& value_type,
173 const char** type_names, bool& type_found)
174 : m_name(name), m_dp(dp), m_key(key), m_value(value),
175 m_value_type(value_type), m_type_names(type_names),
176 m_type_found(type_found) {}
177 template <class Value>
178 void operator()(Value)
180 if (m_value_type == m_type_names[mpl::find<ValueVector,Value>::type::pos::value])
182 put(m_name, m_dp, m_key, lexical_cast<Value>(m_value));
187 const std::string& m_name;
188 dynamic_properties& m_dp;
190 const std::string& m_value;
191 const std::string& m_value_type;
192 const char** m_type_names;
198 dynamic_properties& m_dp;
199 typedef mpl::vector<bool, int, long, float, double, std::string> value_types;
200 static const char* m_type_names[];
203 template<typename MutableGraph>
204 const char* mutate_graph_impl<MutableGraph>::m_type_names[] = {"boolean", "int", "long", "float", "double", "string"};
206 void BOOST_GRAPH_DECL
207 read_graphml(std::istream& in, mutate_graph& g, size_t desired_idx);
209 template<typename MutableGraph>
211 read_graphml(std::istream& in, MutableGraph& g, dynamic_properties& dp, size_t desired_idx = 0)
213 mutate_graph_impl<MutableGraph> mg(g,dp);
214 read_graphml(in, mg, desired_idx);
217 template <typename Types>
221 get_type_name(const std::type_info& type, const char** type_names, std::string& type_name)
222 : m_type(type), m_type_names(type_names), m_type_name(type_name) {}
223 template <typename Type>
224 void operator()(Type)
226 if (typeid(Type) == m_type)
227 m_type_name = m_type_names[mpl::find<Types,Type>::type::pos::value];
230 const std::type_info &m_type;
231 const char** m_type_names;
232 std::string &m_type_name;
236 template <typename Graph, typename VertexIndexMap>
238 write_graphml(std::ostream& out, const Graph& g, VertexIndexMap vertex_index,
239 const dynamic_properties& dp, bool ordered_vertices=false)
241 typedef typename graph_traits<Graph>::directed_category directed_category;
242 typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
243 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
245 using boost::property_tree::xml_parser::encode_char_entities;
247 BOOST_STATIC_CONSTANT(bool,
249 (is_convertible<directed_category*, directed_tag*>::value));
251 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
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";
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;
255 const char* type_names[] = {"boolean", "int", "int", "int", "int", "long", "long", "long", "long", "float", "double", "double", "string"};
256 std::map<std::string, std::string> graph_key_ids;
257 std::map<std::string, std::string> vertex_key_ids;
258 std::map<std::string, std::string> edge_key_ids;
262 for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i)
264 std::string key_id = "key" + lexical_cast<std::string>(key_count++);
265 if (i->second->key() == typeid(Graph*))
266 graph_key_ids[i->first] = key_id;
267 else if (i->second->key() == typeid(vertex_descriptor))
268 vertex_key_ids[i->first] = key_id;
269 else if (i->second->key() == typeid(edge_descriptor))
270 edge_key_ids[i->first] = key_id;
273 std::string type_name = "string";
274 mpl::for_each<value_types>(get_type_name<value_types>(i->second->value(), type_names, type_name));
275 out << " <key id=\"" << encode_char_entities(key_id) << "\" for=\""
276 << (i->second->key() == typeid(Graph*) ? "graph" : (i->second->key() == typeid(vertex_descriptor) ? "node" : "edge")) << "\""
277 << " attr.name=\"" << i->first << "\""
278 << " attr.type=\"" << type_name << "\""
282 out << " <graph id=\"G\" edgedefault=\""
283 << (graph_is_directed ? "directed" : "undirected") << "\""
284 << " parse.nodeids=\"" << (ordered_vertices ? "canonical" : "free") << "\""
285 << " parse.edgeids=\"canonical\" parse.order=\"nodesfirst\">\n";
288 for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i)
290 if (i->second->key() == typeid(Graph*))
292 // The const_cast here is just to get typeid correct for property
293 // map key; the graph should not be mutated using it.
294 out << " <data key=\"" << graph_key_ids[i->first] << "\">"
295 << encode_char_entities(i->second->get_string(const_cast<Graph*>(&g))) << "</data>\n";
299 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
300 vertex_iterator v, v_end;
301 for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v)
303 out << " <node id=\"n" << get(vertex_index, *v) << "\">\n";
305 for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i)
307 if (i->second->key() == typeid(vertex_descriptor))
309 out << " <data key=\"" << vertex_key_ids[i->first] << "\">"
310 << encode_char_entities(i->second->get_string(*v)) << "</data>\n";
316 typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
317 edge_iterator e, e_end;
318 typename graph_traits<Graph>::edges_size_type edge_count = 0;
319 for (boost::tie(e, e_end) = edges(g); e != e_end; ++e)
321 out << " <edge id=\"e" << edge_count++ << "\" source=\"n"
322 << get(vertex_index, source(*e, g)) << "\" target=\"n"
323 << get(vertex_index, target(*e, g)) << "\">\n";
326 for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i)
328 if (i->second->key() == typeid(edge_descriptor))
330 out << " <data key=\"" << edge_key_ids[i->first] << "\">"
331 << encode_char_entities(i->second->get_string(*e)) << "</data>\n";
342 template <typename Graph>
344 write_graphml(std::ostream& out, const Graph& g, const dynamic_properties& dp,
345 bool ordered_vertices=false)
347 write_graphml(out, g, get(vertex_index, g), dp, ordered_vertices);
352 #endif // BOOST_GRAPH_GRAPHML_HPP