在您的代码段中(稍微清理一下):
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;
}
}
当然使用 ranged-for 要容易得多:
for (auto const& name : parentNodes) {
auto& parent = pt.get_child(name);
for (auto const& child : parent) {
std::cout << child.first << std::endl;
}
}
更好的是
您可以避免关于命名以及第二个循环和向量存储的假设:
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)
. 事实上,在最近的编译器上,您可以使用结构化绑定编写循环:
for (auto const& [name, node] : pt) {
std::cout << name << std::endl;
for (auto const& child : node) {
std::cout << child.first << std::endl;
}
}
仍然在做同样的事情。
概括
你说你想让这个通用。但是,假设父/子关系的两层层次结构并不让我觉得“通用”。上次我将您链接到一些显示通用遍历(例如在整个树中查找模式)的示例,例如使用 boost 对 xml 文件进行迭代- 该示例中的一个函数:
活在魔杖盒上
#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