[英]Iterate Through All Nodes In yaml-cpp Including Recursive Anchor/Alias
給定YAML::Node
我們如何訪問該節點內的所有標量節點(以修改它們)? 我最好的猜測是遞歸 function:
void parseNode(YAML::Node node) {
if (node.IsMap()) {
for (YAML::iterator it = node.begin(); it != node.end(); ++it) {
parseNode(it->second);
}
}
else if (node.IsSequence()) {
for (YAML::iterator it = node.begin(); it != node.end(); ++it) {
parseNode(*it);
}
}
else if (node.IsScalar()) {
// Perform modifications here.
}
}
這對我的需求很好,除了在一種情況下:如果有遞歸錨/別名。 (我認為 YAML 1.2 規范允許這樣做? yaml-cpp
在解析時當然不會拋出Exception
)例如:
first: &firstanchor
a: 5
b: *firstanchor
上面的代碼將重復跟隨錨的別名,直到崩潰(SEGFAULT)可能是由於堆棧問題。 如何克服這個問題?
Node
結構來解決這個問題?Node
檢查它是否是別名,這樣我們就可以維護一堆以前訪問過的別名來檢測循環和中斷。Node
標識符,這樣我就可以維護一堆以前訪問過的節點?識別節點最明顯的方法是使用它們的m_pNode
指針; 但是,這是不可公開查詢的。 下一個最好的方法是使用bool Node::is(const Node& rhs) const
,遺憾的是它不允許我們在搜索循環時進行任何排序以提高性能。
所以你要做的是維護當前的節點堆棧並在下降之前搜索它,例如
class Visitor {
public:
using Callback = std::function<void(const YAML::Node&)>;
Visitor(Callback cb): stack(), cb(cb) {}
void visitSubgraph(const YAML::Node &cur) {
stack.push_back(target);
if (cur.IsMap()) {
for (const auto &pair : cur) {
descend(pair.second);
}
} else if (node.IsSequence()) {
for (const auto &child : cur) {
descend(child);
}
} else if (node.IsScalar()) {
cb(cur);
}
stack.pop_back();
}
private:
void descend(const YAML::Node &target) {
for (const auto &item : stack) {
if (item.is(target)) return;
}
visitSubgraph(target);
}
std::vector<YAML::Node> stack;
Callback cb;
};
然后你可以做
Visitor v([](const YAML::Node &scalar) {
// do whatever with the scalar
});
v.visitSubgraph(node);
(請原諒我的錯誤,我的 C++ 有點生銹;我希望你明白。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.