使用libyaml解析树状结构

使用libyaml解析树状结构,yaml,libyaml,Yaml,Libyaml,我是YAML的新手,我想解析以下YAML文件: basket : size : 10 type : organic fruit1: mango : 5 type : farm-fresh fruit2: peach : 43 manufacturer : xyz color : brown design : netted ... yaml文件将遵循上述格式,具有任意随机字符串名称和值(字符串、浮点、int等)。 我想将这些值存储在一个结构中,该结构具有键和值字符数

我是YAML的新手,我想解析以下YAML文件:

basket :
 size : 10
 type : organic
 fruit1:
  mango : 5
  type : farm-fresh
 fruit2:
  peach : 43
  manufacturer : xyz
 color : brown
 design : netted
 ...
yaml文件将遵循上述格式,具有任意随机字符串名称和值(字符串、浮点、int等)。 我想将这些值存储在一个
结构
中,该结构具有
字符数组

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文件,并将各个节点/叶作为字符串输出。因此,基于上述yaml文件,我得到的节点值为
basket
size
5
43
,等等。我遵循定义的方法。这是迄今为止我发现的学习yaml的好资源之一

这种方法对我没有多大用处,因为我以前的节点与叶子之间没有任何关系,反之亦然


libyaml
是否提供了一种在树中维护此关系的方法,然后在响应查询时返回。由于项目要求,我必须使用
libyaml
。但是任何其他建议都是受欢迎的。

您链接的资源介绍了几种解析YAML的方法。与教程中所说的相反,基于令牌的解析根本没有用处,除非您正在实现语法高亮。对于所有其他情况,您希望使用基于事件的解析。所以我假设你试过用它

libyaml是否提供了在树中维护这种关系的方法

基于事件的解析确实维护了树结构(不确定树中的关系到底是什么意思),您得到了序列和映射的开始和结束事件,这些事件描述了输入结构。构建遍历事件流的
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] = '\0'; // 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] = {'\0'};
  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);
  }
}
#包括
#包括
#包括
#包括
#包括
结构输入{
字符键[100];
字符值[100];
};
结构输入生成器(常量字符*键,常量字符*值){
结构输入ret;
strcpy(ret.key,key);
strcpy(ret.value,value);
返回ret;
}
void append_all(yaml_解析器_t*p,结构输入**目标,
字符电流键[100],大小(长度){
yaml_事件;
yaml_parser_parse(p&e);
开关(e型){
案例YAML\u映射\u开始\u事件:
yaml_事件_删除(&e);
yaml_parser_parse(p&e);
while(e.type!=YAML\u映射\u结束\u事件){
//假定标量键
断言(e.type==YAML\u标量\u事件);
如果(len!=0)cur_键[len++]=';
memcpy(cur_key+len,e.data.scalar.value,
strlen(e.data.scalar.value)+1);
const size\u t new\u len=len+strlen(e.data.scalar.value);
yaml_事件_删除(&e);
追加所有(p、目标、当前键、新列);
如果(len!=0)——len;
cur_key[len]='\0';//删除键部分
yaml_parser_parse(p&e);
}
打破
案例YAML_标量_事件:
*(*target)+=gen(cur_键,e.data.scalar.value);
打破
默认值:断言(false);
}
yaml_事件_删除(&e);
}
int main(int argc,char*argv[]){
yaml_parser_t p;
yaml_事件;
yaml_解析器_初始化(&p);
文件*f=fopen(“foo.yaml”,“r”);
yaml_解析器_集_输入_文件(&p,f);
//跳过流启动和文档启动
yaml_parser_parse(&p&e);
yaml_事件_删除(&e);
yaml_parser_parse(&p&e);
yaml_事件_删除(&e);
字符cur_键[100]={'\0'};
结构输入[100];
结构输入*输入\结束=输入;
追加所有(&p,&input\U end,cur\U键,0);
//跳过文档结束和流结束
yaml_parser_parse(&p&e);
yaml_事件_删除(&e);
yaml_parser_parse(&p&e);
yaml_事件_删除(&e);
yaml_解析器_删除(&p);
fclose(f);
//打印输入项
用于(结构输入*cur=Input;curkey,cur->value);
}
}

您链接的资源介绍了几种解析YAML的方法。与教程中所说的相反,基于令牌的解析根本没有用处,除非您正在实现语法高亮。对于所有其他情况,您希望使用基于事件的解析。所以我假设你试过用它

libyaml是否提供了在树中维护这种关系的方法

基于事件的解析确实维护了树结构(不确定树中的关系到底是什么意思),您得到了序列和映射的开始和结束事件,这些事件描述了输入结构。构建遍历事件流的
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] = '\0'; // 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] = {'\0'};
  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);
  }
}
#包括
#包括
#包括
#包括
#包括
结构输入{
字符键[100];
字符值[100];
};
结构输入生成器(常量字符*键,常量字符*值){
结构输入ret;
strcpy(ret.key,key);
strcpy(ret.value,value);
返回ret;
}
void append_all(yaml_解析器_t*p,结构输入**目标,
字符电流键[100],大小(长度){
yaml_事件;
yaml_parser_parse(p&e);
开关(e型){
案例YAML\u映射\u开始\u事件:
yaml_事件_删除(&e);
yaml_parser_parse(p&e);
while(e.type!=YAML\u映射\u结束\u事件){
//假定标量键
断言(e.type==YAML\u标量\u事件);
如果(len!=0)cur_键[len++]=';
memcpy(cur_key+len,e.data.scalar.value,
strlen(e.data.scalar.value)+1);
const size\u t new\u len=len+strlen(e.data.scalar.value);
yaml_事件_删除(&e);
追加所有(p、目标、当前键、新列);
如果(len!=0)——len;
cur_key[len]='\0';//删除键部分
yaml_parser_parse(p&e);
}
打破
案例YAML_标量_事件:
*(*target)+=gen(cur_键,e.data.scalar.value);
打破
默认值:断言(false);
}
yaml_事件_删除(&e);
}
int main(int argc,char*argv[]){
yaml_parser_t p;
yaml_事件;
yaml_解析器_初始化(&p);
文件*f=fopen(“foo.yaml”,“r”);
yaml_解析器_se