在 C++ 中解析 YAML 文件

发布于 2024-07-10 02:07:45 字数 621 浏览 8 评论 0 原文

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

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

任何人都可以给我指一个教程? (我用 google 搜索了至少 30 分钟,阅读了任何看起来相关的内容)或者有一个很好的教程或示例的库的名称。 也许您可以告诉我哪个 libyaml 测试会加载到文件中并对其执行某些操作,或者为什么会出现错误。 本文档不解释如何使用该文件 - 仅解释如何加载它:

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

I want a simple tutorial to show me how 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.

So far I ran multiple tests in the yaml-0.1.1 source code for C and I either get an error, no output whatsoever, or in the 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 because the file was bad or my build is incorrect (I didn't modify anything...) The file was copied from yaml.org

Can anyone point me to a tutorial? (I googled for at least 30 minutes 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 got errors. This document does not explain how to use the file--only how to load it:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

戏蝶舞 2024-07-17 02:07:45

尝试 yaml-cpp (按照 这个问题)适用于 C++ 解析器。

披露:我是作者。

示例语法(来自 教程):

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;

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

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;
雪落纷纷 2024-07-17 02:07:45

我在以下位置写了一篇教程
http://wpsoftware.net/andrew/pages/libyaml.html

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

I have written a tutorial at
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.

江南烟雨〆相思醉 2024-07-17 02:07:45

C 示例 - 将 YAML 树解析为 glib "N-ary树”

#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);
}

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

#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);
}
做个ˇ局外人 2024-07-17 02:07:45

作为 yaml-cpp 和 libyaml 的替代品,有 rapidyaml< /a>. 这是一个例子。

#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>

#include <ryml_std.hpp>
#include <ryml.hpp>

std::string get_file_contents(const char *filename)
{
    std::ifstream in(filename, std::ios::in | std::ios::binary);
    if (!in) {
        std::cerr << "could not open " << filename << std::endl;
        exit(1);
    }
    std::ostringstream contents;
    contents << in.rdbuf();
    return contents.str();
}

int main(int argc, char const *argv[]) 
{
    std::string contents = get_file_contents("config.yaml");
    ryml::Tree tree = ryml::parse_in_place(ryml::to_substr(contents));
    ryml::NodeRef foo = tree["foo"];
    for (ryml::NodeRef const& child : foo.children()) {
        std::cout << "key: " << child.key() << " val: " << child.val() << std::endl;
    }
    
    ryml::NodeRef array = tree["matrix"]["array"];
    for (ryml::NodeRef const& child : array.children()) {
        double val;
        child >> val;
        std::cout << "float val: " << std::setprecision (18) << val << std::endl;
    }
    return 0;
}

config.yaml

foo:
  bar: a
  barbar: b
  barbarbar: c

matrix:
  array:
    - 0.045533736417839546
    - 0.16564066086021373
    - 0.028658520327566304
    - 0.009133486414620372
    - -0.5801749091384203

更新

请注意,该项目递归地使用子模块,这就是 GitHub 上的“下载 ZIP”选项不起作用的原因。 使用 git

git clone --recurse-submodules -j8 https://github.com/biojppm/rapidyaml.git

考虑到您已经在 thirdparty/rapidyaml 中克隆了 rapidyaml,这里是一个最小的 cmake 配置。

CMakeLists.txt

cmake_minimum_required(VERSION 3.14)

project(so_answer VERSION 0.0.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_subdirectory(thirdparty/rapidyaml)

add_executable(example example.cpp)
target_include_directories(example PRIVATE thirdparty/rapidyaml/src)
target_link_libraries(example ryml)

As an alternative to yaml-cpp and libyaml there is rapidyaml. Here's an example.

#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>

#include <ryml_std.hpp>
#include <ryml.hpp>

std::string get_file_contents(const char *filename)
{
    std::ifstream in(filename, std::ios::in | std::ios::binary);
    if (!in) {
        std::cerr << "could not open " << filename << std::endl;
        exit(1);
    }
    std::ostringstream contents;
    contents << in.rdbuf();
    return contents.str();
}

int main(int argc, char const *argv[]) 
{
    std::string contents = get_file_contents("config.yaml");
    ryml::Tree tree = ryml::parse_in_place(ryml::to_substr(contents));
    ryml::NodeRef foo = tree["foo"];
    for (ryml::NodeRef const& child : foo.children()) {
        std::cout << "key: " << child.key() << " val: " << child.val() << std::endl;
    }
    
    ryml::NodeRef array = tree["matrix"]["array"];
    for (ryml::NodeRef const& child : array.children()) {
        double val;
        child >> val;
        std::cout << "float val: " << std::setprecision (18) << val << std::endl;
    }
    return 0;
}

config.yaml

foo:
  bar: a
  barbar: b
  barbarbar: c

matrix:
  array:
    - 0.045533736417839546
    - 0.16564066086021373
    - 0.028658520327566304
    - 0.009133486414620372
    - -0.5801749091384203

Update

Be aware that this project uses submodules recursively, that is why "Download ZIP" option on GitHub will not work. Use git

git clone --recurse-submodules -j8 https://github.com/biojppm/rapidyaml.git

Considering you have rapidyaml cloned in thirdparty/rapidyaml here is a minimal cmake configuration .

CMakeLists.txt

cmake_minimum_required(VERSION 3.14)

project(so_answer VERSION 0.0.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_subdirectory(thirdparty/rapidyaml)

add_executable(example example.cpp)
target_include_directories(example PRIVATE thirdparty/rapidyaml/src)
target_link_libraries(example ryml)
把梦留给海 2024-07-17 02:07:45

“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;
}

A Google Code Search (now defunct) for "yaml load lang:c++" gave this as the first link: 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文