2011-11-16 41 views
15

私はboost :: property_treeのドキュメントを読んでおり、ptreeを別のptreeに更新またはマージする方法が見つかりませんでした。これはどうすればいいですか?boost :: property_tree :: 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でを追加しようとしましたが、私がすることができなかった)

答えて

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

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

+0

ありがとうございます。これは興味深い解決策です。見てコンパイルしよう!しかし、 "同じパスを持つ複数のノードを持つことは可能です"ということはどういう意味ですか? Tree_1 = "a.b.c" = 0更新ツリーTree_2 = "a.b.c" = 1、 "a.b.d" = 2。 "a.b.d" = 2のみ更新されるのでしょうか? (デバッグして参照する) – mantler

+0

正確に同じパスを持つ複数のノードを持つことは可能です。 Tree_1に「a.b.c」= 1、「a.b.c」= 2、Tree_2に「a.b.c」= 1が含まれ、Tree_1でTree_2を更新した後、Tree_2に「a.b.c」= 2が含まれます。 –

+0

これは本当にクールなコードです。この演算子がpath_typeで動作することをどう知ったのですか?ptree :: path_type curPath = childPath/ptree :: path_type(it-> first); 'オペレータがドキュメントに定義されているかどうかわかりません。 – 2NinerRomeo

5

Boost.Propertyツリーはまだ、これをサポートしていません:boost.org/doc/libs/1_48_0/doc/html/property_tree/appendices.htmlを。将来の作業セクションを見てください。

数学的関係:ptree difference、union、intersection。

アップデートは単純に違いがあり、その後にユニオンが続きます。 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」)
  • できる値は、リーフノードに格納することができます。
+0

ありがとうございます。私はこれを試して、それがどのように機能するか見る。 「木は2層しかできない」ということは面白いですが、私はそれについては考えていませんでした。だから、私は(任意のツリーの深さのために)したいことをするための回避策や "ジェネリック"アルゴリズムがないことがありますか? – mantler

関連する問題