В вашем фрагменте (немного очищенном):
std::vector<std::string> parentNodes;
for(auto const& parent : pt) {
std::cout << parent.first << std::endl;
parentNodes.push_back(parent.first);
}
, похоже, собирает имена узлов дерева в parentNodes
. Однако это предполагает, что имена уникальны или непусты.
Имена свойств не обязательно должны быть уникальными, и они не обязательно должны быть непустыми. Фактически массивы в дереве свойств часто моделируются как узлы только с безымянными дочерними узлами.
Тогда у вас возникли проблемы с получением дочерних узлов соответствующих узлов. Давайте сначала сделаем это утомительным способом (опять же, предполагая, что имена уникальны):
for (size_t i = 0; i < parentNodes.size(); i++) {
auto& parent = pt.get_child(parentNodes[i]);
for (auto const& child : parent) {
std::cout << child.first << std::endl;
}
}
Конечно, использование дальнего боя намного проще:
for (auto const& name : parentNodes) {
auto& parent = pt.get_child(name);
for (auto const& child : parent) {
std::cout << child.first << std::endl;
}
}
Еще лучше
Вы можете избежать предположений относительно именования, а также второго l oop и векторного хранилища:
for (auto const& parent : pt) {
std::cout << parent.first << std::endl;
auto& node = parent.second;
for (auto const& child : node) {
std::cout << child.first << std::endl;
}
}
Это потому, что итератор указывает на пару (key, value)
. Фактически, в недавнем компиляторе вы можете написать l oop со структурированными привязками:
for (auto const& [name, node] : pt) {
std::cout << name << std::endl;
for (auto const& child : node) {
std::cout << child.first << std::endl;
}
}
, все еще делая то же самое.
Generalizing
Вы сказали, что хотите чтобы сделать этот generi c. Однако предположение о двухуровневой иерархии родительских / дочерних отношений не кажется мне "generi c". Я связал вас с некоторыми примерами, которые показывают общий обход c (например, поиск шаблонов по всему дереву) в последний раз , например Итерация по xml файлу с повышением - функция из этого примера:
Live On Wandbox
#include <boost/property_tree/xml_parser.hpp>
#include <iostream>
using boost::property_tree::ptree;
static auto settings = boost::property_tree::xml_writer_make_settings<std::string>(' ', 4);
template <typename Out>
Out enumerate_nodes(ptree const& pt, ptree::path_type path, Out out) {
if (path.empty())
return out;
if (path.single()) {
auto name = path.reduce();
for (auto& child : pt) {
if (child.first == name)
*out++ = child.second;
}
} else {
auto head = path.reduce();
for (auto& child : pt) {
if (head == "*" || child.first == head) {
out = enumerate_nodes(child.second, path, out);
}
}
}
return out;
}
int main() {
std::ifstream fileName("input.xml");
ptree pt;
read_xml(fileName, pt);
for (auto const& [name, node] : pt) {
std::cout << name << std::endl;
for (auto const& child : node)
std::cout << child.first << std::endl;
}
std::vector<std::reference_wrapper<ptree const>> matched;
enumerate_nodes(pt, "root.parent2.child3", back_inserter(matched));
for (ptree const& match : matched)
std::cout << "Matched: " << match.get_value<std::string>() << "\n";
}
При использовании input.xml
:
<?xml version="1.0"?>
<root>
<parent1>
<child1>parent1/child1</child1>
<child2>parent1/child2</child2>
<child3>parent1/child3</child3>
<child4>parent1/child4</child4>
</parent1>
<parent2>
<child1>parent2/child1</child1>
<child2>parent2/child2</child2>
<child3>parent2/child3</child3>
<child4>parent2/child4</child4>
</parent2>
<parent3>
<child1>parent3/child1</child1>
<child2>parent3/child2</child2>
<child3>parent3/child3</child3>
<child4>parent3/child4</child4>
</parent3>
<parent4>
<child1>parent4/child1</child1>
<child2>parent4/child2</child2>
<child3>parent4/child3</child3>
<child4>parent4/child4</child4>
</parent4>
</root>
Печать
root
parent1
parent2
parent3
parent4
Matched: parent2/child3