YAML-CPP#

YAML-CPP Logo

Introduction#

YAML (YAML Ain’t Markup Language) is a human-readable data-serialization language, like JSON.
YAML-CPP is a corresponding library for C++ able to create and read .yaml files.
YAML is based on key:values pair. Those can be scalars (integers, float, string, bool), lists, associative arrays (maps, dictionaries) also seen as NODES, which are simply lists of multiple key:values.
YAML also allows to create aliases and references. See Wikipedia
A very simple base file can be such as :
RootNode:
  ANode1:
    aString: My Name
    aSubNode:
      aFloat: 3.14
    aSubNode2:
      aFloat: 1.57
    aBool: true
  ANode2:
    aInt : 34

How to use#

The library can be found here.

Prepare library#

  1. First, it must be built thanks to CMake for your particular builder.
    • A build for MSVC 2019 can be found on GitLab.

  2. Once built/copied to a chosen path, the folder YAML_CPP\share\cmake\yaml-cpp must be added to PATH.

Use it inside your project#

CMake integration is not standard.
Normally, you would add YAML_CPP_INCLUDE_DIR to the include_directories() directive, and YAML_CPP_LIBRARIES under target_link_libraries().
But both these variables are empty. To use it, do as follow :
 1project(MyProject)
 2set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin)
 3set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
 4set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
 5# Find includes in corresponding build directories
 6set(CMAKE_INCLUDE_CURRENT_DIR ON)
 7# Find the library
 8find_package(yaml-cpp REQUIRED)  # here to ensure library exists
 9file(GLOB project_SOURCES
10        "src/*.h"
11        "src/*.hpp"
12        "src/*.cpp"
13        )
14#Main app
15add_executable(${PROJECT_NAME} "src/main.cpp" ${project_SOURCES})
16target_link_libraries(${PROJECT_NAME} yaml-cpp) # here to include it

Warning

The library uses exceptions throwing whenever something goes wrong. Please ensure to embrace your code with throw{} catch(...){} directives.

Documentation for the library can be found on Github.

Reading a YAML file#

Once you get the file path, you can read it with :

1YAML::Node root;
2try
3{
4    root = YAML::LoadFile(filepath);
5}
6catch(...){/*error - could not load*/}

Afterward, it is up to you to know how your file is structured. In the example given before, the first step is to ensure our root node RootNode exists and that it contains data :

 1// Do we have data as Nodes in our file ?
 2if(!root.IsMap())
 3{
 4    // error - exit
 5}
 6// Check our RootNode exists
 7if(!root["RootNode"])
 8{
 9    // error - exit
10}
11// OK, we can iterate over data

If you know exactly how you data should be, you must first ensure you key exists, then read the value while specifying its format :

 1// Example to access aFloat field
 2if(!root["RootNode"]["ANode1"]["aSubNode"]["aFloat"])
 3{
 4    // does not exist
 5}
 6else
 7{
 8    float value = root["RootNode"]["ANode1"]["aSubNode"]["aFloat"].as<float>();
 9    // if wrong type is passed, throws an exception
10}
Nodes are accessed through their keys. If we have a length-undefined list, we can iterate through field of our node.
Let’s say I’d like to check all my aSubNodeX node :
 1// Ensure node exists
 2if(!root["RootNode"]["ANode1"])
 3{
 4    // error
 5}
 6else
 7{
 8    // create a const ref (we are just reading, so we won't modify it)
 9    const YAML::Node& whereSubNodes = root["RootNode"]["ANode1"];
10    // iterate through keys to find our subnodes
11    try
12    {
13        for (YAML::const_iterator it = whereSubNodes.begin(); it != whereSubNodes.end(); ++it)
14        {
15            // it->first gives key, it->second gives value (can be a node too !)
16            if(it->first.as<std::string>().find("aSubNode") != std::string::npos)
17            {
18                // we found a correct Node, read float value if field exists else gives -1.0
19                float val = it->second["aFloat"] ? it->second["aFloat"].as<float>() : -1.0;
20            }
21        }
22    } catch(...) {/*error*/}
23}

Writing a YAML file#

A YAML::Emitter can be used to create a file. It can be written thanks to a special formatting.
Otherwise, you can populate Nodes and use the emitter afterward. Let’s try creating a simple file :
 1// Root of our file
 2YAML::Node root;
 3// Create a node listing some values
 4root["MyNode"] = YAML::Node(YAML::NodeType::Map);
 5// We now will write our values under root["MyNode"]
 6YAML::Node& wrnode = root["MyNode"];
 7// Write some values
 8wrnode["seed"] = 3.14;
 9wrnode["name"] = "Glados";
10wrnode["isTurret"] = false;
11// Populate emitter
12YAML::Emitter emitter;
13emitter << root;
14// Write to file
15std::ofstream fout("my/path/to/file.yaml");
16fout << emitter.c_str();

this will create the following file :

MyNode:
    seed: 3.14
    name: Glados
    isTurret: False

C++ Library