Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting Complex types of C# into YAML

I am a beginner with YAML and studying how to parse YAML into C#. Here I am trying to parse C# Object modules where I have data of complex objects types such as DataTable class or Type class in C#. I know how to convert basic types using YAMLDotNet library but really don't know how to do the same with such types. Please help.

like image 771
starklord Avatar asked Dec 08 '25 14:12

starklord


1 Answers

A DataTable is a complex object with lost of properties. The easiest way would be to extract the data that is relevant to you into a simpler data structure and serialize that instead. However, you can create a custom IYamlTypeConverter if you really want to. Here is an example that will serialize the table's column names and type, as well as the values of the rows:

public class DataTableTypeConverter : IYamlTypeConverter
{
    public bool Accepts(Type type)
    {
        return typeof(DataTable).IsAssignableFrom(type);
    }

    public object ReadYaml(IParser parser, Type type)
    {
        var table = new DataTable();

        parser.Expect<MappingStart>();

        ReadColumns(parser, table);
        ReadRows(parser, table);

        parser.Expect<MappingEnd>();

        return table;
    }

    private static void ReadColumns(IParser parser, DataTable table)
    {
        var columns = parser.Expect<Scalar>();
        if (columns.Value != "columns")
        {
            throw new YamlException(columns.Start, columns.End,
                                    "Expected a scalar named 'columns'");
        }

        parser.Expect<MappingStart>();
        while (parser.Allow<MappingEnd>() == null)
        {
            var columnName = parser.Expect<Scalar>();
            var typeName = parser.Expect<Scalar>();

            table.Columns.Add(columnName.Value, Type.GetType(typeName.Value));
        }
    }

    private static void ReadRows(IParser parser, DataTable table)
    {
        var columns = parser.Expect<Scalar>();
        if (columns.Value != "rows")
        {
            throw new YamlException(columns.Start, columns.End,
                                    "Expected a scalar named 'rows'");
        }

        parser.Expect<SequenceStart>();
        while (parser.Allow<SequenceEnd>() == null)
        {
            var row = table.NewRow();

            var columnIndex = 0;
            parser.Expect<SequenceStart>();
            while (parser.Allow<SequenceEnd>() == null)
            {
                var value = parser.Expect<Scalar>();
                var columnType = table.Columns[columnIndex].DataType;
                row[columnIndex] = TypeConverter.ChangeType(value.Value, columnType);
                ++columnIndex;
            }

            table.Rows.Add(row);
        }
    }

    public void WriteYaml(IEmitter emitter, object value, Type type)
    {
        var table = (DataTable)value;
        emitter.Emit(new MappingStart());

        EmitColumns(emitter, table);
        EmitRows(emitter, table);

        emitter.Emit(new MappingEnd());
    }

    private static void EmitColumns(IEmitter emitter, DataTable table)
    {
        emitter.Emit(new Scalar("columns"));
        emitter.Emit(new MappingStart(null, null, true, MappingStyle.Block));
        foreach (DataColumn column in table.Columns)
        {
            emitter.Emit(new Scalar(column.ColumnName));
            emitter.Emit(new Scalar(column.DataType.AssemblyQualifiedName));
        }
        emitter.Emit(new MappingEnd());
    }

    private static void EmitRows(IEmitter emitter, DataTable table)
    {
        emitter.Emit(new Scalar("rows"));
        emitter.Emit(new SequenceStart(null, null, true, SequenceStyle.Block));

        foreach (DataRow row in table.Rows)
        {
            emitter.Emit(new SequenceStart(null, null, true, SequenceStyle.Flow));
            foreach (var item in row.ItemArray)
            {
                var value = TypeConverter.ChangeType<string>(item);
                emitter.Emit(new Scalar(value));
            }
            emitter.Emit(new SequenceEnd());
        }

        emitter.Emit(new SequenceEnd());
    }
}

It is used as follows:

var table = new DataTable();
table.Columns.Add("id", typeof(int));
table.Columns.Add("name", typeof(string));
table.Columns.Add("description", typeof(string));

table.Rows.Add(1, "first", "The first row");
table.Rows.Add(2, "second", "The second row");

// Serialize
var serializer = new SerializerBuilder()
    .WithTypeConverter(new DataTableTypeConverter())
    .Build();

var yaml = serializer.Serialize(table);

// Deserialize
var deserializer = new DeserializerBuilder()
    .WithTypeConverter(new DataTableTypeConverter())
    .Build();

var parsedTable = deserializer.Deserialize<DataTable>(yaml);

The serialized YAML in this example is:

columns:
  id: System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
  name: System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
  description: System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
rows:
- [1, first, The first row]
- [2, second, The second row]
like image 75
Antoine Aubry Avatar answered Dec 11 '25 04:12

Antoine Aubry