Mario Torres
Mario Torres

Reputation: 73

Issue Serializing Type Tags from YamlStream

I am having an issue creating a config file for a class that includes a list of objects that implement the same interface when I use the YamlStream API.

I want to preserve the local tags that I put on list items so that they can be deserialized correctly from another context. In my actual project, I have to do some pre-processing on the YamlNodes. However, when I want to serialize the YamlDocument to a file, the local type tags are lost. I see that the tags are parsed when converted to a YamlStream (some nodes have the Tag property set appropriately). However, after processing, they are serialized without the tags.

I have some examples of what I have tried in this repo: https://github.com/mariotee/YamlDotNetIssue

var stream = new YamlStream();
stream.Load(new StringReader(yaml));

//pre processing would go here

using (var wr = new StringWriter())
{
    stream.Save(wr, false);
    File.WriteAllText("path", wr.ToString());
}

expected result:

pets:  
- !Cat
  name: skippy
  likesMilk: true
- !Cat
  name: felix
  likesMilk: true
- !Dog
  name: ralf
  likesBones: true
- !Hamster
  name: Hamtaro
  likesTv: true
...

actual result:

pets:
- name: skippy
  likesMilk: true
- name: felix
  likesMilk: true
- name: ralf
  likesBones: true
- name: Hamtaro
  likesTv: true
...

Upvotes: 1

Views: 516

Answers (1)

Antoine Aubry
Antoine Aubry

Reputation: 12469

As I commented, this is a bug. However, you can work around it by providing your own implementation of IEmitter and forcing the IsImplicit property of MappingStart to false:

public static void Main()
{
    var yaml = @"
pets:  
- !Cat
  name: skippy
  likesMilk: true
- !Cat
  name: felix
  likesMilk: true
- !Dog
  name: ralf
  likesBones: true
- !Hamster
  name: Hamtaro
  likesTv: true
...
";

    var stream = new YamlStream();
    stream.Load(new StringReader(yaml));
    stream.Save(new MappingFix(new Emitter(Console.Out)), false);
}

public class MappingFix : IEmitter
{
    private readonly IEmitter next;

    public MappingFix(IEmitter next)
    {
        this.next = next;
    }

    public void Emit(ParsingEvent @event)
    {
        var mapping = @event as MappingStart;
        if (mapping != null) {
            @event = new MappingStart(mapping.Anchor, mapping.Tag, false, mapping.Style, mapping.Start, mapping.End);
        }
        next.Emit(@event);
    }
}

This produces the intended output:

pets:
- !Cat
  name: skippy
  likesMilk: true
- !Cat
  name: felix
  likesMilk: true
- !Dog
  name: ralf
  likesBones: true
- !Hamster
  name: Hamtaro
  likesTv: true
...

Note that this requires the latest release - YamlDotNet 6.1.1

Upvotes: 1

Related Questions