yaml文件解析:c++篇

本文使用 C++ 库 yaml-cpp 对 yaml 文件进行解析。

下载编译

下载地址:https://github.com/jbeder/yaml-cpp/releases/tag/yaml-cpp-0.6.3 。 文件名为:yaml-cpp-yaml-cpp-0.6.3.zip。
解压,进入库目录,创建build目录。执行:

1
2
3
cd build
cmake ../
make

在build目录生成 libyaml-cpp.a 文件。将其与源码的 include 目录拷贝至工程目录,在编译时进行链接即可。

注:cmake须3.0以上。

测试

yaml 配置文件

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# yaml测试样例
# null 或 NULL 为关键字,不能写

# 名称
# 字符串
name: conf file

# 版本
# 如按浮点,2.0会转换成2
# 如按字符串,保留原样
version: 2.0

# 布尔类,转换为1或0
need: true

# 时间
time: 2020-10-03T09:21:13

empty: nul

# 对象
# 加双引号会转义\n,即会换行
my:
name: late \n lee
name1: "late \n lee"
age: 99

# 块
text: |
hello
world!

# 数组
fruit:
- apple
- apple1
- apple2
- apple3
- apple4
- apple5

# 多级数组
multi:
sta:
- 110 210 ddd 99
- 133 135 1 2 1588 1509
- 310-410
- 333-444

该示例基本涵盖了大部分的 yaml 格式。包括:字符串,数值、数组、多级map。

测试代码

测试代码如下:

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

#include <iostream>
#include "yaml-cpp/yaml.h"

using namespace std;

int main(int argc,char** argv)
{
YAML::Node config;
// 当文件不存在或yaml格式出错时,抛异常
try {
config = YAML::LoadFile("config.yaml");
} catch (...) {
printf("error loading file, yaml file error or not exist.\n");
return 0;
}


// 获取类型
for (YAML::const_iterator it = config.begin(); it != config.end(); ++it) {
std::string key = it->first.as<std::string>();
YAML::Node value = it->second;
switch (value.Type()) {
case YAML::NodeType::Scalar:
printf("key: %s scalar\n", key.c_str());
break;
case YAML::NodeType::Sequence:
printf("key: %s Sequence\n", key.c_str());
cout << "seq: " << value << endl;
break;
case YAML::NodeType::Map:
printf("key: %s Map\n", key.c_str());
break;
case YAML::NodeType::Null:
printf("key: %s Null\n", key.c_str());
break;
case YAML::NodeType::Undefined:
printf("key: %s Undefined\n", key.c_str());
break;
// etc.
}
}

// 顶层
cout << "version:" << config["version"].as<float>() << endl;
cout << "version(str):" << config["version"].as<string>() << endl;
cout << "need:" << config["need"].as<bool>() << endl; // 输出值为1
cout << "time:" << config["time"].as<string>() << endl;
cout << "empty:" << config["empty"].as<string>() << endl;

try {
printf("sizeof array: %d\n", (int)config["fruit"].size());
//cout << "fruit1:\n" << config["fruit"] << endl; // 此处返回 Node
// 索引方式取
//for (int i = 0; i < (int)config["fruit"].size(); i++)
//{
// cout << "fruit2: " << config["fruit"][i].as<string>() << endl;
//}
// 单个取
for (auto item : config["fruit"])
{
cout << "fruit3: " << item.as<string>() << endl;
}

} catch(...) {
printf("fruit not ok.\n");
}

try {
printf("new sta: \n");
for (auto item : config["multi"]["sta"])
{
printf("%s \n", item.as<string>().c_str());
}
printf("\n");
} catch (...) {
//printf("key not exist...\n");
//return 0;
}

// 对于不存在的key,似乎只能用try
try {
cout << "bad:" << config["bad"].as<int>() << endl;
} catch (...) {
printf("key bad not exist...\n");
//return 0;
}

cout << "text:" << config["text"].as<string>() << endl;
// 有两层
printf("name: %s \nname1: %s \nage: %d\n",
config["my"]["name"].as<string>().c_str(),
config["my"]["name1"].as<string>().c_str(),
config["my"]["age"].as<int>());


return 0;
}

输出结果如下:

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
31
32
33
34
35
36
37
38
39
40
41
42
./a.out 
key: name scalar
key: version scalar
key: need scalar
key: time scalar
key: empty scalar
key: my Map
key: text scalar
key: fruit Sequence
seq: - apple
- apple1
- apple2
- apple3
- apple4
- apple5
key: multi Map
version:2
version(str):2.0
need:1
time:2020-10-03T09:21:13
empty:nul
sizeof array: 6
fruit3: apple
fruit3: apple1
fruit3: apple2
fruit3: apple3
fruit3: apple4
fruit3: apple5
new sta:
110 210 ddd 99
133 135 1 2 1588 1509
310-410
333-444

key bad not exist...
text:hello
world!

name: late \n lee
name1: late
lee
age: 99

结果说明

1、name: "late \n lee" 输出会换行。而 name: late \n lee 则会原样输出。
2、参数的值不能为 null 或 NULL,但可以为nul。
3、如果字段不存在或非法,会直接报段错误,因此需要用 try catch 读取。