How to Check YAML Node Types (IsScalar, IsSequence, IsMap) in yaml-cpp
The yaml-cpp library provides three lightweight query methods—IsScalar(), IsSequence(), and IsMap()—that inspect a node's internal NodeType to determine whether it holds a single value, an ordered list, or a key-value mapping.
When parsing YAML documents with the jbeder/yaml-cpp library, you must determine the structural type of each Node before accessing its data. These type checks are implemented as simple enum comparisons in include/yaml-cpp/node/node.h, offering zero-cost verification that guards against invalid conversions.
Understanding the NodeType Enumeration
yaml-cpp represents every parsed YAML construct as a Node object that internally stores a NodeType value. This enumeration defines three distinct categories:
- Scalar – Single values such as strings, integers, floats, or booleans
- Sequence – Ordered lists (YAML arrays)
- Map – Associative collections of key-value pairs (YAML mappings)
The NodeType enum is defined within the Node class implementation in include/yaml-cpp/node/node.h. When you load a document using YAML::Load(), each node in the resulting hierarchy carries one of these type markers.
Checking Node Types with Query Methods
The Node class exposes three boolean query methods that compare the stored NodeType against the corresponding enum value. These methods are defined at lines 56-58 of include/yaml-cpp/node/node.h:
bool IsScalar() const { return Type() == NodeType::Scalar; }
bool IsSequence() const { return Type() == NodeType::Sequence; }
bool IsMap() const { return Type() == NodeType::Map; }
Each method calls the internal Type() accessor and performs a direct equality comparison. This design provides zero-cost type queries with no dynamic casting or exception handling overhead.
Usage in Conversion Utilities
The library uses these guards throughout include/yaml-cpp/node/convert.h to validate node shapes before extracting values. For example, conversion functions typically check if (!node.IsScalar()) before attempting to parse scalar data, throwing BadConversion when the type check fails.
Practical Examples for Type Checking
Detecting and Extracting Scalars
Before converting a node to a specific type, verify it contains a scalar value:
#include <yaml-cpp/yaml.h>
#include <iostream>
double getDouble(const YAML::Node& n) {
// Guard against non-scalar nodes before extraction
if (!n.IsScalar()) {
throw YAML::BadConversion(n, "expected scalar for double");
}
return n.as<double>();
}
int main() {
YAML::Node root = YAML::Load("value: 3.14");
if (root["value"].IsScalar()) {
std::cout << "Scalar: " << root["value"].as<double>() << "\n";
}
}
Iterating Over Sequence Nodes
Use IsSequence() to safely access array elements:
YAML::Node node = YAML::Load("[1, 2, 3]");
if (node.IsSequence()) {
std::cout << "Sequence size: " << node.size() << "\n";
for (std::size_t i = 0; i < node.size(); ++i) {
std::cout << " - " << node[i].as<int>() << "\n";
}
}
Traversing Map Nodes
Check for associative structures before iterating:
YAML::Node config = YAML::Load(R"(
database:
host: localhost
port: 5432
)");
if (config["database"].IsMap()) {
for (auto it = config["database"].begin(); it != config["database"].end(); ++it) {
std::cout << it->first.as<std::string>()
<< ": " << it->second.as<std::string>() << "\n";
}
}
Testing and Validation
The test suite in test/node/node_test.cpp exercises these type queries across various YAML constructs. For instance, the suite verifies that a loaded sequence correctly identifies as such:
YAML::Node node = YAML::Load("[1, 2, 3]");
EXPECT_TRUE(node.IsSequence()); // Validates sequence detection
These tests ensure that IsScalar(), IsSequence(), and IsMap() behave consistently regardless of how the YAML document was constructed or loaded.
Summary
- Type Safety: Use
IsScalar(),IsSequence(), andIsMap()frominclude/yaml-cpp/node/node.hto verify node structure before access - Zero Overhead: These methods perform simple enum comparisons with no dynamic casting
- Defensive Programming: Conversion utilities in
include/yaml-cpp/node/convert.hrely on these checks to throwBadConversionon type mismatches - Comprehensive Coverage: The
NodeTypeenum covers all three fundamental YAML constructs, enabling complete document traversal
Frequently Asked Questions
What happens if I call as<T>() without checking the node type first?
The conversion will attempt to proceed, but if the node's NodeType does not match the requested conversion (for example, calling as<std::string>() on a Sequence), the library throws YAML::BadConversion. While the library does not require explicit type checks, using IsScalar(), IsSequence(), or IsMap() before conversion prevents exceptions and makes intent explicit.
Can a node be more than one type simultaneously?
No. According to the implementation in include/yaml-cpp/node/node.h, each Node maintains exactly one NodeType value. A node cannot be both a Scalar and a Map, or both a Sequence and a Scalar. The type is determined during parsing and remains fixed for the lifetime of the node object.
Are these type-checking methods thread-safe?
Yes. The IsScalar(), IsSequence(), and IsMap() methods are const member functions that only read the node's internal type identifier. Since they do not modify state and the NodeType is immutable after construction, these checks are safe to call from multiple threads on the same node instance.
How do I check if a node exists before checking its type?
Use the operator[] or operator() accessors first, as they return a valid Node object even for missing keys. Check if the node is defined (non-null) using if (node) or if (!node.IsNull()) before calling IsScalar(), IsSequence(), or IsMap(). Undefined nodes may report unexpected type behavior, so always verify existence before inspecting the type.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →