如何为YAML::Node添加注释并在输出中展示?
解决方案:在yaml-cpp中为YAML::Node添加注释(无需子类化或重写Emitter)
yaml-cpp的YAML::Node本身不存储注释(因为注释属于序列化格式信息,而非YAML数据结构的一部分),但不用子类化Node或重写Emitter也能实现类似需求,以下是两种可行方案:
方案1:外部映射关联节点与注释
核心思路是单独维护一个注释映射表,记录需要添加注释的节点路径对应的注释内容,在序列化时主动插入注释。
#include <yaml-cpp/yaml.h> #include <unordered_map> #include <string> #include <iostream> // 维护节点路径到注释的映射 std::unordered_map<std::string, std::string> nodeComments; // 递归序列化节点并插入注释 void emitWithComments(YAML::Emitter& emitter, const YAML::Node& node, const std::string& path = "") { if (node.IsMap()) { emitter << YAML::BeginMap; for (const auto& pair : node) { std::string currentPath = path.empty() ? pair.first.Scalar() : path + "." + pair.first.Scalar(); // 检查当前节点是否有注释 auto it = nodeComments.find(currentPath); if (it != nodeComments.end()) { emitter << YAML::Comment(it->second); } emitter << YAML::Key << pair.first; emitter << YAML::Value; emitWithComments(emitter, pair.second, currentPath); } emitter << YAML::EndMap; } else if (node.IsSequence()) { emitter << YAML::BeginSeq; for (std::size_t i = 0; i < node.size(); ++i) { std::string currentPath = path + "[" + std::to_string(i) + "]"; auto it = nodeComments.find(currentPath); if (it != nodeComments.end()) { emitter << YAML::Comment(it->second); } emitWithComments(emitter, node[i], currentPath); } emitter << YAML::EndSeq; } else { emitter << node; } } int main() { // 构建YAML节点 YAML::Node topNode; topNode["one"]["two"]["A"] = "foo"; topNode["one"]["two"]["B"] = 123; topNode["list"].push_back("item1"); topNode["list"].push_back("item2"); // 添加注释映射 nodeComments["one.two.A"] = "A should be 'foo'"; nodeComments["one.two.B"] = "B is an integer value"; nodeComments["list[0]"] = "First list item"; // 序列化并输出带注释的YAML YAML::Emitter emitter; emitWithComments(emitter, topNode); std::cout << emitter.c_str() << std::endl; return 0; }
该方案灵活度高,能给任意层级的节点添加注释,无需修改原有Node的构建逻辑。
方案2:包装节点为带注释的自定义类型
通过自定义包含Node和注释的结构体,为其实现yaml-cpp的序列化逻辑,构建Node时直接使用包装类型,序列化时自动输出注释。
#include <yaml-cpp/yaml.h> #include <string> #include <iostream> // 带注释的节点包装类 struct CommentedNode { YAML::Node node; std::string comment; // 构造函数,支持直接赋值 template<typename T> CommentedNode(T&& value, const std::string& comm) : node(std::forward<T>(value)), comment(comm) {} }; // 为CommentedNode实现yaml-cpp序列化逻辑 namespace YAML { template<> struct convert<CommentedNode> { static Node encode(const CommentedNode& rhs) { return rhs.node; } static bool decode(const Node& node, CommentedNode& rhs) { rhs.node = node; return true; } }; // 重载Emitter的<<操作符,输出注释和节点 Emitter& operator<<(Emitter& out, const CommentedNode& cn) { if (!cn.comment.empty()) { out << Comment(cn.comment); } out << cn.node; return out; } } int main() { YAML::Node topNode; // 使用包装类直接赋值并添加注释 topNode["one"]["two"]["A"] = CommentedNode("foo", "A should be 'foo'"); topNode["one"]["two"]["B"] = CommentedNode(123, "B is an integer value"); // 序列化输出 YAML::Emitter emitter; emitter << topNode; std::cout << emitter.c_str() << std::endl; return 0; }
该方案代码直观,构建节点时即可明确标注注释,适合需要固定注释的节点场景。
注:两种方案均在序列化阶段(使用Emitter时)插入注释,因为YAML::Node本身无存储注释的设计,无法直接为Node添加addComment方法,但完全满足无需子类化或重写Emitter的需求。
内容的提问来源于stack exchange,提问作者Lance E.T. Compte
相关产品推荐
相关产品推荐

