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

Tutorial.md (5493B)


      1 # Introduction #
      2 
      3 A typical example, loading a configuration file, might look like this:
      4 
      5 ```cpp
      6 YAML::Node config = YAML::LoadFile("config.yaml");
      7 
      8 if (config["lastLogin"]) {
      9   std::cout << "Last logged in: " << config["lastLogin"].as<DateTime>() << "\n";
     10 }
     11 
     12 const std::string username = config["username"].as<std::string>();
     13 const std::string password = config["password"].as<std::string>();
     14 login(username, password);
     15 config["lastLogin"] = getCurrentDateTime();
     16 
     17 std::ofstream fout("config.yaml");
     18 fout << config;
     19 ```
     20 
     21 # Basic Parsing and Node Editing #
     22 
     23 All nodes in a YAML document (including the root) are represented by `YAML::Node`. You can check what kind it is:
     24 
     25 ```cpp
     26 YAML::Node node = YAML::Load("[1, 2, 3]");
     27 assert(node.Type() == YAML::NodeType::Sequence);
     28 assert(node.IsSequence());  // a shortcut!
     29 ```
     30 
     31 Collection nodes (sequences and maps) act somewhat like STL vectors and maps:
     32 
     33 ```cpp
     34 YAML::Node primes = YAML::Load("[2, 3, 5, 7, 11]");
     35 for (std::size_t i=0;i<primes.size();i++) {
     36   std::cout << primes[i].as<int>() << "\n";
     37 }
     38 // or:
     39 for (YAML::const_iterator it=primes.begin();it!=primes.end();++it) {
     40   std::cout << it->as<int>() << "\n";
     41 }
     42 
     43 primes.push_back(13);
     44 assert(primes.size() == 6);
     45 ```
     46 
     47 and
     48 
     49 ```cpp
     50 YAML::Node lineup = YAML::Load("{1B: Prince Fielder, 2B: Rickie Weeks, LF: Ryan Braun}");
     51 for(YAML::const_iterator it=lineup.begin();it!=lineup.end();++it) {
     52   std::cout << "Playing at " << it->first.as<std::string>() << " is " << it->second.as<std::string>() << "\n";
     53 }
     54 
     55 lineup["RF"] = "Corey Hart";
     56 lineup["C"] = "Jonathan Lucroy";
     57 assert(lineup.size() == 5);
     58 ```
     59 
     60 Querying for keys does **not** create them automatically (this makes handling optional map entries very easy)
     61 
     62 ```cpp
     63 YAML::Node node = YAML::Load("{name: Brewers, city: Milwaukee}");
     64 if (node["name"]) {
     65   std::cout << node["name"].as<std::string>() << "\n";
     66 }
     67 if (node["mascot"]) {
     68   std::cout << node["mascot"].as<std::string>() << "\n";
     69 }
     70 assert(node.size() == 2); // the previous call didn't create a node
     71 ```
     72 
     73 If you're not sure what kind of data you're getting, you can query the type of a node:
     74 
     75 ```cpp
     76 switch (node.Type()) {
     77   case Null: // ...
     78   case Scalar: // ...
     79   case Sequence: // ...
     80   case Map: // ...
     81   case Undefined: // ...
     82 }
     83 ```
     84 
     85 or ask directly whether it's a particular type, e.g.:
     86 
     87 ```cpp
     88 if (node.IsSequence()) {
     89   // ...
     90 }
     91 ```
     92 
     93 # Building Nodes #
     94 
     95 You can build `YAML::Node` from scratch:
     96 
     97 ```cpp
     98 YAML::Node node;  // starts out as null
     99 node["key"] = "value";  // it now is a map node
    100 node["seq"].push_back("first element");  // node["seq"] automatically becomes a sequence
    101 node["seq"].push_back("second element");
    102 
    103 node["mirror"] = node["seq"][0];  // this creates an alias
    104 node["seq"][0] = "1st element";  // this also changes node["mirror"]
    105 node["mirror"] = "element #1";  // and this changes node["seq"][0] - they're really the "same" node
    106 
    107 node["self"] = node;  // you can even create self-aliases
    108 node[node["mirror"]] = node["seq"];  // and strange loops :)
    109 ```
    110 
    111 The above node is now:
    112 
    113 ```yaml
    114 &1
    115 key: value
    116 &2 seq: [&3 "element #1", second element]
    117 mirror: *3
    118 self: *1
    119 *3 : *2
    120 ```
    121 
    122 # How Sequences Turn Into Maps #
    123 
    124 Sequences can be turned into maps by asking for non-integer keys. For example,
    125 
    126 ```cpp
    127 YAML::Node node  = YAML::Load("[1, 2, 3]");
    128 node[1] = 5;  // still a sequence, [1, 5, 3]
    129 node.push_back(-3) // still a sequence, [1, 5, 3, -3]
    130 node["key"] = "value"; // now it's a map! {0: 1, 1: 5, 2: 3, 3: -3, key: value}
    131 ```
    132 
    133 Indexing a sequence node by an index that's not in its range will _usually_ turn it into a map, but if the index is one past the end of the sequence, then the sequence will grow by one to accommodate it. (That's the **only** exception to this rule.) For example,
    134 
    135 ```cpp
    136 YAML::Node node = YAML::Load("[1, 2, 3]");
    137 node[3] = 4; // still a sequence, [1, 2, 3, 4]
    138 node[10] = 10;  // now it's a map! {0: 1, 1: 2, 2: 3, 3: 4, 10: 10}
    139 ```
    140 
    141 # Converting To/From Native Data Types #
    142 
    143 Yaml-cpp has built-in conversion to and from most built-in data types, as well as `std::vector`, `std::list`, and `std::map`. The following examples demonstrate when those conversions are used:
    144 
    145 ```cpp
    146 YAML::Node node = YAML::Load("{pi: 3.14159, [0, 1]: integers}");
    147 
    148 // this needs the conversion from Node to double
    149 double pi = node["pi"].as<double>();
    150 
    151 // this needs the conversion from double to Node
    152 node["e"] = 2.71828;
    153 
    154 // this needs the conversion from Node to std::vector<int> (*not* the other way around!)
    155 std::vector<int> v;
    156 v.push_back(0);
    157 v.push_back(1);
    158 std::string str = node[v].as<std::string>();
    159 ```
    160 
    161 To use yaml-cpp with your own data types, you need to specialize the YAML::convert<> template class. For example, suppose you had a simple `Vec3` class:
    162 
    163 ```cpp
    164 struct Vec3 { double x, y, z; /* etc - make sure you have overloaded operator== */ };
    165 ```
    166 
    167 You could write
    168 
    169 ```cpp
    170 namespace YAML {
    171 template<>
    172 struct convert<Vec3> {
    173   static Node encode(const Vec3& rhs) {
    174     Node node;
    175     node.push_back(rhs.x);
    176     node.push_back(rhs.y);
    177     node.push_back(rhs.z);
    178     return node;
    179   }
    180 
    181   static bool decode(const Node& node, Vec3& rhs) {
    182     if(!node.IsSequence() || node.size() != 3) {
    183       return false;
    184     }
    185 
    186     rhs.x = node[0].as<double>();
    187     rhs.y = node[1].as<double>();
    188     rhs.z = node[2].as<double>();
    189     return true;
    190   }
    191 };
    192 }
    193 ```
    194 
    195 Then you could use `Vec3` wherever you could use any other type:
    196 
    197 ```cpp
    198 YAML::Node node = YAML::Load("start: [1, 3, 0]");
    199 Vec3 v = node["start"].as<Vec3>();
    200 node["end"] = Vec3(2, -1, 0);
    201 ```