Parse YAML Files in C++

后端 未结 4 1219
醉话见心
醉话见心 2020-12-07 18:28

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

相关标签:
4条回答
  • 2020-12-07 18:39

    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.

    0 讨论(0)
  • 2020-12-07 18:44

    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);
    }
    
    0 讨论(0)
  • 2020-12-07 18:46

    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;
    
    0 讨论(0)
  • 2020-12-07 18:54

    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;
    }
    
    0 讨论(0)
提交回复
热议问题