Skip to content

YAML-CPP

YAML-CPP Logo
Figure 1: 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 :
project(MyProject)
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Find the library
find_package(yaml-cpp REQUIRED)  # here to ensure library exists
file(GLOB project_SOURCES
        "src/*.h"
        "src/*.hpp"
        "src/*.cpp"
        )
#Main app
add_executable(${PROJECT_NAME} "src/main.cpp" ${project_SOURCES})
target_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 :

YAML::Node root;
try
{
    root = YAML::LoadFile(filepath);
}
catch(...){/*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 :

// Do we have data as Nodes in our file ?
if(!root.IsMap())
{
    // error - exit
}
// Check our RootNode exists
if(!root["RootNode"])
{
    // error - exit
}
// 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 :

// Example to access aFloat field
if(!root["RootNode"]["ANode1"]["aSubNode"]["aFloat"])
{
    // does not exist
}
else
{
    float value = root["RootNode"]["ANode1"]["aSubNode"]["aFloat"].as<float>();
    // if wrong type is passed, throws an exception
}
  • 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 :
// Ensure node exists
if(!root["RootNode"]["ANode1"])
{
    // error
}
else
{
    // create a const ref (we are just reading, so we won't modify it)
    const YAML::Node& whereSubNodes = root["RootNode"]["ANode1"];
    // iterate through keys to find our subnodes
    try
    {
        for (YAML::const_iterator it = whereSubNodes.begin(); it != whereSubNodes.end(); ++it)
        {
            // it->first gives key, it->second gives value (can be a node too !)
            if(it->first.as<std::string>().find("aSubNode") != std::string::npos)
            {
                // we found a correct Node, read float value if field exists else gives -1.0
                float val = it->second["aFloat"] ? it->second["aFloat"].as<float>() : -1.0;
            }
        }
    } catch(...) {/*error*/}
}

Writing a YAML file

// Root of our file
YAML::Node root;
// Create a node listing some values
root["MyNode"] = YAML::Node(YAML::NodeType::Map);
// We now will write our values under root["MyNode"]
YAML::Node& wrnode = root["MyNode"];
// Write some values
wrnode["seed"] = 3.14;
wrnode["name"] = "Glados";
wrnode["isTurret"] = false;
// Populate emitter
YAML::Emitter emitter;
emitter << root;
// Write to file
std::ofstream fout("my/path/to/file.yaml");
fout << emitter.c_str();

this will create the following file :

MyNode:
    seed: 3.14
    name: Glados
    isTurret: False