遍历 PTree children w/o 包括标签名称

Iterate through PTree children w/o including tag name

我想知道是否有一种方法可以通过遍历父节点的向量来获取子节点中的数据。我有一个我计划经常更改的 XML 文件,因此我想避免对属性名称进行硬编码。因此,我想在我的子节点中提取数据,而不使用 pt.get_child(myparentNodes) 声明节点的标签名称。我主要有这个。

非常感谢任何帮助!

vector<string> parentNodes;
ptree pt;
ifstream fileName("myxml");
read_xml(fileName, pt);

for(const ptree::value_type &parent : pt)
{
    cout << parent.first << std::endl;
    parentNodes.push_back(parent.first);
  
}
 for(int i=0; i<parentNodes.size();i++)
 {
BOOST_FOREACH(boost::property_tree::ptree::value_type const &node,pt.get_child(parentNodes[i]))

/* I'm having trouble properly accessing the children nodes here */

在您的代码段中(稍作清理):

std::vector<std::string> parentNodes;
for(auto const& parent : pt) {
    std::cout << parent.first << std::endl;
    parentNodes.push_back(parent.first);
}

似乎正在将树节点的 名称 收集到 parentNodes 中。但是,这假定名称是唯一的,或者 non-empty.

Property names need not be unique, nor are they guaranteed to be non-empty. In fact arrays in Property Tree are frequently modeled as nodes with only unnamed child nodes.

那你在获取相应节点的子节点时遇到了麻烦。让我们首先以繁琐的方式进行(同样,假设名称是唯一的):

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

还在做同样的事情。

泛化

你说你想让它通用。但是,假设 parent/child 关系的 two-layer 层次结构并没有让我觉得“通用”。我将您链接到一些显示通用遍历的示例(例如,在整个树中寻找模式), e.g. - 来自该示例的函数:

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