如何在yaml-cpp中合并节点
How to merge node in yaml-cpp
我有两个节点对象,像这样:
school:
grade:
class:
name: bob
school:
grade:
class:
age: 18
我想合并,结果是这样的:
school:
grade:
class:
name: bob
age: 18
如何合并呢?当不知道节点大小和深度时。
这是我的尝试:
#include <yaml-cpp/yaml.h>
inline const YAML::Node & cnode(const YAML::Node &n) {
return n;
}
YAML::Node merge_nodes(YAML::Node a, YAML::Node b)
{
if (!b.IsMap()) {
// If b is not a map, merge result is b, unless b is null
return b.IsNull() ? a : b;
}
if (!a.IsMap()) {
// If a is not a map, merge result is b
return b;
}
if (!b.size()) {
// If a is a map, and b is an empty map, return a
return a;
}
// Create a new map 'c' with the same mappings as a, merged with b
auto c = YAML::Node(YAML::NodeType::Map);
for (auto n : a) {
if (n.first.IsScalar()) {
const std::string & key = n.first.Scalar();
auto t = YAML::Node(cnode(b)[key]);
if (t) {
c[n.first] = merge_nodes(n.second, t);
continue;
}
}
c[n.first] = n.second;
}
// Add the mappings from 'b' not already in 'c'
for (auto n : b) {
if (!n.first.IsScalar() || !cnode(c)[n.first.Scalar()]) {
c[n.first] = n.second;
}
}
return c;
}
对于非标量键,我选择忽略节点等效性。请注意,此版本不修改 a
。它 returns 一个新地图 c
,它是 b
合并到 a
。来自 b
的值将替换 c
映射中来自 a
的相同键控的非映射值。
我发现 md5i 的回答有一个问题,它没有合并第二个节点的唯一子节点。我的修复是在节点 b 的 for 循环中再次调用该函数(我将其重命名为覆盖节点)。我还把所有东西都设为 const,因为我没有在这里编辑任何东西,所以我不必强制转换它。我还强调了第二个节点覆盖另一个节点的事实。
const YAML::Node mergeNodes(const YAML::Node& defaultNode, const YAML::Node& overrideNode)
{
if (!overrideNode.IsMap()) {
// If overrideNode is not a map, merge result is overrideNode, unless overrideNode is null
return overrideNode.IsNull() ? defaultNode : overrideNode;
}
if (!defaultNode.IsMap()) {
// If defaultNode is not a map, merge result is overrideNode
return overrideNode;
}
if (!defaultNode.size()) {
return YAML::Node(overrideNode);
}
// Create a new map 'newNode' with the same mappings as defaultNode, merged with overrideNode
auto newNode = YAML::Node(YAML::NodeType::Map);
for (auto node : defaultNode) {
if (node.first.IsScalar()) {
const std::string& key = node.first.Scalar();
if (overrideNode[key]) {
newNode[node.first] = mergeNodes(node.second, overrideNode[key]);
continue;
}
}
newNode[n.first] = node.second;
}
// Add the mappings from 'overrideNode' not already in 'newNode'
for (auto node : overrideNode) {
if (!node.first.IsScalar()) {
const std::string& key = node.first.Scalar();
if (defaultNode[key]) {
newNode[node.first] = mergeNodes(defaultNode[key], node.second);
continue;
}
}
newNode[node.first] = node.second;
}
return YAML::Node(newNode);
}
这可能不会对 N 事情有任何好处,但它会从节点 b/overrideNode 获取节点,即使它们在节点 a/defaultNode.
中没有实例
我有两个节点对象,像这样:
school:
grade:
class:
name: bob
school:
grade:
class:
age: 18
我想合并,结果是这样的:
school:
grade:
class:
name: bob
age: 18
如何合并呢?当不知道节点大小和深度时。
这是我的尝试:
#include <yaml-cpp/yaml.h>
inline const YAML::Node & cnode(const YAML::Node &n) {
return n;
}
YAML::Node merge_nodes(YAML::Node a, YAML::Node b)
{
if (!b.IsMap()) {
// If b is not a map, merge result is b, unless b is null
return b.IsNull() ? a : b;
}
if (!a.IsMap()) {
// If a is not a map, merge result is b
return b;
}
if (!b.size()) {
// If a is a map, and b is an empty map, return a
return a;
}
// Create a new map 'c' with the same mappings as a, merged with b
auto c = YAML::Node(YAML::NodeType::Map);
for (auto n : a) {
if (n.first.IsScalar()) {
const std::string & key = n.first.Scalar();
auto t = YAML::Node(cnode(b)[key]);
if (t) {
c[n.first] = merge_nodes(n.second, t);
continue;
}
}
c[n.first] = n.second;
}
// Add the mappings from 'b' not already in 'c'
for (auto n : b) {
if (!n.first.IsScalar() || !cnode(c)[n.first.Scalar()]) {
c[n.first] = n.second;
}
}
return c;
}
对于非标量键,我选择忽略节点等效性。请注意,此版本不修改 a
。它 returns 一个新地图 c
,它是 b
合并到 a
。来自 b
的值将替换 c
映射中来自 a
的相同键控的非映射值。
我发现 md5i 的回答有一个问题,它没有合并第二个节点的唯一子节点。我的修复是在节点 b 的 for 循环中再次调用该函数(我将其重命名为覆盖节点)。我还把所有东西都设为 const,因为我没有在这里编辑任何东西,所以我不必强制转换它。我还强调了第二个节点覆盖另一个节点的事实。
const YAML::Node mergeNodes(const YAML::Node& defaultNode, const YAML::Node& overrideNode)
{
if (!overrideNode.IsMap()) {
// If overrideNode is not a map, merge result is overrideNode, unless overrideNode is null
return overrideNode.IsNull() ? defaultNode : overrideNode;
}
if (!defaultNode.IsMap()) {
// If defaultNode is not a map, merge result is overrideNode
return overrideNode;
}
if (!defaultNode.size()) {
return YAML::Node(overrideNode);
}
// Create a new map 'newNode' with the same mappings as defaultNode, merged with overrideNode
auto newNode = YAML::Node(YAML::NodeType::Map);
for (auto node : defaultNode) {
if (node.first.IsScalar()) {
const std::string& key = node.first.Scalar();
if (overrideNode[key]) {
newNode[node.first] = mergeNodes(node.second, overrideNode[key]);
continue;
}
}
newNode[n.first] = node.second;
}
// Add the mappings from 'overrideNode' not already in 'newNode'
for (auto node : overrideNode) {
if (!node.first.IsScalar()) {
const std::string& key = node.first.Scalar();
if (defaultNode[key]) {
newNode[node.first] = mergeNodes(defaultNode[key], node.second);
continue;
}
}
newNode[node.first] = node.second;
}
return YAML::Node(newNode);
}
这可能不会对 N 事情有任何好处,但它会从节点 b/overrideNode 获取节点,即使它们在节点 a/defaultNode.
中没有实例