2011-11-16 2 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); 
} 

이제 하나의 노드를 병합하는 하나의 메소드를 추가하고 update_ptree 메소드를 채우기 위해 클래스 A를 수정할 수 있습니다.

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

충분히 좋은 솔루션에는 두 가지 제한이 있습니다. 우연히도 ini_parser와 같은 제한이 있습니다.

  • 트리 단지 2 (예를 들면 "first.number"가 아니라 "first.again.number") 층
  • 값은 단지 리프 노드에 저장 될 수있을 수있다.
+0

감사합니다. 나는 이것을 시험해보고 그것이 어떻게 작동하는지 보게 될 것이다. "나무는 단지 두 개의 레이어가 될 수 있습니다 .."라고 말하면 흥미 롭습니다. 그런 생각은하지 않았습니다. 그래서 내가 할 일 (임의의 트리 깊이에 대한)을 수행하는 "일반적인"알고리즘이 없다는 것입니다. – mantler