Search code examples
c++boost-propertytree

Parse XML with boost property tree


I have the following XML file and I want to store it using the below structures.

the data structs:

    struct transitions
    {
     string oldstate;
     string event;
     string newstate;
    };

    struct XML_Diagram
    {
     string diag_name;
     string diag_defaultstate;
     list<string> diag_states;
     list<string> diag_events;
     list<transitions> diag_transitions;
    };

the xml file:

    <diagram>
      <diagname>DiagaX</diagname>
      <states>
         <state>A</state>
         .............       
      </states>
      <events>
          <event>ev1</event>
          .................
      </events>
      <defaultstate>A</defaultstate>
      <transitions>
          <transition>
              <oldstate>A</oldstate>
              <event>ev1</event>
              <newstate>B</newstate>
          </transition>
          <transition>
              <oldstate>B</oldstate>
              <event>ev2</event>
              <newstate>C</newstate>
          </transition>
          .........................
      </transitions>
    </diagram>

It is clear to me how can I to access diagram.states . I can do it with the folowing code:

    using boost::property_tree::ptree;
    ptree pt;

    // Get diagram states
    BOOST_FOREACH(ptree::value_type &v, pt.get_child("diagram.states"))
    {
       diag_states.push_back(v.second.data());
    }

What is not clear to me is how can I access the data from at the level diagram.transitions.transition ?

My problem is that I could not find any examples in the documentation on how to parse more complex xml files with several levels.


Solution

  • This useful utility function traverses and pretty-prints an entire property tree:

    using boost::property_tree::ptree;
    
    std::string q(const std::string& s) { return "\"" + s + "\""; }
    
    void print_tree(const ptree& pt, int level)
    {
        const std::string sep(2 * level, ' ');
        BOOST_FOREACH(const ptree::value_type &v, pt) {
            std::cout
                << sep
                << q(v.first) << " : " << q(v.second.data()) << "\n";
            print_tree(v.second, level + 1);
        }
    }
    
    void print_tree(const ptree& pt) { print_tree(pt, 0); }
    

    The v.second values are trees themselves that can be accessed with the usual get methods. The transitions can for example be accessed and printed like this:

    using std::string;
    
    void print_transitions(const ptree& pt)
    {
        BOOST_FOREACH(
            const ptree::value_type &v,
            pt.get_child("diagram.transitions"))
        {
            const ptree& child = v.second;
            std::cout
                << "Event "
                << child.get<string>("event")
                << " in state "
                << child.get<string>("oldstate")
                << " leads to state "
                << child.get<string>("newstate")
                << "\n";
        }
    }