18 KiB
介绍
什么是YAML文件?
YAML(YAML Ain't Markup Language)是一种人类可读的数据序列化格式,专注于简洁表达结构化数据。它广泛用于配置文件、数据交换和复杂数据结构的描述(如Kubernetes、Ansible等工具的配置),而非传统电子表格类的表格数据存储。
YAML文件的特点
- 可读性高:
使用缩进和符号(如-、:)表示层级关系,类似自然语言的格式,比JSON/XML更易阅读。
user:
name: Alice
age: 30
hobbies:
- reading
- hiking
-
支持复杂数据结构:
可表示标量(字符串、数字)、列表、字典等类型,支持嵌套和多行文本(通过|或>)。 -
跨平台兼容:
纯文本格式,所有操作系统和编程语言均可解析。 -
与编程语言无缝集成:
大多数语言(Python、Java、Go等)提供原生或第三方库(如PyYAML)支持YAML解析。
YAML的用途
- 配置文件(核心用途)
- 软件配置(如Docker Compose、GitLab CI/CD)
- 云原生工具配置(Kubernetes manifests)
# Kubernetes Deployment示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
- 数据序列化
- 替代JSON/XML传输复杂数据
- API请求/响应的结构化数据描述
- 数据交换
- 不同系统间传递结构化信息(如微服务配置同步)
如何创建和编辑YAML文件?
- 文本编辑器
- VS Code(推荐安装YAML插件实现语法高亮和校验)
- Sublime Text / Vim等
- 专用工具
- Online YAML Validator:校验语法有效性
- yq:命令行工具(类似jq,用于处理YAML)
注意事项
- 缩进敏感
- 必须使用空格(通常2或4空格,禁止使用Tab)
- 缩进错误会导致解析失败
- 键值对格式
- 冒号后需有空格:
key: value(而非key:value)
- 特殊字符处理
- 字符串包含
:、#等符号时建议使用引号:
message: "Hello:World"
comment: "This is a # symbol"
- 多行文本
- 保留换行符:
|
description: |
This is a
multi-line
text.
- 折叠换行符:
>
summary: >
This will fold
into a single line.
- 数据类型标记
- 强制指定类型:
boolean: !!bool "true"
timestamp: !!timestamp 2023-07-20T15:30:00Z
常见错误示例
# 错误:缩进混用空格和Tab
user:
name: Bob
age: 25 # 缩进不一致
# 错误:键值对缺少空格
key1:value1 # 应改为 key1: value1
# 错误:未转义特殊字符
message: Line 1
Line 2 # 缺少多行文本标识符
C语言版YAML库
varch提供的YAML库,简便易用,能完成大部分对于YAML文件的基础操作,包含对yaml的加载和保存,增删改查等操作。
接口
创建和删除yaml对象
yaml_t yaml_create(void);
void yaml_delete(yaml_t yaml);
其中yaml_t为yaml的结构体,创建方法会生成一个空yaml对象。删除方法则删除指定的yaml对象。
yaml对象加载
yaml_t yaml_loads(const char* text, int flag);
yaml_t yaml_file_load(char* filename, int flag);
yaml对象可以从字符串文本中加载,也可以从文件中加载。加载成功则会返回一个yaml对象,失败则返回NULL。 flag为操作函数的一些flag,定义如下:
#define YAML_F_NONE (0)
#define YAML_F_DFLOW (0x01) /* dumps flow format */
#define YAML_F_LDOCS (0x02) /* load muti documents */
#define YAML_F_NOKEY (0x04) /* operate without key */
#define YAML_F_COMPLEX (0x08) /* operate with complex key */
#define YAML_F_ANCHOR (0x10) /* operate with anchor */
#define YAML_F_RECURSE (0x20) /* operate recurse */
#define YAML_F_REFERENCE (0x40) /* operate with reference */
当yaml对象加载失败的时候,可以调用int yaml_error_info(int* line, int* column);函数进行定位错误。
错误类型包含
#define YAML_E_OK (0) /* ok, no error */
#define YAML_E_INVALID (1) /* invalid, not a valid expected value */
#define YAML_E_END (2) /* many invalid characters appear at the end */
#define YAML_E_KEY (3) /* parsing key, invalid key content found */
#define YAML_E_VALUE (4) /* parsing value, invalid value content found */
#define YAML_E_MEMORY (5) /* memory allocation failed */
#define YAML_E_SQUARE (6) /* mising ']' */
#define YAML_E_CURLY (7) /* mising '}' */
#define YAML_E_TAB (8) /* incorrect indent depth */
#define YAML_E_MIX (9) /* mix type */
#define YAML_E_FLINE (10) /* the first line of value can only be a literal */
#define YAML_E_LNUMBER (11) /* the number exceeds the storage capacity */
#define YAML_E_LBREAK (12) /* line break */
#define YAML_E_NANCHOR (13) /* null anchor */
#define YAML_E_IANCHOR (14) /* invalid anchor */
#define YAML_E_RANCHOR (15) /* repeat anchor */
#define YAML_E_UANCHOR (16) /* undefine anchor */
#define YAML_E_TANCHOR (17) /* type error anchor */
#define YAML_E_DATE (18) /* date error */
#define YAML_E_TARTGET (19) /* date error */
yaml对象转储
char* yaml_dumps(yaml_t yaml, int preset, int* len, int flag);
int yaml_file_dump(yaml_t yaml, char* filename);
首先yaml_dumps方法,将yaml对象按格式转储为字符串。*len则是转换出来的字符串长度,传入NULL时候就是不获取长度。返回值则是转换出来的字符串,这个字符串是函数分配的,在结束使用需要free掉。
yaml_file_dump方法则是在yaml_dumps的基础上将yaml转储到文件当中,filename传入文件名,返回值为转储的长度,负值表示转储失败。
yaml添加子对象
#define yaml_seq_add_null(yaml)
#define yaml_seq_add_int(yaml, num)
#define yaml_seq_add_float(yaml, num)
#define yaml_seq_add_string(yaml, string)
#define yaml_seq_add_sequence(yaml, sequence)
#define yaml_seq_add_mapping(yaml, mapping)
#define yaml_map_add_null(yaml, key)
#define yaml_map_add_int(yaml, key, num)
#define yaml_map_add_float(yaml, key, num)
#define yaml_map_add_string(yaml, key, string)
#define yaml_map_add_sequence(yaml, key, sequence)
#define yaml_map_add_mapping(yaml, key, mapping)
以上方法分别在序列中和在映射中添加标量,其实就是套用 insert 类方法实现的
yaml_t yaml_insert_null(yaml_t yaml, const char* key, unsigned int index);
yaml_t yaml_insert_bool(yaml_t yaml, const char* key, unsigned int index, int b);
yaml_t yaml_insert_int(yaml_t yaml, const char* key, unsigned int index, int num);
yaml_t yaml_insert_float(yaml_t yaml, const char* key, unsigned int index, double num);
yaml_t yaml_insert_string(yaml_t yaml, const char* key, unsigned int index, const char* string);
yaml_t yaml_insert_sequence(yaml_t yaml, const char* key, unsigned int index, yaml_t sequence);
yaml_t yaml_insert_mapping(yaml_t yaml, const char* key, unsigned int index, yaml_t mapping);
yaml_t yaml_insert_document(yaml_t yaml, unsigned int index, yaml_t document);
yaml_t yaml_insert_reference(yaml_t yaml, const char* key, unsigned int index, const char* anchor, yaml_t doc);
这些insert类方法用于在yaml对象的指定位置插入不同类型的子对象。key为插入对象的键,index为插入的位置。返回值为插入操作后的yaml对象,若插入失败则返回NULL。具体如下:
yaml_insert_null:插入一个空类型的子对象。yaml_insert_bool:插入一个布尔类型的子对象,b为布尔值(YAML_FALSE或YAML_TRUE)。yaml_insert_int:插入一个整数类型的子对象,num为整数值。yaml_insert_float:插入一个浮点数类型的子对象,num为浮点数值。yaml_insert_string:插入一个字符串类型的子对象,string为字符串值。yaml_insert_sequence:插入一个序列类型的子对象,sequence为序列对象。yaml_insert_mapping:插入一个映射类型的子对象,mapping为映射对象。yaml_insert_document:插入一个文档类型的子对象,document为文档对象。yaml_insert_reference:插入一个引用类型的子对象,anchor为引用的锚点,doc为引用的文档对象。
yaml移除子对象
int yaml_remove(yaml_t yaml, const char* key, unsigned int index);
移除yaml对象中特定的键为key的第index个子对象。若移除成功,返回YAML_E_OK;若移除失败,返回相应的错误码。
yaml对象属性操作
int yaml_type(yaml_t yaml);
unsigned int yaml_size(yaml_t yaml);
yaml_type:获取yaml对象的类型,返回值为YAML_TYPE_*系列宏定义的值,用于判断对象是NULL、布尔、整数、浮点数、字符串、序列、映射、文档、引用或复杂键等类型。yaml_size:获取yaml对象的大小。对于序列或映射类型的对象,返回其元素的数量;对于其他类型的对象,返回值的含义可能因具体实现而异。
yaml对象比较和复制
int yaml_compare(yaml_t yaml, yaml_t cmp, int flag);
yaml_t yaml_copy(yaml_t yaml, int flag);
yaml_compare:比较两个yaml对象。flag为比较的标志位,用于指定比较的方式。返回值为比较结果,具体含义由实现决定,通常 0 表示相等,非 0 表示不相等。yaml_copy:复制一个yaml对象。flag为复制的标志位,用于指定复制的方式。返回值为复制后的yaml对象,若复制失败则返回NULL。
yaml对象键操作
yaml_t yaml_set_key(yaml_t yaml, const char* key);
yaml_t yaml_set_key_complex(yaml_t yaml, yaml_t key);
const char* yaml_key(yaml_t yaml);
yaml_t yaml_key_complex(yaml_t yaml);
yaml_set_key:为yaml对象设置一个简单键,key为键的字符串值。返回值为设置键后的yaml对象。yaml_set_key_complex:为yaml对象设置一个复杂键,key为复杂键的yaml对象。返回值为设置键后的yaml对象。yaml_key:获取yaml对象的简单键,返回值为键的字符串值。yaml_key_complex:获取yaml对象的复杂键,返回值为复杂键的yaml对象。
yaml对象值设置
yaml_t yaml_set_null(yaml_t yaml);
yaml_t yaml_set_bool(yaml_t yaml, int b);
yaml_t yaml_set_int(yaml_t yaml, int num);
yaml_t yaml_set_float(yaml_t yaml, double num);
yaml_t yaml_set_string(yaml_t yaml, const char* string);
yaml_t yaml_set_date(yaml_t yaml, int year, char month, char day);
yaml_t yaml_set_time(yaml_t yaml, char hour, char minute, char second, int msec);
yaml_t yaml_set_utc(yaml_t yaml, char hour, char minute);
yaml_t yaml_set_sequence(yaml_t yaml, yaml_t sequence);
yaml_t yaml_set_mapping(yaml_t yaml, yaml_t mapping);
yaml_t yaml_set_document(yaml_t yaml, yaml_t document);
这些方法用于设置yaml对象的值,返回值为设置值后的yaml对象。具体如下:
yaml_set_null:将yaml对象的值设置为空类型。yaml_set_bool:将yaml对象的值设置为布尔类型,b为布尔值(YAML_FALSE或YAML_TRUE)。yaml_set_int:将yaml对象的值设置为整数类型,num为整数值。yaml_set_float:将yaml对象的值设置为浮点数类型,num为浮点数值。yaml_set_string:将yaml对象的值设置为字符串类型,string为字符串值。yaml_set_date:将yaml对象的值设置为日期类型,year为年份,month为月份,day为日期。yaml_set_time:将yaml对象的值设置为时间类型,hour为小时,minute为分钟,second为秒,msec为毫秒。yaml_set_utc:将yaml对象的值设置为 UTC 时间偏移类型,hour为小时偏移,minute为分钟偏移。yaml_set_sequence:将yaml对象的值设置为序列类型,sequence为序列对象。yaml_set_mapping:将yaml对象的值设置为映射类型,mapping为映射对象。yaml_set_document:将yaml对象的值设置为文档类型,document为文档对象。
yaml对象值获取
int yaml_value_bool(yaml_t yaml);
int yaml_value_int(yaml_t yaml);
double yaml_value_float(yaml_t yaml);
const char* yaml_value_string(yaml_t yaml);
yaml_t yaml_value_sequence(yaml_t yaml);
yaml_t yaml_value_mapping(yaml_t yaml);
yaml_t yaml_value_document(yaml_t yaml);
这些方法用于获取yaml对象的值,返回值为获取到的值。具体如下:
yaml_value_bool:获取yaml对象的布尔值。yaml_value_int:获取yaml对象的整数值。yaml_value_float:获取yaml对象的浮点数值。yaml_value_string:获取yaml对象的字符串值。yaml_value_sequence:获取yaml对象的序列值,返回序列对象。yaml_value_mapping:获取yaml对象的映射值,返回映射对象。yaml_value_document:获取yaml对象的文档值,返回文档对象。
yaml对象子元素操作
yaml_t yaml_attach(yaml_t yaml, unsigned int index, yaml_t attach);
yaml_t yaml_dettach(yaml_t yaml, unsigned int index);
yaml_attach:在yaml对象的指定位置index附加一个yaml子对象attach。返回值为操作后的yaml对象,若操作失败则返回NULL。yaml_dettach:从yaml对象的指定位置index分离一个子对象。返回值为分离出的子对象,若操作失败则返回NULL。
yaml对象索引和子对象获取
unsigned int yaml_get_index(yaml_t yaml, const char* key, unsigned int index);
unsigned int yaml_get_index_complex(yaml_t yaml, yaml_t key);
yaml_t yaml_get_child(yaml_t yaml, const char* key, unsigned int index);
yaml_t yaml_get_child_complex(yaml_t yaml, yaml_t key);
yaml_get_index:获取yaml对象中键为key的第index个子对象的索引。返回值为子对象的索引,若未找到则返回YAML_INV_INDEX。yaml_get_index_complex:获取yaml对象中复杂键为key的子对象的索引。返回值为子对象的索引,若未找到则返回YAML_INV_INDEX。yaml_get_child:获取yaml对象中键为key的第index个子对象。返回值为子对象的yaml对象,若未找到则返回NULL。yaml_get_child_complex:获取yaml对象中复杂键为key的子对象。返回值为子对象的yaml对象,若未找到则返回NULL。
yaml对象锚点和别名操作
const char* yaml_get_alias(yaml_t yaml);
yaml_t yaml_get_anchor(yaml_t yaml, unsigned int index);
yaml_t yaml_set_alias(yaml_t yaml, const char* alias, yaml_t doc);
yaml_t yaml_set_anchor(yaml_t yaml, const char* anchor, yaml_t doc);
unsigned int yaml_anchor_size(yaml_t yaml);
yaml_get_alias:获取yaml对象的别名,返回值为别名的字符串值。yaml_get_anchor:获取yaml对象中指定索引index的锚点对象,返回值为锚点的yaml对象。yaml_set_alias:为yaml对象设置别名,alias为别名的字符串值,doc为关联的文档对象。返回值为设置别名后的yaml对象。yaml_set_anchor:为yaml对象设置锚点,anchor为锚点的字符串值,doc为关联的文档对象。返回值为设置锚点后的yaml对象。yaml_anchor_size:获取yaml对象中锚点的数量。返回值为锚点的数量。
参考例子
生成yaml文件
static void test_dump(void)
{
yaml_t root, node, temp;
root = yaml_create();
yaml_set_mapping(root, NULL);
node = yaml_map_add_mapping(root, "mapping", NULL);
yaml_map_add_string(node, "version", "1.0.0");
yaml_map_add_string(node, "author", "Lamdonn");
yaml_map_add_string(node, "license", "GPL-2.0");
node = yaml_map_add_sequence(root, "sequence", NULL);
yaml_seq_add_string(node, "file description");
yaml_seq_add_string(node, "This is a C language version of yaml streamlined parser");
yaml_seq_add_string(node, "Copyright (C) 2023 Lamdonn.");
temp = yaml_seq_add_mapping(node, NULL);
yaml_map_add_string(temp, "age", "18");
yaml_map_add_string(temp, "height", "178cm");
yaml_map_add_string(temp, "weight", "75kg");
yaml_remove(temp, 0, 1);
/* preview yaml */
yaml_preview(root);
/* dump yaml file */
yaml_file_dump(root, WRITE_FILE);
yaml_delete(root);
}
转储的文件 write.yaml
mapping:
version: 1.0.0
author: Lamdonn
license: GPL-2.0
sequence:
- file description
- This is a C language version of yaml streamlined parser
- Copyright (C) 2023 Lamdonn.
-
age: 18
weight: 75kg
加载yaml文件
同样加载yaml文件
static void test_load(void)
{
yaml_t root = NULL, x = NULL;
root = yaml_file_load(READ_FILE, YAML_F_LDOCS);
if (!root)
{
int type = 0, line = 0, column = 0;
type = yaml_error_info(&line, &column);
printf("error at line %d column %d type %d.\r\n", line, column, type);
return;
}
printf("load success!\r\n");
yaml_preview(root);
yaml_delete(root);
}
运行结果:
load success!
mapping:
version: 1.0.0
author: Lamdonn
license: GPL-2.0
sequence:
- file description
- This is a C language version of yaml streamlined parser
- Copyright (C) 2023 Lamdonn.
-
age: 18
weight: 75kg