Как мне объединить / обновить boost :: property_tree :: ptree? - PullRequest
16 голосов
/ 16 ноября 2011

Я прочитал документацию для 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, использует:

pt_.add_child(".",pt);

В основном я пытаюсь добавить pt как дочерний элемент в корень pt_.К сожалению, это не похоже на работу.

Есть идеи?

Я благодарен за любую помощь.

Спасибо.

(Я пытался добавитьтеги property_tree и ptree на этот вопрос, но мне не разрешили)

Ответы [ 2 ]

17 голосов
/ 18 ноября 2011

Я думаю, что вы должны рекурсивно пройти по дереву 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());
  }    
}; 

Единственное ограничение заключается в том, что возможноиметь несколько узлов с одинаковым путем.Будет использован каждый из них, но будет объединен только последний.

6 голосов
/ 17 ноября 2011

Boost.Property не поддерживает это, однако: boost.org / doc / libs / 1_48_0 / doc / html / property_tree / appendices.html . Посмотрите на раздел будущих работ.

Математические отношения: разность деревьев, объединение, пересечение.

Обновление - это просто разница, за которой следует объединение. a = (a - b) + b.

Общее решение потребовало бы рекурсивного обхода обновления дерева и размещения каждого листа.

Однако достаточно хорошее решение можно построить с помощью 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")
  • значения могут храниться только в конечных узлах.
...