Search code examples
yamlyamldotnet

Change the scalar style used for all multi-line strings when serialising a dynamic model using YamlDotNet


I am using the following code snippet to serialise a dynamic model of a project to a string (which is eventually exported to a YAML file).

    dynamic exportModel = exportModelConvertor.ToDynamicModel(project);
    var serializerBuilder = new SerializerBuilder();
    var serializer = serializerBuilder.EmitDefaults().DisableAliases().Build();

    using (var sw = new StringWriter())
    {
        serializer.Serialize(sw, exportModel);
        string result = sw.ToString();
    }

Any multi-line strings such as the following:

propertyName = "One line of text
followed by another line
and another line"

are exported in the following format:

propertyName: >
  One line of text

  followed by another line

  and another line

Note the extra (unwanted) line breaks.

According to this YAML Multiline guide, the format used here is the folded block scalar style. Is there a way using YamlDotNet to change the style of this output for all multi-line string properties to literal block scalar style or one of the flow scalar styles?

The YamlDotNet documentation shows how to apply ScalarStyle.DoubleQuoted to a particular property using WithAttributeOverride but this requires a class name and the model to be serialised is dynamic. This also requires listing every property to change (of which there are many). I would like to change the style for all multi-line string properties at once.


Solution

  • To answer my own question, I've now worked out how to do this by deriving from the ChainedEventEmitter class and overriding void Emit(ScalarEventInfo eventInfo, IEmitter emitter). See code sample below.

    public class MultilineScalarFlowStyleEmitter : ChainedEventEmitter
    {
        public MultilineScalarFlowStyleEmitter(IEventEmitter nextEmitter)
            : base(nextEmitter) { }
    
        public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter)
        {
    
            if (typeof(string).IsAssignableFrom(eventInfo.Source.Type))
            {
                string value = eventInfo.Source.Value as string;
                if (!string.IsNullOrEmpty(value))
                {
                    bool isMultiLine = value.IndexOfAny(new char[] { '\r', '\n', '\x85', '\x2028', '\x2029' }) >= 0;
                    if (isMultiLine)
                        eventInfo = new ScalarEventInfo(eventInfo.Source)
                        {
                            Style = ScalarStyle.Literal
                        };
                }
            }
    
            nextEmitter.Emit(eventInfo, emitter);
        }
    }