yaml-cpp

FORK: A YAML parser and emitter in C++
git clone https://git.neptards.moe/neptards/yaml-cpp.git
Log | Files | Refs | README | LICENSE

How-To-Parse-A-Document-(Old-API).md (7076B)


      1 _The following describes the old API. For the new API, see the [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial)._
      2 
      3 ## Contents ##
      4 
      5 
      6 # Basic Parsing #
      7 
      8 The parser accepts streams, not file names, so you need to first load the file. Since a YAML file can contain many documents, you can grab them one-by-one. A simple way to parse a YAML file might be:
      9 
     10 ```
     11 #include <fstream>
     12 #include "yaml-cpp/yaml.h"
     13 
     14 int main()
     15 {
     16     std::ifstream fin("test.yaml");
     17     YAML::Parser parser(fin);
     18 
     19     YAML::Node doc;
     20     while(parser.GetNextDocument(doc)) {
     21        // ...
     22     }
     23 
     24     return 0;
     25 }
     26 ```
     27 
     28 # Reading From the Document #
     29 
     30 Suppose we have a document consisting only of a scalar. We can read that scalar like this:
     31 
     32 ```
     33 YAML::Node doc;    // let's say we've already parsed this document
     34 std::string scalar;
     35 doc >> scalar;
     36 std::cout << "That scalar was: " << scalar << std::endl;
     37 ```
     38 
     39 How about sequences? Let's say our document now consists only of a sequences of scalars. We can use an iterator:
     40 
     41 ```
     42 YAML::Node doc;    // already parsed
     43 for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
     44     std::string scalar;
     45     *it >> scalar;
     46     std::cout << "Found scalar: " << scalar << std::endl;
     47 }
     48 ```
     49 
     50 ... or we can just loop through:
     51 
     52 ```
     53 YAML::Node doc;    // already parsed
     54 for(unsigned i=0;i<doc.size();i++) {
     55     std::string scalar;
     56     doc[i] >> scalar;
     57     std::cout << "Found scalar: " << scalar << std::endl;
     58 }
     59 ```
     60 
     61 And finally maps. For now, let's say our document is a map with all keys/values being scalars. Again, we can iterate:
     62 
     63 ```
     64 YAML::Node doc;    // already parsed
     65 for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
     66     std::string key, value;
     67     it.first() >> key;
     68     it.second() >> value;
     69     std::cout << "Key: " << key << ", value: " << value << std::endl;
     70 }
     71 ```
     72 
     73 Note that dereferencing a map iterator is undefined; instead, use the `first` and `second` methods to get the key and value nodes, respectively.
     74 
     75 Alternatively, we can pick off the values one-by-one, if we know the keys:
     76 
     77 ```
     78 YAML::Node doc;    // already parsed
     79 std::string name;
     80 doc["name"] >> name;
     81 int age;
     82 doc["age"] >> age;
     83 std::cout << "Found entry with name '" << name << "' and age '" << age << "'\n";
     84 ```
     85 
     86 One thing to be keep in mind: reading a map by key (as immediately above) requires looping through all entries until we find the right key, which is an O(n) operation. So if you're reading the entire map this way, it'll be O(n^2). For small n, this isn't a big deal, but I wouldn't recommend reading maps with a very large number of entries (>100, say) this way.
     87 
     88 ## Optional Keys ##
     89 
     90 If you try to access a key that doesn't exist, `yaml-cpp` throws an exception (see [When Something Goes Wrong](https://github.com/jbeder/yaml-cpp/wiki/How-To-Parse-A-Document-(Old-API)#When_Something_Goes_Wrong). If you have optional keys, it's often easier to use `FindValue` instead of `operator[]`:
     91 
     92 ```
     93 YAML::Node doc;    // already parsed
     94 if(const YAML::Node *pName = doc.FindValue("name")) {
     95     std::string name;
     96     *pName >> name;
     97     std::cout << "Key 'name' exists, with value '" << name << "'\n";
     98 } else {
     99     std::cout << "Key 'name' doesn't exist\n";
    100 }
    101 ```
    102 
    103 # Getting More Complicated #
    104 
    105 The above three methods can be combined to read from an arbitrary document. But we can make life a lot easier. Suppose we're reading 3-vectors (i.e., vectors with three components), so we've got a structure looking like this:
    106 
    107 ```
    108 struct Vec3 {
    109     float x, y, z;
    110 };
    111 ```
    112 
    113 We can read this in one operation by overloading the extraction (>>) operator:
    114 
    115 ```
    116 void operator >> (const YAML::Node& node, Vec3& v)
    117 {
    118     node[0] >> v.x;
    119     node[1] >> v.y;
    120     node[2] >> v.z;
    121 }
    122 
    123 // now it's a piece of cake to read it
    124 YAML::Node doc;    // already parsed
    125 Vec3 v;
    126 doc >> v;
    127 std::cout << "Here's the vector: (" << v.x << ", " << v.y << ", " << v.z << ")\n";
    128 ```
    129 
    130 # A Complete Example #
    131 
    132 Here's a complete example of how to parse a complex YAML file:
    133 
    134 `monsters.yaml`
    135 
    136 ```
    137 - name: Ogre
    138   position: [0, 5, 0]
    139   powers:
    140     - name: Club
    141       damage: 10
    142     - name: Fist
    143       damage: 8
    144 - name: Dragon
    145   position: [1, 0, 10]
    146   powers:
    147     - name: Fire Breath
    148       damage: 25
    149     - name: Claws
    150       damage: 15
    151 - name: Wizard
    152   position: [5, -3, 0]
    153   powers:
    154     - name: Acid Rain
    155       damage: 50
    156     - name: Staff
    157       damage: 3
    158 ```
    159 
    160 `main.cpp`
    161 
    162 ```
    163 #include "yaml-cpp/yaml.h"
    164 #include <iostream>
    165 #include <fstream>
    166 #include <string>
    167 #include <vector>
    168 
    169 // our data types
    170 struct Vec3 {
    171    float x, y, z;
    172 };
    173 
    174 struct Power {
    175    std::string name;
    176    int damage;
    177 };
    178 
    179 struct Monster {
    180    std::string name;
    181    Vec3 position;
    182    std::vector <Power> powers;
    183 };
    184 
    185 // now the extraction operators for these types
    186 void operator >> (const YAML::Node& node, Vec3& v) {
    187    node[0] >> v.x;
    188    node[1] >> v.y;
    189    node[2] >> v.z;
    190 }
    191 
    192 void operator >> (const YAML::Node& node, Power& power) {
    193    node["name"] >> power.name;
    194    node["damage"] >> power.damage;
    195 }
    196 
    197 void operator >> (const YAML::Node& node, Monster& monster) {
    198    node["name"] >> monster.name;
    199    node["position"] >> monster.position;
    200    const YAML::Node& powers = node["powers"];
    201    for(unsigned i=0;i<powers.size();i++) {
    202       Power power;
    203       powers[i] >> power;
    204       monster.powers.push_back(power);
    205    }
    206 }
    207 
    208 int main()
    209 {
    210    std::ifstream fin("monsters.yaml");
    211    YAML::Parser parser(fin);
    212    YAML::Node doc;
    213    parser.GetNextDocument(doc);
    214    for(unsigned i=0;i<doc.size();i++) {
    215       Monster monster;
    216       doc[i] >> monster;
    217       std::cout << monster.name << "\n";
    218    }
    219 
    220    return 0;
    221 }
    222 ```
    223 
    224 # When Something Goes Wrong #
    225 
    226 ... we throw an exception (all exceptions are derived from `YAML::Exception`). If there's a parsing exception (i.e., a malformed YAML document), we throw a `YAML::ParserException`:
    227 
    228 ```
    229 try {
    230     std::ifstream fin("test.yaml");
    231     YAML::Parser parser(fin);
    232     YAML::Node doc;
    233     parser.GetNextDocument(doc);
    234     // do stuff
    235 } catch(YAML::ParserException& e) {
    236     std::cout << e.what() << "\n";
    237 }
    238 ```
    239 
    240 If you make a programming error (say, trying to read a scalar from a sequence node, or grabbing a key that doesn't exist), we throw some kind of `YAML::RepresentationException`. To prevent this, you can check what kind of node something is:
    241 
    242 ```
    243     YAML::Node node;
    244     YAML::NodeType::value type = node.Type();  // should be:
    245                                                // YAML::NodeType::Null
    246                                                // YAML::NodeType::Scalar
    247                                                // YAML::NodeType::Sequence
    248                                                // YAML::NodeType::Map
    249 ```
    250 
    251 # Note about copying `YAML::Node` #
    252 
    253 Currently `YAML::Node` is non-copyable, so you need to do something like
    254 
    255 ```
    256     const YAML::Node& node = doc["whatever"];
    257 ```
    258 
    259 This is intended behavior. If you want to copy a node, use the `Clone` function:
    260 
    261 ```
    262     std::auto_ptr<YAML::Node> pCopy = myOtherNode.Clone();
    263 ```
    264 
    265 The intent is that if you'd like to keep a `YAML::Node` around for longer than the document will stay in scope, you can clone it and store it as long as you like.