使用 libyaml 解析树状结构
Using libyaml to parse tree like structure
我是 YAML 的新手,我想解析以下 yaml 文件:
basket :
size : 10
type : organic
fruit1:
mango : 5
type : farm-fresh
fruit2:
peach : 43
manufacturer : xyz
color : brown
design : netted
...
yaml 文件将遵循上述格式,具有任意随机字符串名称和值(string、float、int 等)。
我想将这些值中的每一个存储在 struct
中,其中 key
和 values
作为字符数组。
struct Input {
char key[100]:
char value[100];
};
存在一个上述结构的数组来存储来自 yaml 文件的值。
因此来自 yaml 文件的数据应存储为:
//Input[x].key //Input[x].value
basket.size 10
basket.fruit1.mango 5
basket.fruit2.manufacturer xyz
basket.color brown
basket.desgin netted
我写了一个应用程序来解析yaml文件,我得到了一个单独的nodes/leaves作为字符串输出。因此,基于上述 yaml 文件,我得到的节点值为 basket
、size
、5
、43
等。我遵循了 here 定义的方法。到目前为止,这是我发现的学习 yaml 的好资源之一。
这种方法对我没有太大用处,因为我之前的节点与叶子之间没有任何关系,反之亦然。
libyaml
是否提供了一种在树中维护这种关系然后给出 return 以响应查询的方法。由于项目需要,我必须使用libyaml
。但也欢迎任何其他建议。
您链接的资源描述了几种解析 YAML 的方法。与教程中所说的相反,基于标记的解析根本没有用,除非您正在实现语法高亮显示。对于所有其他情况,您希望使用基于事件的解析。所以我假设您尝试使用它。
Does libyaml provide a way to maintain this relationship in a tree
基于事件的解析确实维护树结构(不确定树中的关系到底是什么意思),你得到…Start 和 …End 序列和映射的事件,描述输入结构。构建 struct Input
遍历事件流的列表非常简单:
#include <yaml.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
struct Input {
char key[100];
char value[100];
};
struct Input gen(const char *key, const char *value) {
struct Input ret;
strcpy(ret.key, key);
strcpy(ret.value, value);
return ret;
}
void append_all(yaml_parser_t *p, struct Input **target,
char cur_key[100], size_t len) {
yaml_event_t e;
yaml_parser_parse(p, &e);
switch (e.type) {
case YAML_MAPPING_START_EVENT:
yaml_event_delete(&e);
yaml_parser_parse(p, &e);
while (e.type != YAML_MAPPING_END_EVENT) {
// assume scalar key
assert(e.type == YAML_SCALAR_EVENT);
if (len != 0) cur_key[len++] = '.';
memcpy(cur_key + len, e.data.scalar.value,
strlen(e.data.scalar.value) + 1);
const size_t new_len = len + strlen(e.data.scalar.value);
yaml_event_delete(&e);
append_all(p, target, cur_key, new_len);
if (len != 0) --len;
cur_key[len] = '[=10=]'; // remove key part
yaml_parser_parse(p, &e);
}
break;
case YAML_SCALAR_EVENT:
*(*target)++ = gen(cur_key, e.data.scalar.value);
break;
default: assert(false);
}
yaml_event_delete(&e);
}
int main(int argc, char *argv[]) {
yaml_parser_t p;
yaml_event_t e;
yaml_parser_initialize(&p);
FILE *f = fopen("foo.yaml", "r");
yaml_parser_set_input_file(&p, f);
// skip stream start and document start
yaml_parser_parse(&p, &e);
yaml_event_delete(&e);
yaml_parser_parse(&p, &e);
yaml_event_delete(&e);
char cur_key[100] = {'[=10=]'};
struct Input input[100];
struct Input *input_end = input;
append_all(&p, &input_end, cur_key, 0);
// skip document end and stream end
yaml_parser_parse(&p, &e);
yaml_event_delete(&e);
yaml_parser_parse(&p, &e);
yaml_event_delete(&e);
yaml_parser_delete(&p);
fclose(f);
// print out input items
for (struct Input *cur = input; cur < input_end; ++cur) {
printf("%s = %s\n", cur->key, cur->value);
}
}
我是 YAML 的新手,我想解析以下 yaml 文件:
basket :
size : 10
type : organic
fruit1:
mango : 5
type : farm-fresh
fruit2:
peach : 43
manufacturer : xyz
color : brown
design : netted
...
yaml 文件将遵循上述格式,具有任意随机字符串名称和值(string、float、int 等)。
我想将这些值中的每一个存储在 struct
中,其中 key
和 values
作为字符数组。
struct Input {
char key[100]:
char value[100];
};
存在一个上述结构的数组来存储来自 yaml 文件的值。
因此来自 yaml 文件的数据应存储为:
//Input[x].key //Input[x].value
basket.size 10
basket.fruit1.mango 5
basket.fruit2.manufacturer xyz
basket.color brown
basket.desgin netted
我写了一个应用程序来解析yaml文件,我得到了一个单独的nodes/leaves作为字符串输出。因此,基于上述 yaml 文件,我得到的节点值为 basket
、size
、5
、43
等。我遵循了 here 定义的方法。到目前为止,这是我发现的学习 yaml 的好资源之一。
这种方法对我没有太大用处,因为我之前的节点与叶子之间没有任何关系,反之亦然。
libyaml
是否提供了一种在树中维护这种关系然后给出 return 以响应查询的方法。由于项目需要,我必须使用libyaml
。但也欢迎任何其他建议。
您链接的资源描述了几种解析 YAML 的方法。与教程中所说的相反,基于标记的解析根本没有用,除非您正在实现语法高亮显示。对于所有其他情况,您希望使用基于事件的解析。所以我假设您尝试使用它。
Does libyaml provide a way to maintain this relationship in a tree
基于事件的解析确实维护树结构(不确定树中的关系到底是什么意思),你得到…Start 和 …End 序列和映射的事件,描述输入结构。构建 struct Input
遍历事件流的列表非常简单:
#include <yaml.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
struct Input {
char key[100];
char value[100];
};
struct Input gen(const char *key, const char *value) {
struct Input ret;
strcpy(ret.key, key);
strcpy(ret.value, value);
return ret;
}
void append_all(yaml_parser_t *p, struct Input **target,
char cur_key[100], size_t len) {
yaml_event_t e;
yaml_parser_parse(p, &e);
switch (e.type) {
case YAML_MAPPING_START_EVENT:
yaml_event_delete(&e);
yaml_parser_parse(p, &e);
while (e.type != YAML_MAPPING_END_EVENT) {
// assume scalar key
assert(e.type == YAML_SCALAR_EVENT);
if (len != 0) cur_key[len++] = '.';
memcpy(cur_key + len, e.data.scalar.value,
strlen(e.data.scalar.value) + 1);
const size_t new_len = len + strlen(e.data.scalar.value);
yaml_event_delete(&e);
append_all(p, target, cur_key, new_len);
if (len != 0) --len;
cur_key[len] = '[=10=]'; // remove key part
yaml_parser_parse(p, &e);
}
break;
case YAML_SCALAR_EVENT:
*(*target)++ = gen(cur_key, e.data.scalar.value);
break;
default: assert(false);
}
yaml_event_delete(&e);
}
int main(int argc, char *argv[]) {
yaml_parser_t p;
yaml_event_t e;
yaml_parser_initialize(&p);
FILE *f = fopen("foo.yaml", "r");
yaml_parser_set_input_file(&p, f);
// skip stream start and document start
yaml_parser_parse(&p, &e);
yaml_event_delete(&e);
yaml_parser_parse(&p, &e);
yaml_event_delete(&e);
char cur_key[100] = {'[=10=]'};
struct Input input[100];
struct Input *input_end = input;
append_all(&p, &input_end, cur_key, 0);
// skip document end and stream end
yaml_parser_parse(&p, &e);
yaml_event_delete(&e);
yaml_parser_parse(&p, &e);
yaml_event_delete(&e);
yaml_parser_delete(&p);
fclose(f);
// print out input items
for (struct Input *cur = input; cur < input_end; ++cur) {
printf("%s = %s\n", cur->key, cur->value);
}
}