YAML解析库:yaml-cpp

yaml-cpp

引言

基本信息

  • yaml:YAML是专门用来写配置文件的语言,非常简洁和强大,比json和xml格式要方便很多,更容易阅读
  • yaml-cpp:是一个开源的C++解析yaml配置文件的库,我们可以使用该库进行解析项目中的yaml文件

windows添加环境变量

  1. 右键点击此电脑,点击属性,选择高级系统设置(或者打开设置,进入系统选型卡,点击系统信息,然后点击高级系统设置),点击环境变量后

    image-20241009092956650

  2. 在用户变量中的双击Path,然后新建,将需要添加到环境变量中的地址放入,然后确定

    image-20241009093305287

安装准备

  1. 下载源码包

    1
    git clone git@github.com:jbeder/yaml-cpp.git
  2. 进入yaml-cpp目录后,创建build目录并且进入

    1
    2
    3
    4
    5
    6
    7
    8
    # linux
    cd yaml-cpp
    mkdir build && cd build

    # windows
    cd yaml-cpp
    mkdir build
    cd build
  3. 将其编译成动态库或静态库来链接到项目中使用

  4. 安装cmake和编译工具

    • windows:进入Download CMake进行下载安装适合的cmke环境,点击w64devkit安装编译环境工具,然后将安装cmake和w64devkit的bin目录地址添加到环境变量中
    • Linux:使用命令行安装Moon’s CMake

注意:这里windows编译库的方法是用mingw的编译工具的,如果需要VS或者Ninja就去百度来查找进行编译

Windows编译库

  1. 进入到yaml-cpp目录下的build目录后用终端打开(右键文件夹)

  2. 执行以下命令:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    cmake .. -G “MinGW Makefiles”
    # 需要生成动态库执行以下命令
    cmake .. -G “MinGW Makefiles” -D BUILD_SHARED_LIBS=ON

    # 进行make生成
    make

    # 如果需要安装可以
    make install

Linux编译库

1
2
3
4
5
6
7
8
cd yaml-cpp
mkdir build && cd build

cmake .. && make
# 需要动态库
cmake .. -D BUILD_SHARED_LIBS=ON && make
# 需要安装
sudo make install

YAML语法

基本语法

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • '#'表示注释
  • 字符串默认不使用引号表示,如果字符串之中包含空格或特殊字符,需要放在引号之中
  • 单引号和双引号都可以使用,双引号不会对特殊字符转义
  • 单引号之中如果还有单引号,必须连续使用两个单引号转义
  • 字符串可以写成多行,从第二行开始,必须有一个单空格缩进,换行符会被转为空格
  • 映射写法为 key: value,冒号后需要带空格

标量(Scalars)单个的、不可再分的值(date、boolean、string、number、null、字符串、浮点数、时间、日期)

1
2
# 写法
k: v

对象(Map)键值对的集合(map、hash、set、object),又称为映射/哈希/字典

1
2
3
4
5
6
7
# 行内写法
k: {k1:v1,k2:v2,k3:v3}
# 或分层写法
k:
k1: v1
k2: v2
k3: v3

数组(Sequence)一组按次序排列的值(array、list、queue)

1
2
3
4
5
6
7
# 行内写法
k: [v1,v2,v3]
# 或分层写法
k:
- v1
- v2
- v3

引用

  • 可以通过引用另一个变量来设置value,使用${}引用变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 定义变量
    test:
    p: 1

    test1: 1

    name:
    p1: ${test.p}
    p2: ${test1}
  • 通过引用锚点&来设置值,用*来取锚点值,可以通过<<:将键值对一起引入

    1
    2
    3
    4
    5
    6
    # 设置锚点
    test: &test-c
    p: 1

    name:
    <<: *test-c
  • 通过使用锚点&来设置键,用*来取锚点值

    1
    2
    3
    4
    5
    6
    7
    test: 
    p1: &test-p1 pp1
    p2: &test-p2 pp2

    name:
    *test-p1: 1
    *test-p2: 2

yaml-cpp使用

引入头文件

1
#include "yaml-cpp/yaml.h"

Node

  • 概念:Node 是 yaml-cpp 中的核心概念,是最重要的数据结构,它用于存储解析后的yaml信息
  • type未定义(Undefined)、空节点(Null)、标量(Scalar)、数组(Sequence)、对象(Map)
1
2
3
4
5
6
7
8
namespace YAML {
struct NodeType {
enum value { Undefined, Null, Scalar, Sequence, Map };
};
}

//定义节点
YAML::Node node; //初始化为null类型

检查节点类型:

1
2
3
4
5
6
7
8
//示例:
if (config["key"].IsScalar()) {
// 处理标量
} else if (config["key"].IsSequence()) {
// 处理序列
} else if (config["key"].IsMap()) {
// 处理映射
}

赋值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//定义节点
YAML::Node node;
//标量赋值
node["key"]="value";

//对象赋值
YAML::Node node1;
node1["key"]["p1"]=1;
node1["key"]["p2"]=2;
//对象中插入值
node1["seq"].push_back("1");

//数组赋值
YAML::Node node2;
node2.push_back("1");
node2.push_back("2");
//数组转变map
node2["key"]="value";

//插入数组
YAML::Node node3;
std::vector<int> v = {1,2,3,4};
node3.push_back(v);

//将node2和node3作为node的子项
node["node2"]=node2;
node["node3"]=node3;

//输出查看
std::cout<<node<<std::endl;

取值使用.as()来将值以type类型取出

1
2
3
4
5
6
7
8
9
10
//取值模板
type value=<Node name>["key"].as<type>();
type value=<Node name>["key"]["key1"].as<type>();

//示例:
//标量取值
std::string ip=config["ip"].as<std::string>();

//对象取值
int port=config["settings"]["port"].as<int>();

删除:使用remove方法进行删除指定节点中的键和指定键

1
2
node.remove("key");	//通过指定键删除
node.remove(node["seq"]["0"]); //删除指定节点中的键

迭代:使用YAML::const_iterator迭代器

  • 解析数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //YAML的迭代器为YAML::const_iterator
    for(YAML::const_iterator it=config["key"].begin();it!=config["items"].end();++it){
    std::cout<<it->as<type>()<<std::endl;
    }

    //或者
    for(auto it=config["key"].begin();it!=config["items"].end();++it){
    std::cout<<it->as<type>()<<std::endl;
    }

    //或者
    for(auto const &it:config["items"]){
    std::cout<<it.as<std::string>()<<std::endl;
    }
  • 解析对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //YAML的迭代器为YAML::const_iterator
    for(YAML::const_iterator it=config["key"].begin();it!=config["items"].end();++it){
    std::string key = it->first.as<std::string>();
    std::string value = it->second.as<std::string>();
    std::cout << key << ": " << value << std::endl;
    }

    //或者
    for(auto it=config["key"].begin();it!=config["items"].end();++it){
    std::string key = it->first.as<std::string>();
    std::string value = it->second.as<std::string>();
    std::cout << key << ": " << value << std::endl;
    }

    //或者
    for(auto const &it:config["items"]){
    std::string key = it.first.as<std::string>();
    std::string value = it.second.as<std::string>();
    std::cout << key << ": " << value << std::endl;
    }

读取yaml文件使用Load或者LoadFile方法

1
2
3
4
5
std::ifstream file("config.yml");
YAML::Node node = YAML::Load(file);//读取来自config.yml的node文件
std::cout << node <<std::endl;
//或者
YAML::Node node_2 = YAML::LoadFile("config.yml");//也可以这样读取文件

保存yaml文件/输出

1
2
3
4
5
6
YAML::Node out;
std::ofstream fout("output.yaml");
//更改out里的数据
...
fout << out;
fout.close();

YAML解析库:yaml-cpp
https://moonfordream.github.io/posts/YAML解析库-yaml-cpp/
作者
Moon
发布于
2024年10月9日
许可协议