Download YamlDotNetTypeConverterPart2.zip, last updated 24/04/2017 (28.19 KB)

Download
  • md5: 77842736a3da9b0ae928274edd184779
  • sha1: b503ddbbe501df282116dbf9a83cb83de370177f
  • sha256: 67dfe4c342abf5f7ff82a0077e752dfce66ace5fee9aa7d6aca7698e19ea9f2a
using System;
using System.Collections.Specialized;
using System.IO;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;

// Using custom type converters with C# and YamlDotNet, part 1
// http://www.cyotek.com/blog/using-custom-type-converters-with-csharp-and-yamldotnet-part-1

// Using custom type converters with C# and YamlDotNet, part 2
// http://www.cyotek.com/blog/using-custom-type-converters-with-csharp-and-yamldotnet-part-2

// This work is licensed under the Creative Commons Attribution 4.0 International License.
// To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/.

namespace YamlDotNetTypeConverter.Serialization
{
  internal sealed class ContentCategoryYamlTypeConverter : IYamlTypeConverter
  {
    #region Constants

    private static readonly Type _contentCategoryNodeType = typeof(ContentCategory);

    private static readonly Type _mappingEndType = typeof(MappingEnd);

    private static readonly Type _mappingStartType = typeof(MappingStart);

    private static readonly Type _sequenceEndType = typeof(SequenceEnd);

    private static readonly Type _sequenceStartType = typeof(SequenceStart);

    #endregion

    #region Methods

    private string GetScalarValue(IParser parser)
    {
      Scalar scalar;

      scalar = parser.Current as Scalar;

      if (scalar == null)
      {
        throw new InvalidDataException("Failed to retrieve scalar value.");
      }

      return scalar.Value;
    }

    private void ReadContentCategories(IParser parser, ContentCategoryCollection categories)
    {
      if (parser.Current.GetType() != _sequenceStartType)
      {
        throw new InvalidDataException("Invalid YAML content.");
      }

      parser.MoveNext(); // skip the sequence start

      do
      {
        categories.Add(this.ReadContentCategory(parser));
      } while (parser.Current.GetType() != _sequenceEndType);
    }

    private ContentCategory ReadContentCategory(IParser parser)
    {
      ContentCategory result;

      if (parser.Current.GetType() != _mappingStartType)
      {
        throw new InvalidDataException("Invalid YAML content.");
      }

      parser.MoveNext(); // move on from the map start

      result = new ContentCategory();

      do
      {
        string value;

        value = this.GetScalarValue(parser);
        parser.MoveNext(); // skip the scalar property name

        switch (value)
        {
          case "Name":
            result.Name = this.GetScalarValue(parser);
            break;
          case "Title":
            result.Title = this.GetScalarValue(parser);
            break;
          case "Topics":
            this.ReadTopics(parser, result.Topics);
            break;
          case "Categories":
            this.ReadContentCategories(parser, result.Categories);
            break;
          default: throw new InvalidDataException("Unexpected scalar value '" + value + "'.");
        }

        parser.MoveNext();
      } while (parser.Current.GetType() != _mappingEndType);

      parser.MoveNext(); // skip the mapping end (or crash)

      return result;
    }

    private void ReadTopics(IParser parser, StringCollection topics)
    {
      if (parser.Current.GetType() != _sequenceStartType)
      {
        throw new InvalidDataException("Invalid YAML content.");
      }

      parser.MoveNext(); // skip the sequence start

      do
      {
        topics.Add(this.GetScalarValue(parser));
        parser.MoveNext();
      } while (parser.Current.GetType() != _sequenceEndType);
    }

    private void WriteChildren(IEmitter emitter, ContentCategory node)
    {
      emitter.Emit(new Scalar(null, "Categories"));
      emitter.Emit(new SequenceStart(null, null, false, SequenceStyle.Block));

      foreach (ContentCategory child in node.Categories)
      {
        this.WriteYaml(emitter, child, _contentCategoryNodeType);
      }

      emitter.Emit(new SequenceEnd());
    }

    private void WriteContentCategory(IEmitter emitter, object value)
    {
      ContentCategory node;

      node = (ContentCategory)value;

      emitter.Emit(new MappingStart(null, null, false, MappingStyle.Block));

      if (node.Name != null)
      {
        emitter.Emit(new Scalar(null, "Name"));
        emitter.Emit(new Scalar(null, node.Name));
      }

      if (node.Title != null)
      {
        emitter.Emit(new Scalar(null, "Title"));
        emitter.Emit(new Scalar(null, node.Title));
      }

      if (node.HasCategories)
      {
        this.WriteChildren(emitter, node);
      }

      if (node.HasTopics)
      {
        this.WriteTopics(emitter, node);
      }

      emitter.Emit(new MappingEnd());
    }

    private void WriteTopics(IEmitter emitter, ContentCategory node)
    {
      emitter.Emit(new Scalar(null, "Topics"));
      emitter.Emit(new SequenceStart(null, null, false, SequenceStyle.Block));

      foreach (string child in node.Topics)
      {
        emitter.Emit(new Scalar(null, child));
      }

      emitter.Emit(new SequenceEnd());
    }

    #endregion

    #region IYamlTypeConverter Interface

    public bool Accepts(Type type)
    {
      return type == _contentCategoryNodeType;
    }

    public object ReadYaml(IParser parser, Type type)
    {
      return this.ReadContentCategory(parser);
    }

    public void WriteYaml(IEmitter emitter, object value, Type type)
    {
      this.WriteContentCategory(emitter, value);
    }

    #endregion
  }
}

Donate

Donate