varch/doc/yaml.md
2025-05-10 21:28:42 +08:00

433 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 介绍
### 什么是YAML文件
YAMLYAML Ain't Markup Language是一种**人类可读的数据序列化格式**专注于简洁表达结构化数据。它广泛用于配置文件、数据交换和复杂数据结构的描述如Kubernetes、Ansible等工具的配置而非传统电子表格类的表格数据存储。
### YAML文件的特点
- **可读性高**
使用缩进和符号(如`-`、`:`表示层级关系类似自然语言的格式比JSON/XML更易阅读。
```yaml
user:
name: Alice
age: 30
hobbies:
- reading
- hiking
```
- **支持复杂数据结构**
可表示标量(字符串、数字)、列表、字典等类型,支持嵌套和多行文本(通过`|`或`>`)。
- **跨平台兼容**
纯文本格式,所有操作系统和编程语言均可解析。
- **与编程语言无缝集成**
大多数语言Python、Java、Go等提供原生或第三方库如PyYAML支持YAML解析。
### YAML的用途
1. **配置文件**(核心用途)
- 软件配置如Docker Compose、GitLab CI/CD
- 云原生工具配置Kubernetes manifests
```yaml
# Kubernetes Deployment示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
```
2. **数据序列化**
- 替代JSON/XML传输复杂数据
- API请求/响应的结构化数据描述
3. **数据交换**
- 不同系统间传递结构化信息(如微服务配置同步)
### 如何创建和编辑YAML文件
1. **文本编辑器**
- VS Code推荐安装YAML插件实现语法高亮和校验
- Sublime Text / Vim等
2. **专用工具**
- **Online YAML Validator**:校验语法有效性
- **yq**命令行工具类似jq用于处理YAML
### 注意事项
1. **缩进敏感**
- 必须使用空格通常2或4空格禁止使用Tab
- 缩进错误会导致解析失败
2. **键值对格式**
- 冒号后需有空格:`key: value`(而非`key:value`
3. **特殊字符处理**
- 字符串包含`:`、`#`等符号时建议使用引号:
```yaml
message: "Hello:World"
comment: "This is a # symbol"
```
4. **多行文本**
- 保留换行符:`|`
```yaml
description: |
This is a
multi-line
text.
```
- 折叠换行符:`>`
```yaml
summary: >
This will fold
into a single line.
```
5. **数据类型标记**
- 强制指定类型:
```yaml
boolean: !!bool "true"
timestamp: !!timestamp 2023-07-20T15:30:00Z
```
### 常见错误示例
```yaml
# 错误缩进混用空格和Tab
user:
name: Bob
age: 25 # 缩进不一致
# 错误:键值对缺少空格
key1:value1 # 应改为 key1: value1
# 错误:未转义特殊字符
message: Line 1
Line 2 # 缺少多行文本标识符
```
### C语言版YAML库
varch提供的YAML库简便易用能完成大部分对于YAML文件的基础操作包含对yaml的加载和保存增删改查等操作。
## 接口
### 创建和删除yaml对象
```c
yaml_t yaml_create(void);
void yaml_delete(yaml_t yaml);
```
其中**yaml_t**为yaml的结构体创建方法会生成一个空yaml对象。删除方法则删除指定的yaml对象。
### yaml对象加载
```c
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对象转储
```c
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添加子对象
```c
#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` 类方法实现的
```c
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移除子对象
```c
int yaml_remove(yaml_t yaml, const char* key, unsigned int index);
```
移除`yaml`对象中特定的键为`key`的第`index`个子对象。若移除成功,返回`YAML_E_OK`;若移除失败,返回相应的错误码。
### yaml对象属性操作
```c
int yaml_type(yaml_t yaml);
unsigned int yaml_size(yaml_t yaml);
```
- `yaml_type`:获取`yaml`对象的类型,返回值为`YAML_TYPE_*`系列宏定义的值,用于判断对象是`NULL`、布尔、整数、浮点数、字符串、序列、映射、文档、引用或复杂键等类型。
- `yaml_size`:获取`yaml`对象的大小。对于序列或映射类型的对象,返回其元素的数量;对于其他类型的对象,返回值的含义可能因具体实现而异。
### yaml对象比较和复制
```c
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对象键操作
```c
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对象值设置
```c
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对象值获取
```c
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对象子元素操作
```c
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对象索引和子对象获取
```c
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对象锚点和别名操作
```c
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文件
```c
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**
```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文件
```c
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
```