Search code examples
c++boostboost-graphgraphml

Boost Read_graphml doesn't read xml properly it gives all the vertices but they are empty


I have a adjacency list of type

boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, GraphData>

Where GraphData is a structure contains name

struct GraphItem
{
    std::string Name;
}

I am able to write graph to xml

void WriteGraph() {
     boost::dynamic_properties dp;

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

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

std::string Name(boost::vertex_bundle_type<Graph>::type v) {
    std::ostringstream oss;
    oss << v.Name;
    return oss.str();
}

I get XML as

<graphml>
  <key id="key0" for="node" attr.name="Name" attr.type="string" />
  <graph id="G" edgedefault="directed" parse.nodeids="canonical" 
   parse.edgeids="canonical" parse.order="nodesfirst">
    <node id="n0">
      <data key="key0">A</data>
    </node>
    <node id="n1">
      <data key="key0">D</data>
    </node>
    <node id="n2">
      <data key="key0">B</data>
    </node>
    <node id="n3">
      <data key="key0">C</data>
    </node>
    <edge id="e0" source="n0" target="n1">
    </edge>
    <edge id="e1" source="n2" target="n3">
    </edge>
  </graph>
</graphml>

When I read graph

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

This is crashing says property Name not found. If I use ignore_other_properties for property,

boost::dynamic_properties dp(ignore_other_properties);

It works but I am not getting any graph item in graph vertices.


Solution

  • The graph is not empty, you get:

    0 --> 1 
    1 --> 
    2 --> 3 
    3 --> 
    

    Or in XML: https://paste.ubuntu.com/p/c4tGmxGssJ/

    Of course, you wanted to read the name property. For that you obviously need to register the property with the dynamic-properties map.

    Note You can access members of property bundles much simpler:

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

    Full Demo

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/graphml.hpp>
    
    struct GraphData {
        std::string Name;
    };
    
    using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, GraphData>;
    
    Graph ReadGraph(std::string const& fileName) {
        Graph graph;
        boost::dynamic_properties dp;
        dp.property("Name", boost::get(&GraphData::Name, graph));
    
        std::ifstream file(fileName);
        boost::read_graphml(file, graph, dp);
    
        return graph;
    }
    
    void WriteGraph(std::ostream& os, Graph& graph) {
        boost::dynamic_properties dp;
        dp.property("Name", get(&GraphData::Name, graph));
    
        boost::write_graphml(os, graph, dp, true); 
    }
    
    #include <boost/graph/graph_utility.hpp>
    
    int main() {
        Graph g = ReadGraph("input.txt");
        print_graph(g, get(&GraphData::Name, g));
    
        // or as XML
        WriteGraph(std::cout << "==== XML version: ====\n\n", g);
    }
    

    Prints

    A --> D 
    D --> 
    B --> C 
    C --> 
    ==== 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="Name" attr.type="string" />
      <graph id="G" edgedefault="directed" parse.nodeids="canonical" parse.edgeids="canonical" parse.order="nodesfirst">
        <node id="n0">
          <data key="key0">A</data>
        </node>
        <node id="n1">
          <data key="key0">D</data>
        </node>
        <node id="n2">
          <data key="key0">B</data>
        </node>
        <node id="n3">
          <data key="key0">C</data>
        </node>
        <edge id="e0" source="n0" target="n1">
        </edge>
        <edge id="e1" source="n2" target="n3">
        </edge>
      </graph>
    </graphml>