反序列化数据的YAML“表”

我使用yamldotnet和c#来反序列化由第三方软件应用程序创建的文件。 以下YAML文件示例均在应用程序中有效:

#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] 

请注意,File2没有任何Age列,但反序列化器仍必须识别每行的第三个值是高度而不是年龄。 这些数据应该代表一个人的表。 以File1为例,Mary Ryan年仅20岁,身高169厘米。 反序列化器需要理解它具有的列(对于File2,它只有FirstName,LastName和Height)并相应地将数据存储在正确的对象中:Mary Ryan高169厘米。

类似地,程序文档声明列的顺序并不重要,因此下面的File3是一种同样有效的方式来表示File2中的数据,即使Height现在是第一个:

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

我有很多问题:

  1. 这是标准的YAML吗? – 我找不到任何关于在同一行上使用多个键的内容,后面跟一个冒号和值列表来表示数据表。
  2. 我如何使用yamldotnet对其进行反序列化? 我可以做些修改来帮助它吗?
  3. 如果我不能使用yamldotnet,我应该怎么做呢?

正如其他答案所述,这是有效的YAML。 但是,文档的结构特定于应用程序,并且不使用YAML的任何特殊function来表达表。

您可以使用YamlDotNet轻松解析此文档。 但是你会遇到两个困难。 首先,由于列的名称放在键内,因此您需要使用一些自定义序列化代码来处理它们。 第二,您需要实现某种抽象,以便能够以表格方式访问数据。

我已经提出了一个概念certificate,它将说明如何解析和读取数据。

首先,创建一个类型来保存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; } } 

然后实现IYamlTypeConverter来解析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"); } } 

最后,将转换器注册到反序列化器并反序列化文档:

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

您可以在此处测试完整的工作示例

这只是一个概念certificate,但它应该作为您自己实现的指南。 可以改进的事情包括:

  • 检查和处理无效文档。
  • 改善Group课程。 也许让它变成不可变的,并且还添加一个索引器。
  • 如果需要序列化支持,则实现WriteYaml方法。

所有这些都是有效的YAML文件。 然而,您错误地用逗号解释标量键作为与该键相关联的值的序列中的“列”的YAML中的描述。

在文件1中, FirstName, LastName, Age, Height是映射的单个字符串标量键,它是序列的第一个元素,它是顶级键Group的值。 就像name一样。 你可以,但不必在YAML中,在整个标量周围加上引号。

您在YAML中不存在字符串“Firstname”和“Joe”之间的关联,您可以在解释键的程序中进行该关联(通过将其拆分为", " ),就像您似乎正在做的那样,但是YAML对此一无所知。

因此,如果您想要明智,那么您需要自己拆分字符串"FirstName, LastName, Age, Height"并使用某种机制然后使用“子键”来索引与键关联的序列。

如果它有助于理解所有这些,以下是第一个文件内容的j​​son转储,在那里你可以清楚地看到键包含的内容:

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

我使用了基于Python的ruamel.yaml库(其中我是作者)但您也可以使用在线转换器/检查器,如http://yaml-online-parser.appspot.com/