用C++解析YAML文件

28 c++ yaml

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

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

谁能指点我一个教程?(我用谷歌搜索至少30分钟阅读任何看起来相关的东西)或者一个有一个很好的教程或例子的lib的名字.也许你可以告诉我哪些libyaml测试加载到文件中并对其执行某些操作或为什么会出现错误.本文档不解释如何使用该文件,仅说明如何加载它.

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

Jes*_*der 46

尝试使用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;
Run Code Online (Sandbox Code Playgroud)

  • 有包含标头和库的完整示例吗? (3认同)
  • 使用 [yaml-cpp](https://github.com/jbeder/yaml-cpp) 需要什么设置?我是否只需要下载头文件并将它们包含在我的 C++ 程序中? (2认同)
  • 不幸的是,yaml-cpp很难维护.发布不经常发生,有时候出现错误(Debian等发行版因上游不够快而恶化),截至2018年初,最新版本仍使用`auto_ptr`禁止在任何C++ 17项目中使用yaml-cpp. (2认同)
  • 我被证明是错误的,0.6.0版本是在我之前的评论后几个小时发布的。 (2认同)
  • @akim你怎么建这个东西?我已经花了好几个小时,我似乎无法建立它.我不断得到未定义的参考它让我疯狂. (2认同)
  • 请为此提供配置文件 (2认同)

小智 11

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

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


mk-*_*-fg 10

C示例 - 将YAML树解析为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);
}
Run Code Online (Sandbox Code Playgroud)

  • 你从哪里得到`yaml.h` (4认同)

Mik*_*san 8

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

#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;
}
Run Code Online (Sandbox Code Playgroud)

配置.yaml

foo:
  bar: a
  barbar: b
  barbarbar: c

matrix:
  array:
    - 0.045533736417839546
    - 0.16564066086021373
    - 0.028658520327566304
    - 0.009133486414620372
    - -0.5801749091384203
Run Code Online (Sandbox Code Playgroud)

更新

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

git clone --recurse-submodules -j8 https://github.com/biojppm/rapidyaml.git
Run Code Online (Sandbox Code Playgroud)

考虑到您已经在第三方/rapidyamlrapidyaml中克隆,这里是一个最小的 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)
Run Code Online (Sandbox Code Playgroud)


jfs*_*jfs 6

"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;
}
Run Code Online (Sandbox Code Playgroud)