Deserializar una “tabla” YAML de datos

Estoy usando yamldotnet y c # para deserializar un archivo creado por una aplicación de software de terceros. Los siguientes ejemplos de archivos YAML son válidos desde la aplicación:

#File1 Groups: - Name: ATeam FirstName, LastName, Age, Height: - [Joe, Soap, 21, 184] - [Mary, Ryan, 20, 169] - [Alex, Dole, 24, 174] #File2 Groups: - Name: ATeam FirstName, LastName, Height: - [Joe, Soap, 184] - [Mary, Ryan, 169] - [Alex, Dole, 174] 

Observe que el Archivo 2 no tiene ninguna columna de Edad, pero el deserializador aún debe reconocer que el tercer valor en cada línea es una altura en lugar de una edad. Se supone que estos datos representan una tabla de personas. En el caso de File1, por ejemplo, Mary Ryan tiene 20 años y 169 cm de altura. El deserializador debe comprender las columnas que tiene (para File2 solo tiene FirstName, LastName y Height) y almacenar los datos en los objetos correctos: Mary Ryan mide 169 cm de altura.

De manera similar, la documentación del progtwig indica que el orden de las columnas no es importante, por lo que el Archivo3 a continuación es una forma igualmente válida de representar los datos en el Archivo2, aunque la Altura ahora sea la primera:

 #File3 Groups: - Name: ATeam Height, FirstName, LastName: - [184, Joe, Soap] - [169, Mary, Ryan] - [174, Alex, Dole] 

Tengo un número de preguntas:

  1. ¿Es este YAML estándar? – No pude encontrar nada sobre el uso de varias teclas en la misma línea, seguidas de dos puntos y listas de valores para representar tablas de datos.
  2. ¿Cómo usaría yamldotnet para deserializar esto? ¿Hay modificaciones que pueda hacer para ayudarlo?
  3. Si no puedo usar yamldotnet, ¿cómo debo hacerlo?

Como otras respuestas indicaron, esto es válido YAML. Sin embargo, la estructura del documento es específica de la aplicación y no utiliza ninguna característica especial de YAML para express tablas.

Puede analizar fácilmente este documento utilizando YamlDotNet. Sin embargo, se encontrará con dos dificultades. La primera es que, dado que los nombres de las columnas se colocan dentro de la clave, necesitará usar algún código de serialización personalizado para manejarlos. La segunda es que necesitará implementar algún tipo de abstracción para poder acceder a los datos de forma tabular.

He presentado una prueba de concepto que ilustrará cómo analizar y leer los datos.

Primero, cree un tipo para contener la información del documento YAML:

 public class Document { public List Groups { get; set; } } public class Group { public string Name { get; set; } public IEnumerable ColumnNames { get; set; } public IList> Rows { get; set; } } 

Luego, implemente IYamlTypeConverter para analizar el tipo de Group :

 public class GroupYamlConverter : IYamlTypeConverter { private readonly Deserializer deserializer; public GroupYamlConverter(Deserializer deserializer) { this.deserializer = deserializer; } public bool Accepts(Type type) { return type == typeof(Group); } public object ReadYaml(IParser parser, Type type) { var group = new Group(); var reader = new EventReader(parser); do { var key = reader.Expect(); if(key.Value == "Name") { group.Name = reader.Expect().Value; } else { group.ColumnNames = key.Value .Split(',') .Select(n => n.Trim()) .ToArray(); group.Rows = deserializer.Deserialize>>(reader); } } while(!reader.Accept()); reader.Expect(); return group; } public void WriteYaml(IEmitter emitter, object value, Type type) { throw new NotImplementedException("TODO"); } } 

Por último, registre el convertidor en el deserializador y deserialice el documento:

 var deserializer = new Deserializer(); deserializer.RegisterTypeConverter(new GroupYamlConverter(deserializer)); var document = deserializer.Deserialize(new StringReader(yaml)); 

Puedes probar el ejemplo completamente funcional aquí

Esto es solo una prueba de concepto, pero debería servir como una guía para su propia implementación. Las cosas que podrían mejorarse incluyen:

  • Comprobación y manejo de documentos inválidos.
  • Mejora de la clase Group . Tal vez hacerlo inmutable, y también agregar un indexador.
  • Implementar el método WriteYaml si se desea el soporte de serialización.

Todos estos son archivos YAML válidos. Sin embargo, está confundiendo la interpretación de una clave escalar con comas que constituyen una descripción en YAML de las “columnas” en las secuencias del valor asociado con esa clave.

En el Archivo 1, FirstName, LastName, Age, Height es una clave escalar de cadena única para la asignación que es el primer elemento de la secuencia que es valor para el Group clave en el nivel superior. Al igual que el name es. Puede, pero no tiene que hacerlo en YAML, ponga comillas alrededor de todo el escalar.

La asociación que realice entre una cadena “Nombre” y “Joe” no se encuentra en YAML, puede hacer esa asociación en el progtwig que interpreta la clave (dividiéndola en ", " ) como parece que está haciendo, pero YAML no tiene conocimiento de eso

Entonces, si quieres ser inteligente al respecto, debes dividir la cadena "FirstName, LastName, Age, Height" y usar algún mecanismo para luego usar las “subclaves” para indexar las secuencias asociadas con la clave.

Si ayuda a comprender todo esto, a continuación se muestra un volcado json del contenido de los primeros archivos, donde se ve claramente en qué consisten las claves:

 {"Groups": [{"FirstName, LastName, Age, Height": [["Joe", "Soap", 21, 184], ["Mary", "Ryan", 20, 169], ["Alex", "Dole", 24, 174]], "Name": "ATeam"}]} 

ruamel.yaml biblioteca ruamel.yaml basada en Python para esto (de la cual soy el autor) pero también podría usar un convertidor / verificador en línea como http://yaml-online-parser.appspot.com/