用 C++ 解析 YAML 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/365155/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:58:09  来源:igfitidea点击:

Parse YAML Files in C++

c++yaml

提问by Jesse Beder

I want a simple tutorial to show me to load a yaml file and parse the data. Expat style would be great but any solution that actually shows me the data in some form would be useful.

我想要一个简单的教程来向我展示如何加载 yaml 文件并解析数据。外派风格会很棒,但任何以某种形式实际向我展示数据的解决方案都会很有用。

So far I ran multiple test in yaml-0.1.1 source for C and I either get an error, no output what so ever or in run-emitter.c case. It reads in the yaml file and prints it to STDOUT, it does not produce the text via libyaml functions/structs. In the cases with an error I don't know if it was bc the file was bad or my build is incorrect (I didn't modify anything...) The file was copied from yaml.org

到目前为止,我在 yaml-0.1.1 源代码中为 C 运行了多个测试,我要么得到一个错误,要么没有输出,要么在 run-emitter.c 的情况下。它读入 yaml 文件并将其打印到 STDOUT,它不会通过 libyaml 函数/结构生成文本。在出现错误的情况下,我不知道是因为文件坏了还是我的构建不正确(我没有修改任何东西...)该文件是从 yaml.org 复制的

Can anyone point me to a tutorial? (I googled for at least 30mins reading anything that looked relevant) or a name of a lib that has a good tutorial or example. Maybe you can tell me which libyaml test loads in files and does something with it or why I gotten errors. This document does not explain how to use the file, only how to load it.

谁能给我指点教程?(我用谷歌搜索了至少 30 分钟,阅读了任何看起来相关的内容)或具有良好教程或示例的库的名称。也许您可以告诉我在文件中加载了哪些 libyaml 测试并对其进行了处理,或者为什么我会出错。本文档不解释如何使用该文件,只解释如何加载它。

http://pyyaml.org/wiki/LibYAML#Documentation

http://pyyaml.org/wiki/LibYAML#Documentation

回答by Jesse Beder

Try yaml-cpp(as suggested by this question) for a C++ parser.

为 C++ 解析器尝试yaml-cpp(如本问题所建议)。

Disclosure: I'm the author.

披露:我是作者。

Example syntax (from the Tutorial):

示例语法(来自教程):

YAML::Node config = YAML::LoadFile("config.yaml");

if (config["lastLogin"]) {
  std::cout << "Last logged in: " << config["lastLogin"].as<DateTime>() << "\n";
}

const std::string username = config["username"].as<std::string>();
const std::string password = config["password"].as<std::string>();
login(username, password);
config["lastLogin"] = getCurrentDateTime();

std::ofstream fout("config.yaml");
fout << config;

回答by apoelstra

I have written a tutorial at http://wpsoftware.net/andrew/pages/libyaml.html.

我在http://wpsoftware.net/andrew/pages/libyaml.html写了一个教程 。

This covers the basics of using libyaml in C, using token-based and event-based parsing. It includes sample code for outputting the contents of a YAML file.

这涵盖了在 C 中使用 libyaml 的基础知识,使用基于令牌和基于事件的解析。它包括用于输出 YAML 文件内容的示例代码。

回答by mk-fg

C example - parsing YAML tree to a glib "N-ary tree":

C 示例 - 将 YAML 树解析为glib “N 元树”

#include <yaml.h>
#include <stdio.h>
#include <glib.h>

void process_layer(yaml_parser_t *parser, GNode *data);
gboolean dump(GNode *n, gpointer data);



int main (int argc, char **argv) {
    char *file_path = "test.yaml";
    GNode *cfg = g_node_new(file_path);
    yaml_parser_t parser;

    FILE *source = fopen(file_path, "rb");
    yaml_parser_initialize(&parser);
    yaml_parser_set_input_file(&parser, source);
    process_layer(&parser, cfg); // Recursive parsing
    yaml_parser_delete(&parser);
    fclose(source);

    printf("Results iteration:\n");
    g_node_traverse(cfg, G_PRE_ORDER, G_TRAVERSE_ALL, -1, dump, NULL);
    g_node_destroy(cfg);

    return(0);
}



enum storage_flags { VAR, VAL, SEQ }; // "Store as" switch

void process_layer(yaml_parser_t *parser, GNode *data) {
    GNode *last_leaf = data;
    yaml_event_t event;
    int storage = VAR; // mapping cannot start with VAL definition w/o VAR key

    while (1) {
        yaml_parser_parse(parser, &event);

        // Parse value either as a new leaf in the mapping
        //  or as a leaf value (one of them, in case it's a sequence)
        if (event.type == YAML_SCALAR_EVENT) {
            if (storage) g_node_append_data(last_leaf, g_strdup((gchar*) event.data.scalar.value));
            else last_leaf = g_node_append(data, g_node_new(g_strdup((gchar*) event.data.scalar.value)));
            storage ^= VAL; // Flip VAR/VAL switch for the next event
        }

        // Sequence - all the following scalars will be appended to the last_leaf
        else if (event.type == YAML_SEQUENCE_START_EVENT) storage = SEQ;
        else if (event.type == YAML_SEQUENCE_END_EVENT) storage = VAR;

        // depth += 1
        else if (event.type == YAML_MAPPING_START_EVENT) {
            process_layer(parser, last_leaf);
            storage ^= VAL; // Flip VAR/VAL, w/o touching SEQ
        }

        // depth -= 1
        else if (
            event.type == YAML_MAPPING_END_EVENT
            || event.type == YAML_STREAM_END_EVENT
        ) break;

        yaml_event_delete(&event);
    }
}


gboolean dump(GNode *node, gpointer data) {
    int i = g_node_depth(node);
    while (--i) printf(" ");
    printf("%s\n", (char*) node->data);
    return(FALSE);
}

回答by jfs

A Google Code Search (now defunct) for "yaml load lang:c++" gave this as the first link: demo.cc:

“yaml load lang:c++” 的 Google 代码搜索(现已失效)将其作为第一个链接:demo.cc

#include <iyaml++.hh>
#include <tr1/memory>
#include <iostream>
#include <stdexcept>

using namespace std;

// What should libyaml++ do when a YAML entity is parsed?
// NOTE:  if any of the event handlers is not defined, a respective default
// no-op handler will be used.  For example, not defining on_eos() is
// equivalent to defining void on_eos() { }.
class my_handler : public yaml::event_handler {
    void on_string(const std::string& s) { cout << "parsed string:  " << s << endl; }
    void on_integer(const std::string& s) { cout << "parsed integer:  " << s << endl; }
    void on_sequence_begin() { cout << "parsed sequence-begin." << endl; }
    void on_mapping_begin() { cout << "parsed mapping-begin." << endl; }
    void on_sequence_end() { cout << "parsed sequence-end." << endl; }
    void on_mapping_end() { cout << "parsed mapping-end." << endl; }
    void on_document() { cout << "parsed document." << endl; }
    void on_pair() { cout << "parsed pair." << endl; }
    void on_eos() { cout << "parsed eos." << endl; }
};

// ok then, now that i know how to behave on each YAML entity encountered, just
// give me a stream to parse!
int main(int argc, char* argv[])
{
    tr1::shared_ptr<my_handler> handler(new my_handler());
    while( cin ) {
        try { yaml::load(cin, handler); } // throws on syntax error

        catch( const runtime_error& e ) {
            cerr << e.what() << endl;
        }
    }
    return 0;
}