How do I merge/update a boost::property_tree::ptree?

后端 未结 2 2007
死守一世寂寞
死守一世寂寞 2021-02-01 07:07

I have read through the documentation for boost::property_tree and have not found a way to update or merge a ptree with another ptree. How do I do this?

Given the code b

相关标签:
2条回答
  • 2021-02-01 07:25

    Boost.Property tree does not support this, yet: boost.org/doc/libs/1_48_0/doc/html/property_tree/appendices.html. Look at the future work section.

    Mathematical relations: ptree difference, union, intersection.

    An update is simply a difference followed by a union. a = (a - b) + b.

    The general solution would require recursively traversing update ptree and putting each leaf.

    However a good enough solution can be built with put_child. This may do all you need, without the complexity of a general solution.

    void merge( ptree& pt, const ptree& updates )
    {
       BOOST_FOREACH( auto& update, updates )
       {
          pt.put_child( update.first, update.second );
       }
    }
    

    The good enough solution has two limitations, by coincidence they are the same limitations the ini_parser has.

    • the tree can only be two layers (e.g. "first.number", but not "first.again.number" )
    • values can only be stored in leaf nodes.
    0 讨论(0)
  • 2021-02-01 07:42

    I think you have to recursively traverse the property_tree.

    You can define a function that iterates on each node recursively and calls a method for each node:

    template<typename T>
    void traverse_recursive(const boost::property_tree::ptree &parent, const boost::property_tree::ptree::path_type &childPath, const boost::property_tree::ptree &child, T &method)
    {
      using boost::property_tree::ptree;
    
      method(parent, childPath, child);
      for(ptree::const_iterator it=child.begin();it!=child.end();++it) {
        ptree::path_type curPath = childPath / ptree::path_type(it->first);
        traverse_recursive(parent, curPath, it->second, method);
      }
    }
    

    We can define a simpler function in order to call the previous one:

    template<typename T>
    void traverse(const boost::property_tree::ptree &parent, T &method)
    {
      traverse_recursive(parent, "", parent, method);
    }
    

    Now, you can modify the class A in order to add one method to merge just one node and fill the update_ptree method:

    #include <boost/bind.hpp>
    
    class A {  
      ptree pt_; 
    
    public:   
      void set_ptree(const ptree &pt)   {    
        pt_ = pt; 
      }
    
      void update_ptree(const ptree &pt)   {  
        using namespace boost;
        traverse(pt, bind(&A::merge, this, _1, _2, _3));
      }
    
      ptree get_ptree()   { 
        return pt_;  
      }
    
    protected:
      void merge(const ptree &parent, const ptree::path_type &childPath, const ptree &child) {
        pt_.put(childPath, child.data());
      }    
    }; 
    

    The only limitation is that it is possible to have several nodes with the same path. Every one of them would be used, but only the last one will be merged.

    0 讨论(0)
提交回复
热议问题