20

I'd like to obtain every node in a map without knowing the keys.

My YAML looks like this:

characterType :
 type1 :
  attribute1 : something
  attribute2 : something
 type2 :
  attribute1 : something
  attribute2 : something

I don't know how many "type"s will be declared or what the name of those keys will be. That's why I'm trying to iterate through the map.

struct CharacterType{
  std::string attribute1;
  std::string attribute2;
};

namespace YAML{
  template<>
  struct convert<CharacterType>{
    static bool decode(const Node& node, CharacterType& cType){ 
       cType.attribute1 = node["attribute1"].as<std::string>();
       cType.attribute2 = node["attribute2"].as<std::string>();
       return true;
    }
  };
}

---------------------
std::vector<CharacterType> cTypeList;

for(YAML::const_iterator it=node["characterType"].begin(); it != node["characterType"].end(); ++it){
   cTypeList.push_back(it->as<CharacterType>());
}

The previous code doesn't give any trouble when compiling but then at execution time I get this error: terminate called after throwing an instance of YAML::TypedBadConversion<CharacterType>

I've also tried using a subindex instead of the iterator, getting the same error.

I'm sure I'm doing something wrong, I just can't see it.

SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
delephin
  • 1,085
  • 1
  • 8
  • 10

2 Answers2

30

When you iterate through a map, the iterator points to a key/value pair of nodes, not a single node. For example:

YAML::Node characterType = node["characterType"];
for(YAML::const_iterator it=characterType.begin();it != characterType.end();++it) {
   std::string key = it->first.as<std::string>();       // <- key
   cTypeList.push_back(it->second.as<CharacterType>()); // <- value
}

(The reason that your code compiled, even though your node is a map node, is that YAML::Node is effectively dynamically typed, so its iterator has to act (statically) as both a sequence iterator and a map iterator.)

Jesse Beder
  • 33,081
  • 21
  • 109
  • 146
  • 1
    A bit offtopic, but I’d find it nice to have a way to get whole map (YAML structure) out as a string, I can’t seem to find any API document where such possibility are mentioned. – Smar Sep 17 '15 at 11:36
  • Also looks like if the value is empty, this error will be raised, instead of returning empty string... – Smar Sep 17 '15 at 11:39
  • @Smar, check out the Emitter. – Jesse Beder Sep 17 '15 at 14:18
  • @jesseBeder I wanted to just get the string for quick debugging instead of constructing something for it myself, but yeah, that could be used for it I guess :) – Smar Sep 18 '15 at 14:24
  • 2
    @Smar, look at YAML::Dump as a shorthand. – Jesse Beder Sep 18 '15 at 16:37
  • To anyone wondering, the official tutorial documentation to show this is here: https://github.com/jbeder/yaml-cpp/wiki/Tutorial#basic-parsing-and-node-editing See the `YAML::Node lineup` example under the "Basic Parsing and Node Editing" section. – Gabriel Staples Aug 25 '22 at 19:36
1

The answer from @jesse-beder is right, I give just another option with using range-based for loop like below:

for(const auto& characterType : node["characterType"]) {
   std::string key = characterType.first.as<std::string>();
   cTypeList.push_back(characterType.second.as<CharacterType>());
}
Nejc Galof
  • 2,538
  • 3
  • 31
  • 70