-1

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++?

Bsquare ℬℬ
  • 4,423
  • 11
  • 24
  • 44
hal9000
  • 201
  • 5
  • 25

2 Answers2

1

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;
}
Anthon
  • 69,918
  • 32
  • 186
  • 246
Crow
  • 35
  • 7
  • Welcome to [so]. Asking questions in an answer is not really appropriate. Either write a comment (once you have enough reputation) asking the OP which version (s)he/it is using. You can just write your version information so it is clear what you used. If the OP has a different, incompatible version, you'll probably get a comment stating that. – Anthon Nov 11 '18 at 15:09
  • @Anthon Thanks for your suggestion, my answer may be so verbose.I will make it concise and clear at next answer – Crow Nov 12 '18 at 12:00
  • 1
    I don't think your answer is too verbose. I have made much more verbose ones. Just restrict yourself to statement. And if some aspect in the question is not 100% clear, just state what assumption you made. Or do something like "If you have version x.y, then ... and if you have version x.z you do .... For older versions I don't think ....." – Anthon Nov 12 '18 at 15:46
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;
    }
hal9000
  • 201
  • 5
  • 25