2011-11-16 45 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以添加一種方法來合併僅一個節點並填充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差異,聯合,交集。

更新只是一個區別,後跟聯合。 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」)
  • 值只能被存儲在葉節點。
+0

謝謝。我會試試看看它是如何工作的。有趣的是,你所說的「樹只能是兩層......」,我沒有想過。所以它可能是沒有工作或「通用」算法來做我想做的事(對於任意樹深度)? – mantler

相關問題