如何在 yaml-cpp 中合并节点
Posted
技术标签:
【中文标题】如何在 yaml-cpp 中合并节点【英文标题】:How to merge node in yaml-cpp 【发布时间】:2016-12-26 03:15:58 【问题描述】:我有两个节点对象,像这样:
school:
grade:
class:
name: bob
school:
grade:
class:
age: 18
我想合并它,结果是这样的:
school:
grade:
class:
name: bob
age: 18
如何合并?当节点大小和深度不知道时。
【问题讨论】:
【参考方案1】:这是我的尝试:
#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
。它返回一个新映射c
,它是b
与a
的合并。 b
中的值将替换 c
映射中 a
中具有相同键的非映射值。
【讨论】:
为什么要使用cnode
函数?
需要调用 operator[]
方法的 const 版本,因为非 const 版本会修改对象(就像在 std::vector
中一样。这看起来比到处进行类型转换更干净。【参考方案2】:
我发现 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 中没有实例。
【讨论】:
以上是关于如何在 yaml-cpp 中合并节点的主要内容,如果未能解决你的问题,请参考以下文章