4

I am using yaml-cpp 0.3.0 (old API version) to parse a yaml file (which I got from here).

This is the yaml file:

- name: Ogre
  position: [0, 5, 0]
  powers:
    - name: Club
      damage: 10
    - name: Fist
      damage: 8
- name: Dragon
  position: [1, 0, 10]
  powers:
    - name: Fire Breath
      damage: 25
    - name: Claws
      damage: 15
- name: Wizard
  position: [5, -3, 0]
  powers:
    - name: Acid Rain
      damage: 50
    - name: Staff
      damage: 3

And now I try to parse the powers name and damage with this code:

#include "yaml-cpp/yaml.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

// our data types
struct Vec3 {
   float x, y, z;
};

struct Power {
   std::string name;
   int damage;
};

struct Monster {
   std::string name;
   Vec3 position;
   std::vector <Power> powers;
};

// now the extraction operators for these types
void operator >> (const YAML::Node& node, Vec3& v) {
   node[0] >> v.x;
   node[1] >> v.y;
   node[2] >> v.z;
}

void operator >> (const YAML::Node& node, Power& power) {
   node["name"] >> power.name;
   node["damage"] >> power.damage;
}

void operator >> (const YAML::Node& node, Monster& monster) {
   node["name"] >> monster.name;
   node["position"] >> monster.position;
   const YAML::Node& powers = node["powers"];
   for(unsigned i=0;i<powers.size();i++) {
      Power power;
      powers[i] >> power;
      monster.powers.push_back(power);
   }
}

int main()
{
   std::ifstream fin("robot.yaml");
   YAML::Parser parser(fin);
   YAML::Node doc;
   parser.GetNextDocument(doc);
   for(unsigned i=0;i<doc.size();i++) {
      Power power;
      doc[i] ["powers"] >> power;
      std::cout << power.name << "\n";
      std::cout << power.damage << "\n";
   }

   return 0;
}

It seems that my code shows error like this :

terminate called after throwing an instance of 'YAML::TypedKeyNotFound<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >'
  what():  yaml-cpp: error at line 4, column 5: key not found: name
Aborted (core dumped)

Please help me understand why can't I parse the powers element.

And please explain to me how can I parse all the key & values in one code since I am new with coding.

Prateek Gupta
  • 2,422
  • 2
  • 16
  • 30
Syam_Keyek
  • 41
  • 1
  • 2

1 Answers1

1

So the problem is here:

  doc[i] ["powers"] >> power;

doc[i]["powers"] does not have an index "name":

- name: Ogre   
  position: [0, 5, 0]   
  powers:
    - name: Club  
      damage: 10
    - name: Fist  
      damage: 8

The "-" denotes items. So similarly to doc[i], you would need to index firstly:

Power power;
doc[i]["powers"][0] >> power;
std::cout << power.name //outputs "Club"

But I assume you want all powers for each item, so you would need another explicit for-loop:

for (unsigned i = 0; i < doc.size(); i++)
{
    for (unsigned j = 0; j < doc[i]["powers"].size(); ++j)
    {
        Power power;
        doc[i]["powers"][j] >> power;
        std::cout << power.name << "\n";
        std::cout << power.damage << "\n";
    }
}

But that's a bit overkill. Better use your Monster-class directly, since the power values are already stored there:

for(unsigned i=0;i<doc.size();i++) {
    Monster monster;
    doc[i] >> monster;

    for (auto& power : monster.powers) // range-for loop
    {
        std::cout << power.name << "\n";
        std::cout << power.damage << "\n";
    }
    std::cout << monster.name << "\n";
}

Maybe this is a good start. A continuation of the answer would depend on what you want to achieve.

JiK
  • 103
  • 4
Mikael H
  • 1,323
  • 7
  • 12
  • Yeah it works. Thank you very much. Its my first task to learn about YAML and I'm very thankful for your help. If you don't mind can you explain to me what is actually the function of YAML::Node? If my yaml file don't have any sequence, did I not need to use index for the `doc[i]`? @Mikael H – Syam_Keyek Jun 25 '20 at 02:11
  • @Syam_Keyek, I think it's easiest do read the docu: https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html. `-` starts a sequence, so if you instead at the top level had a map `some_item: 1`, you should not start by `doc[i]`, but directly by `doc["some_item"]`. – Mikael H Jun 25 '20 at 12:59
  • `YAML::Node` is just a node representing the structure that can be indexed as lists or maps. It's supposed to give have the intuitive feeling for how a yaml-file C++ structure looks like. – Mikael H Jun 25 '20 at 13:01
  • Yeah I have tried. There so much difference with `hyphens '-' ` . So I guess its the same with `|` and `>` right? Just directly use `doc["some_item"]` @Mikael H – Syam_Keyek Jun 26 '20 at 03:18
  • `-` is only for lists. `|` and `>` is for indicating line break. But I suggest you get familiar with the docu (see link above). It's good to learn how to use the documentation to find solutions to your problems (even though it can be a lot to digest in the beginning). – Mikael H Jun 26 '20 at 10:58