Использование libyaml для анализа древовидной структуры - PullRequest
0 голосов
/ 24 октября 2019

Я новичок в 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, и я получил отдельные узлы / листья в качестве вывода строки. Таким образом, основываясь на приведенных выше файлах yaml, я получаю значения узлов как basket, size, 5, 43 и т. Д. Я следовал подходу, определенному здесь . Это один из хороших ресурсов, которые я нашел для изучения yaml.

Этот подход не очень полезен для меня, так как я не имею никакого отношения между моими предыдущими узлами к листьям и наоборот.

Предоставляет ли libyaml способ поддерживать это отношение в дереве и затем возвращать ответ на запрос. Я обязан использовать libyaml из-за требований проекта. Но любые другие предложения также приветствуются.

1 Ответ

2 голосов
/ 25 октября 2019

Ресурс, который вы указали, описывает несколько способов анализа YAML. Синтаксический анализ на основе токенов, в отличие от того, что говорится в учебнике, совершенно бесполезен, если вы не используете подсветку синтаксиса. Во всех остальных случаях вы хотите использовать анализ на основе событий. Поэтому я предполагаю, что вы пытались использовать это.

Предоставляет ли libyaml способ поддерживать эти отношения в дереве

Анализ на основе событий делает поддерживая древовидную структуру (не уверен, что именно вы подразумеваете под отношением в дереве ), вы получаете … 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] = '\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);
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...