简体   繁体   English

如何合并/更新boost :: property_tree :: ptree?

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

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. 我已经阅读了boost :: property_tree的文档,但没有找到更新或合并ptree与另一个ptree的方法。 How do I do this? 我该怎么做呢?

Given the code below, how would the update_ptree function look like? 鉴于下面的代码,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;
}

I have thought about iterating over the new ptree and using "put" to insert values. 我已经考虑过迭代新的ptree并使用“put”来插入值。 But "put" requires a type and I don't know how to get that information from the new ptree and use it as a argument for the old ptree. 但是“put”需要一个类型,我不知道如何从新的ptree获取该信息并将其用作旧ptree的参数。

One thing I have tried in the update_ptree function is using: 我在update_ptree函数中尝试过的一件事是使用:

pt_.add_child(".",pt);

Basically I try to add the pt as a child to the root of pt_. 基本上我尝试将pt作为孩子添加到pt_的根目录。 Unfortunately this does not seem to work. 不幸的是,这似乎不起作用。

Any ideas? 有任何想法吗?

I am grateful for any help. 我很感激任何帮助。

Thank you. 谢谢。

(I tried to add the tags property_tree and ptree to this question but I wasn't allowed to) (我试图将标签property_tree和ptree添加到这个问题,但我不被允许)

I think you have to recursively traverse the property_tree. 我认为你必须以递归方式遍历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: 现在,您可以修改类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());
  }    
}; 

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. 它们中的每一个都将被使用,但只有最后一个将被合并。

Boost.Property tree does not support this, yet: boost.org/doc/libs/1_48_0/doc/html/property_tree/appendices.html . Boost.Property树不支持这个,但是: 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. 数学关系:ptree差异,联合,交集。

An update is simply a difference followed by a union. 更新只是工会之后的差异。 a = (a - b) + b . a = (a - b) + b

The general solution would require recursively traversing update ptree and putting each leaf. 一般解决方案需要递归遍历更新ptree并放置每个叶子。

However a good enough solution can be built with put_child . 但是,使用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. 足够好的解决方案有两个限制,巧合的是它们与ini_parser具有相同的限制。

  • the tree can only be two layers (eg "first.number", but not "first.again.number" ) 树只能是两层(例如“first.number”,但不是“first.again.number”)
  • values can only be stored in leaf nodes. 值只能存储在叶节点中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM