YAML格式支持在单个文件中包含多个连续的文档,每个文档以三个短横线---作为分隔符,这种特性常被用于存放多组独立配置或者批量数据。在C++中解析这类YAML内容时,需要合理使用YAML库的Parser和Node相关接口,通过循环逻辑逐个读取文档内容。

环境准备
首先需要安装yaml-cpp库,这是C++中常用的YAML解析库。在Ubuntu系统中可以通过apt命令快速安装:
sudo apt-get install libyaml-cpp-dev
如果是其他系统,也可以从源码编译安装,安装完成后在编译时需要链接yaml-cpp库,比如使用g++编译时添加-lyaml-cpp参数。
YAML多文档示例
我们先准备一个包含多个连续文档的YAML文件,命名为multi_doc.yaml,内容如下:
--- name: 配置组1 version: 1.0 items: - item1 - item2 --- name: 配置组2 version: 2.0 items: - item3 - item4 --- name: 配置组3 version: 3.0 items: - item5 - item6
核心解析逻辑
解析多个连续YAML文档的核心思路是:先初始化YAML::Parser对象并加载YAML内容,然后循环调用Parser的文档读取方法,每次读取到一个文档就将其转为YAML::Node对象进行处理,直到没有更多文档为止。
基础解析代码实现
下面是完整的解析代码示例,实现了循环读取上述YAML文件中的多个文档:
#include <iostream>
#include <fstream>
#include <yaml-cpp/yaml.h>
int main() {
// 打开YAML文件
std::ifstream fin("multi_doc.yaml");
if (!fin.is_open()) {
std::cerr << "无法打开YAML文件" << std::endl;
return 1;
}
// 初始化Parser对象,绑定文件流
YAML::Parser parser(fin);
// 定义Node对象用于存储每个文档的内容
YAML::Node doc;
// 循环解析多个文档
while (parser.GetNextDocument(doc)) {
// 提取当前文档的字段
std::string name = doc["name"].as<std::string>();
float version = doc["version"].as<float>();
std::cout << "解析到文档:" << std::endl;
std::cout << "name: " << name << std::endl;
std::cout << "version: " << version << std::endl;
std::cout << "items: ";
// 遍历items列表
const YAML::Node& items = doc["items"];
for (size_t i = 0; i < items.size(); ++i) {
std::cout << items[i].as<std::string>() << " ";
}
std::cout << std::endl << std::endl;
}
fin.close();
return 0;
}
代码逻辑说明
- 首先通过
std::ifstream打开YAML文件,若打开失败则输出错误提示。 - 创建
YAML::Parser对象并将文件流传入,Parser会自动识别文件中的YAML内容。 - 定义
YAML::Node对象doc,用于接收每次解析到的单个文档内容。 - 使用
while循环调用parser.GetNextDocument(doc)方法,该方法会逐个读取文档,若有新文档则返回true并将内容存入doc,若无更多文档则返回false,退出循环。 - 在循环内部,通过
doc["字段名"].as<类型>()的方式提取当前文档的字段值,对于列表类型的字段可以遍历其元素。
常见注意事项
如果YAML文件中存在语法错误,GetNextDocument方法会抛出异常,实际开发中建议添加异常捕获逻辑,避免程序崩溃。另外,当文档中的某个字段可能不存在时,不要直接调用as方法,可以先判断doc["字段名"]是否有效,示例如下:
// 安全获取字段,不存在时使用默认值 std::string desc = doc["desc"] ? doc["desc"].as<std::string>() : "无描述";
还有一点需要注意,YAML::Parser对象在解析完成后不需要手动释放资源,其生命周期结束后会自动处理相关内存,避免内存泄漏问题。