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関数で試したことの1つは、次を使用することです。

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を変更して、1つのメソッドを追加し、1つのノードだけをマージして、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());
  }    
}; 

唯一の制限は、同じパスを持つ複数のノードを持つことができることです。それらのすべてが使用されますが、最後の1つだけがマージされます。

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

十分に優れたソリューションには2つの制限があります。偶然にも、これらはini_parserと同じ制限です。

  • ツリーは2つのレイヤーのみにすることができます(例:「first.number」、「first.again.number」は不可)
  • 値はリーフノードにのみ保存できます。
于 2011-11-16T22:03:25.157 に答える