Serilizing an object with tags similar to AWS Cloudformation
gitisz opened this issue · comments
I'm trying to use the C# YamlDotNet to return a serialized output of an object expressed as YAML, where much of the YAML will have tags similiar to those avaialble in AWS Cloudformation templates, such as !FindInMap
as documented (here)[https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-findinmap.html].
Here is one example where !FindInMap
may be expressed:
value:
- -Djob.enebled=true
- !FindInMap [ "FOO", "BAR", "BAZ" ]
Or something slightly more complex, like a nested tag:
value:
- -Djob.enebled=true
- !FindInMap [ "FOO", "BAR", !Ref Baz ]
Using YamlDotNet, I see how to leverage SerializeBuilder,
but WithTagMapping
eludes me. In the examples above, how might a class/type look to achieve serialize to achieve the same?
Thanks
With the current implementation of mapping this is probably going to get you as close as you can get. With a little more work you could probably get the first element in your value object list to output without a single quote another type converter. Maybe something like an argument object or something. But, here you go to get you started.
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
var serializer = new SerializerBuilder()
.WithTagMapping("!FindInMap", typeof(List<object>))
.WithTagMapping("!Ref", typeof(Baz))
.WithDefaultScalarStyle(ScalarStyle.DoubleQuoted)
.WithTypeConverter(new BazTypeConverter())
.Build();
var list = new List<object>();
list.AddRange(new[] { "FOO", "BAR" });
list.Add(new Baz());
var outer = new Outer
{
Value =
[
"-Djob.enebled=true",
list
]
};
var yaml = serializer.Serialize(outer);
Console.WriteLine(yaml);
var deserializer = new DeserializerBuilder()
.WithTagMapping("!FindInMap", typeof(List<object>))
.WithTagMapping("!Ref", typeof(Baz))
.WithTypeConverter(new BazTypeConverter())
.Build();
Console.WriteLine("=== Deserialized");
var result = deserializer.Deserialize<Outer>(yaml);
foreach (var o in result.Value)
{
if (o is List<object> list1)
{
foreach (var o2 in list1)
{
Console.WriteLine($" {o2}");
}
}
else
{
Console.WriteLine(o);
}
}
class Outer
{
public object[] Value { get; set; }
}
class BazTypeConverter : IYamlTypeConverter
{
public bool Accepts(Type type) => type == typeof(Baz);
public object? ReadYaml(IParser parser, Type type)
{
var valid = parser.TryConsume<Scalar>(out var value);
if (!valid || value == null)
{
throw new Exception($"Invalid type, expected scalar got {value?.GetType()}");
}
if (value.Value != "Baz")
{
throw new Exception("Invalid Scalar Value");
}
return new Baz();
}
public void WriteYaml(IEmitter emitter, object? value, Type type)
{
emitter.Emit(new Scalar(null, "!Ref", "Baz", ScalarStyle.Plain, false, false));
}
}
class Baz
{
public override string ToString()
{
return "I'm a Baz";
}
}
Results in
Value:
- "-Djob.enebled=true"
- !FindInMap
- "FOO"
- "BAR"
- !Ref Baz
=== Deserialized
-Djob.enebled=true
FOO
BAR
I'm a Baz
Did the above answer your question?
Haven't heard back in a couple of months, I'm going to close the issue.
Thank you for the generous example! I did shelve this and used a client-side NodeJS alternative, but that was temporary. I'll give this a go and share back. Thank you!