YAML Conversion
This recipe demonstrates how to convert between YAML and JSON using the Corvus.Text.Json.Yaml library. It covers YAML→JSON parsing, JSON→YAML conversion, schema modes, multi-document handling, anchors and aliases, block scalars, streaming conversion, and the Utf8YamlWriter.
The Pattern
YAML is a human-friendly data serialization format commonly used for configuration files, CI pipelines, Kubernetes manifests, and API specifications. The Corvus.Text.Json.Yaml converter transforms YAML content into JSON with zero-allocation on the hot path, and converts JSON back to canonical YAML via the Utf8YamlWriter, supporting all YAML 1.2 features and four schema modes.
Parsing YAML to a Document
The simplest approach parses YAML to a strongly-typed ParsedJsonDocument<JsonElement>:
string yaml = """
name: Alice
age: 30
hobbies:
- reading
- cycling
""";
using ParsedJsonDocument<JsonElement> doc = YamlDocument.Parse<JsonElement>(yaml);
JsonElement root = doc.RootElement;
Console.WriteLine($"Name: {root.GetProperty("name").GetString()}");
Console.WriteLine($"Age: {root.GetProperty("age").GetInt32()}");
Output:
Name: Alice
Age: 30
Converting to a JSON String
When you need the raw JSON text:
string json = YamlDocument.ConvertToJsonString("key: value");
// {"key":"value"}
Schema Modes
The YAML Core Schema (default) resolves plain scalars to typed JSON values:
string: hello
integer: 42
hex: 0xFF
octal: 0o77
float: 3.14
infinity: .inf
not_a_number: .nan
null_value: null
tilde_null: ~
boolean: true
The JSON Schema mode is stricter — only JSON-compatible patterns are recognized as typed values. The Failsafe Schema treats everything as strings. YAML 1.1 compatibility mode adds yes/no/on/off booleans.
Anchors and Aliases
YAML anchors define reusable content; aliases reference it:
defaults: &defaults
adapter: postgres
host: localhost
development:
database: dev_db
<<: *defaults
With YamlSchema.Yaml11, the merge key (<<) expands the anchor inline.
Block Scalars
Literal blocks (|) preserve newlines; folded blocks (>) join lines:
literal: |
Line 1
Line 2
folded: >
This is a long
paragraph.
Chomping indicators (- strip, + keep) control trailing newlines.
Multi-Document Streams
YAML files can contain multiple documents separated by ---:
---
name: first
---
name: second
Use YamlDocumentMode.MultiAsArray to parse all documents into a JSON array.
JSON to YAML Conversion
Convert JSON content to canonical YAML:
string json = """{"name":"Alice","scores":[95,87,92]}""";
string yaml = YamlDocument.ConvertToYamlString(json);
// name: Alice
// scores:
// - 95
// - 87
// - 92
From a pre-parsed document
When you already have a parsed document, the element walk avoids re-parsing:
using ParsedJsonDocument<JsonElement> doc = ParsedJsonDocument<JsonElement>.Parse(jsonBytes);
JsonElement root = doc.RootElement;
string yaml = YamlDocument.ConvertToYamlString(in root);
Streaming to an IBufferWriter
For zero-allocation output (aside from the pooled buffer):
ArrayBufferWriter<byte> buffer = new(1024);
YamlDocument.ConvertToYaml(doc.RootElement, buffer);
ReadOnlySpan<byte> yamlBytes = buffer.WrittenSpan;
Using Utf8YamlWriter directly
For fine-grained control over the YAML output:
ArrayBufferWriter<byte> output = new(256);
Utf8YamlWriter writer = new(output);
try
{
writer.WriteStartMapping();
writer.WritePropertyName("enabled"u8);
writer.WriteBooleanValue(true);
writer.WritePropertyName("count"u8);
writer.WriteNumberValue("42"u8);
writer.WriteEndMapping();
writer.Flush();
}
finally
{
writer.Dispose();
}
Event Parsing
For advanced scenarios, EnumerateEvents provides zero-allocation, callback-based event enumeration:
YamlDocument.EnumerateEvents(
"items:\n - one\n - two",
(in YamlEvent e) =>
{
Console.WriteLine($"[{e.Line}:{e.Column}] {e.Type}");
return true; // return false to stop early
});
The YamlEvent ref struct provides the event type, scalar value (UTF-8 bytes), anchor, tag, scalar style, and line/column position. Its spans point directly into the source buffer and are only valid during the callback.
Running the Example
cd docs/ExampleRecipes/027-Yaml
dotnet run
Related Patterns
- 023-JsonPatch — Apply RFC 6902 patches to JSON documents
- 024-JsonLogic — Evaluate JsonLogic rules against JSON data
- 025-Jsonata — Query and transform JSON with JSONata expressions
- 026-Jmespath — Query JSON with JMESPath expressions