17

我已经阅读了 boost::property_tree 的文档,但还没有找到一种方法来更新或合并一个 ptree 与另一个 ptree。我该怎么做呢?

给定下面的代码,update_ptree 函数会是什么样子?

#include <iostream>
#include <boost/property_tree/ptree.hpp>
using boost::property_tree::ptree;

class A
{
  ptree pt_;
public:
  void set_ptree(const ptree &pt)
  {
    pt_ = pt;
  };
  void update_ptree(const ptree &pt)
  {
    //How do I merge/update a ptree?
  };
  ptree get_ptree()
  {
    return pt_;
  };
};

int main()
{
  A a;
  ptree pt;
  pt.put<int>("first.number",0);
  pt.put<int>("second.number",1);
  pt.put<int>("third.number",2);
  a.set_ptree(pt);
  ptree pta = a.get_ptree();

  //prints "0 1 2"
  std::cout << pta.get<int>("first.number") << " "
            << pta.get<int>("second.number") << " "
            << pta.get<int>("third.number") << "\n";


  ptree updates;
  updates.put<int>("first.number",7);
  a.update_ptree(updates);
  pta = a.get_ptree();

  //Because the update_tree function doesn't do anything it just prints "0 1 2".
  //I would like to see "7 1 2"
  std::cout << pta.get<int>("first.number") << " " 
            << pta.get<int>("second.number") << " " 
            << pta.get<int>("third.number") << "\n";

  return 0;
}

我考虑过迭代新的 ptree 并使用“put”来插入值。但是“put”需要一个类型,我不知道如何从新的 ptree 中获取该信息并将其用作旧 ptree 的参数。

我在 update_ptree 函数中尝试过的一件事是使用:

pt_.add_child(".",pt);

基本上我尝试将 pt 作为子级添加到 pt_ 的根目录中。不幸的是,这似乎不起作用。

有任何想法吗?

我很感激任何帮助。

谢谢你。

(我试图将标签 property_tree 和 ptree 添加到这个问题,但我不被允许)

4

2 回答 2

17

我认为您必须递归遍历property_tree。

您可以定义一个函数,递归地迭代每个节点并为每个节点调用一个方法:

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);
  }
}

我们可以定义一个更简单的函数来调用前一个函数:

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

现在,您可以修改类 A 以添加一种方法来仅合并一个节点并填充 update_ptree 方法:

#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());
  }    
}; 

唯一的限制是可能有多个节点具有相同的路径。它们中的每一个都会被使用,但只有最后一个会被合并。

于 2011-11-17T23:26:59.373 回答
7

Boost.Property 树尚不支持此功能:boost.org/doc/libs/1_48_0/doc/html/property_tree/appendices.html。看看未来的工作部分。

数学关系:ptree差分、并集、交集。

更新只是一个差异,然后是一个联合。 a = (a - b) + b.

一般的解决方案需要递归遍历更新 ptree 并放置每个叶子。

然而,一个足够好的解决方案可以用put_child. 这可以满足您的所有需求,而无需一般解决方案的复杂性。

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

足够好的解决方案有两个限制,巧合的是,它们与 ini_parser 的限制相同。

  • 树只能是两层(例如“first.number”,但不能是“first.again.number”)
  • 值只能存储在叶节点中。
于 2011-11-16T22:03:25.157 回答