简体   繁体   中英

Add YAML values to std map using YAML-CPP

I have a yaml file which has nested maps in it:

SOLAR-SYSTEM:
  my/planet:
    earth: blue
  my/satellite:
    moon: white

I am using yaml-cpp to parse these values.

Is there any way I can pull out these values from the yaml file and add them to a stl map ?

Which brings me to second part of the question.

I am fairly new to C++ so not exactly sure how maps work in it.

In Java I parse the same yaml file using snakeyaml .

It adds the map to a triple hashmap data structure:

HashMap<String, Map<String, Map<String, String>>>

And I can conveniently do a get in this.

Is there any easy way to do something like this in C++?

I've used this great library for YAML parser for 2 days. So, I may also have some mistakes. I use yaml-cpp ver0.6.2.

The main idea is to build your own structure. After that, template specialization is used for specific types of transformation.

I think the structure of your document is not very good. It feels like nesting for std::map. I think you can look at this example Only for yaml file , Because these API are old

At last, you can pull the values into structures you've constructed.

I sorry, I'm poor in English. So show you my code. And you can ask me again if you have new problems.

Also, the code author is here. You may get more accurate answers from him .

struct Planet {
    std::string earth;
};

struct Satellite {
    std::string moon;
};

struct SolarSystem {
    Planet p;
    Satellite s;
};

namespace YAML {
template<>
struct convert<Planet> {
    static Node encode(const Planet &rhs) {
        Node node;
        node["earth"] = rhs.earth;
        return node;
    }

    static bool decode(const Node &node, Planet &rhs) {
        if (!node.IsMap())
            return false;
        rhs.earth = node["earth"].as<std::string>();
        return true;
    }
};

template<>
struct convert<Satellite> {
    static Node encode(const Satellite &rhs) {
        Node node;
        node["moon"] = rhs.moon;
        return node;
    }

    static bool decode(const Node &node, Satellite &rhs) {
        if (!node.IsMap())
            return false;
        rhs.moon = node["moon"].as<std::string>();
        return true;
    }
};

template<>
struct convert<SolarSystem> {
    static Node encode(const SolarSystem &rhs) {
        Node node;
        node["my/planet"] = rhs.p;
        node["my/satellite"] = rhs.s;
        return node;
    }

    static bool decode(const Node &node, SolarSystem &rhs) {
        if (!node.IsMap())
            return false;

        rhs.p = node["my/planet"].as<Planet>();
        rhs.s = node["my/satellite"].as<Satellite>();
        return true;
    }
};
}

int main(void)
{
    YAML::Node doc = YAML::LoadFile("path/to/your/file");
    SolarSystem ss = doc["SOLAR-SYSTEM"].as<SolarSystem>();

    std::cout << ss.p.earth << std::endl;      // "blue"
    std::cout << ss.s.moon << std::endl;       // "white"

    return 0;
}

Not sure why it was downvoted. Thanks to @Crow for the answer. I couldn't use it as it involved hard coding the values. Here is the solution i devised:

try {
        YAML::Node firstTierNode = YAML::LoadFile("config.yml");

        std::map<std::string, std::map<std::string, std::map<std::string, std::string>>> newMap1;
        for (YAML::const_iterator it = firstTierNode.begin(); it != firstTierNode.end(); ++it) {

            string level1First = it->first.as<std::string>();

            YAML::Node secondTierNode = it->second;

            std::map<std::string, std::map<std::string, std::string>>  newMap2;
            for (YAML::const_iterator it = secondTierNode.begin(); it != secondTierNode.end(); ++it) {

                string level2First = it->first.as<std::string>();

                YAML::Node thirdTierNode = it->second;

                std::map<std::string, std::string> newMap3;
                for (YAML::const_iterator it = thirdTierNode.begin(); it != thirdTierNode.end(); ++it) {

                    string level3First = it->first.as<std::string>();

                    string level3SecondString = it->second.as<std::string>();

                    newMap3.insert(std::pair<std::string, std::string>(level3First, level3SecondString));
                }

                newMap2.insert(std::pair<std::string, std::map<string, string>>(level2First, newMap3));

            }

            newMap1.insert(std::pair<std::string, std::map<string, std::map<string, string>>>(level1First, newMap2));

        }

        for (const auto& x : newMap1) {
            std::cout <<x.first << endl << endl;
            for (const auto& y : x.second) {
                std::cout << y.first << endl << endl;
                for (const auto& z : y.second) {
                    std::cout << z.first << endl << z.second << endl << endl << endl;
                }
            }
        }

        return 1;
    }
    catch (exception& e) {
            cerr <<e.what()<< endl;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM