YamlDotNet
YamlDotNet copied to clipboard
How to serialize the !include Directive in YamlDotNet
Description:
I have a YAML configuration that includes external files using the !include directive, like this:
views:
- !include views/home.yaml
- title: Světnice
path: dashboard
badges: ...
I'm using YamlDotNet for YAML serialization in my C# project, and I'm wondering how to properly serialize this YAML structure while ensuring that the !include directive is correctly processed to include external files.
I'm tried
views = new[]
{
new YamlScalarNode("!include views/home.yaml"),
new
{
title = dashboard.Title,
path = dashboard.UrlSlug,
badges = dashboard.GetBadges().Select(badge => badge.ToYml()),
cards = dashboard.GetCards().Select(card => card.ToYml())
}.ToYml(),
}
also
views = new object[]
{
"!include views/home.yaml",
new
{
title = dashboard.Title,
path = dashboard.UrlSlug,
badges = dashboard.GetBadges().Select(badge => badge.ToYml()),
cards = dashboard.GetCards().Select(card => card.ToYml())
},
}
The result is both cases the same:
views:
- '!include views/home.yaml' #this should not be a string
- title: Světla
path: lovelace-lights
badges: ...
Is there something like RawYamlNode
?
On the YamlScalarNode try setting the scalar type to plain. That should do it.
@EdwardCooke thanks for the answer. The NodeType property is get only.
https://github.com/aaubry/YamlDotNet/blob/847230593e95750d4294ca72c98a4bd46bdcf265/YamlDotNet/RepresentationModel/YamlScalarNode.cs#L219
The property is actually style. Sorry about that.
https://github.com/aaubry/YamlDotNet/blob/847230593e95750d4294ca72c98a4bd46bdcf265/YamlDotNet/RepresentationModel/YamlScalarNode.cs#L68
@EdwardCooke the result is same.
new YamlScalarNode("!include views/home.yaml")
{
Style = ScalarStyle.Plain
}
- '!include views/home.yaml'
I hope this is only temporary solution :)
var yamlNode = YamlHelper.Include("views/home.yaml");
var serializer = new SerializerBuilder().Build();
var yaml = serializer.Serialize(yamlNode);
System.Console.WriteLine(yaml);
public static class YamlHelper
{
public static YamlNode Include(string fileName)
{
return ToYaml($"!include {fileName}");
}
public static YamlNode ToYaml(string yaml)
{
var yamlStream = new YamlStream();
yamlStream.Load(new StringReader(yaml));
return yamlStream.Documents[0].RootNode;
}
}
!include views/home.yaml
What if you set the tag property to !include or include? Then set the value to your file.
Just got to spend more time on this. This is much cleaner, using a yaml type convert and an include object.
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
var serializer = new SerializerBuilder()
.WithTagMapping("!include", typeof(IncludedObject))
.WithTypeConverter(new TestTypeConverter())
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.Build();
var o = new object[] {
new IncludedObject{ Filename = "test.yaml" },
new Book
{
Title = "a title",
Path = "a path",
Badges = "some badges"
}
};
var serialized = serializer.Serialize(o);
Console.WriteLine(serialized);
class Outer
{
public object[] Items { get; set; }
}
class Book
{
public string Title { get; set; }
public string Path { get; set; }
public string Badges { get; set; }
}
// This is the magic that makes it easily re-usable
class TestTypeConverter : IYamlTypeConverter
{
public bool Accepts(Type type) => type == typeof(IncludedObject);
public object? ReadYaml(IParser parser, Type type)
{
throw new NotImplementedException();
}
public void WriteYaml(IEmitter emitter, object? value, Type type)
{
if (type != typeof(IncludedObject))
{
return;
}
if (value is IncludedObject o)
{
emitter.Emit(new Scalar(null, "!include", o.Filename, ScalarStyle.Plain, false, false));
}
}
}
class IncludedObject
{
public string Filename { get; set; } = string.Empty;
}
Results in
- !include test.yaml
- title: a title
path: a path
badges: some badges
If you want to see how to read in an include directive, checkout my answer here.
https://github.com/aaubry/YamlDotNet/issues/909
@EdwardCooke thanks!