将多个序列化格式存储在一个文件中? AKA避免了集合的序列化膨胀

时间:2018-06-13 09:16:33

标签: c# json xml serialization yaml

简单的问题,到目前为止,我还没有轻易找到答案。 (类似的问题建议我输入这一点并不相关 - 但我不能相信我是唯一面临这一挑战的人。)

说我在内存中有一个包含

的对象
  1. 简单类型(例如名称,计算机名称,创建日期,配置等);和
  2. 某种的集合(例如统计测量的时间序列,例如移动平均值)
  3. 序列化这些是有道理的

    1. 以简单的序列化格式存储简单类型,例如JSON,XML,YAML
    2. 将收集值存储在CSV文件中(以保存每个条目的不必要的标记重复)
    3. 但这意味着我最终得到了两个文件。如果所有信息都在一个文件中则更好,因此读者可以明确地理解(2)来自(1)的结果。也更容易在文件系统中维护。

      我不想组合成BLOB,因为这会失去人类的可读性。

      是否有一种简单的方法可以将(1)中的JSON和(2)的CSV组合成一个文件?

      我的第一个猜测是让(比方说)XML标签分隔不同的类型。 e.g。

      <SimpleTypes format="JSON">
         [JSON for simple types]
      </SimpleTypes>
      <Collection format="CSV" type="Dictionary" name="DailySalesTotal">
         [CSV for collection]
      </Collection>
      <Collection format="CSV" type="Dictionary" name="DailyFootfallInStore">
         [CSV for collection]
      </Collection>
      

      然后只需打开文件,将XML解析为单独的JSON和CSV部分并正常处理。

      这是一种明智的做法吗?有风险吗?

      或者这里有图书馆吗?我使用C#所以需要一个.NET库。

3 个答案:

答案 0 :(得分:1)

我挑战了为什么这会有意义的原因。

主要是,提议的使用XML的解决方案只是使用另一种序列化格式。让我们看看我们是否能达到既定目标:

  

为每个条目保存不必要的标签重复

与YAML合作。借用您的示例,假设我们将namecomputer_name作为“简单”数据,并将一些数据附加为“集合数据”< / em>的。琐碎的方法看起来像这样:

name: My Name
computer_name: My Computer
collection:
- time: 1:30
  data: foo
- time: 2:20
  data: bar

不涉及重复标签。当反序列化为正确的类型时,YAML将知道collection:的值将是没有显式标记的数据点列表。但是,我们有一个开销,因为我们每次都指定字段名称timedata。所以,让我们试着摆脱它们:

name: My Name
computer_name: My Computer
collection:
- [ 1:30, foo ]
- [ 2:20, bar ]

大多数YAML框架将提供将这些YAML序列反序列化为适当数据类的必要功能。我们仍然在YAML语法中。现在,让我们看看我们是否可以在那里获得实际的CSV:

name: My Name
computer_name: My Computer
collection: |
  1:30;foo
  2:20;bar

使用YAML文字块标量,我们现在将集合数据输入为标量,然后我们可以使用CSV解析器进行解析。我们甚至可以在遇到collection:的值时指示我们的YAML实现立即执行此操作。

使用JSON作为主序列化格式来执行此操作会更加困难,因为JSON没有配备块标量。 XML也可以工作,但它本身非常臃肿。

虽然我们在YAML,但还有另一种可能的解决方案:使用文档结束标记向YAML解析器发出YAML文档在此处结束的信号,并将CSV数据放在其后面。类似的事情在Jekyll中完成,以将“YAML前面的事物”与内容分开。它看起来像这样:

name: My Name
computer_name: My Computer
...
1:30;foo
2:20;bar

...是文档结束标记。 Jekyll使用---代替,根据规范将在那里开始第二个YAML文档,我不知道为什么他们选择这样做。 ...是更符合规范的方式。

答案 1 :(得分:1)

看到这一点。

使用XmlAttribute创建一些模型:

public class Foo
{
    [XmlAttribute]
    public string Bar { get; set; }
    [XmlAttribute]
    public List<int> List1 { get; set; }
    [XmlAttribute]
    public List<double> List2 { get; set; }
}

序列化:

var foo = new Foo
{
    Bar = "test",
    List1 = new List<int> { 1, 2, 3 },
    List2 = new List<double> { 0.1, 0.2, 0.3 }
};

var xs = new XmlSerializer(typeof(Foo));
var settings = new XmlWriterSettings { NewLineOnAttributes = true, Indent = true };
using (var xmlWriter = XmlWriter.Create(Console.Out, settings))
{
    xs.Serialize(xmlWriter, foo);
}

Console.WriteLine();

结果紧凑且易读:

<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  Bar="test"
  List1="1 2 3"
  List2="0.1 0.2 0.3" />

不要重新发明轮子。

答案 2 :(得分:0)

我找到了两个折衷的解决方案,它们很好用。

  1. 使用相同的文件名和不同的扩展名为每种序列化格式保存文件,例如<GUID>.csv <GUID>.xml <GUID.yaml> <GUID>.json
  2. 使用上面flyx概述的YAML方法

因此,flyx的答案已被接受为答案。非常感谢!