Как слить/обновить boost:: property_tree:: ptree?
Я прочитал документацию для 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 к этому вопросу, но мне не разрешили)
Ответы
Ответ 1
Я думаю, вы должны рекурсивно пройти через свойство_tree.
Вы можете определить функцию, которая повторяется на каждом node рекурсивно и вызывает метод для каждого node:
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, чтобы добавить один метод для слияния только одного node и заполнить метод 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());
}
};
Единственное ограничение состоит в том, что возможно иметь несколько узлов с одним и тем же путем. Каждый из них будет использоваться, но только последний будет объединен.
Ответ 2
Дерево 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" )
Значения
- могут храниться только в листовых узлах.