是否可以禁止YAML文件中的重复项?

时间:2015-05-28 15:20:24

标签: yamldotnet

我正在使用YamlDotNet来解析简单的配置文件(没有深度嵌套等)。反序列化器将解析包含重复字段的字符串,覆盖先前的值。例如,

foo: bar
foo: baz

被认为等同于

foo: baz

对于我的应用程序,我希望这样的重复会导致抛出异常。这可能吗?

3 个答案:

答案 0 :(得分:0)

默认节点反序列化器使用索引器来指定值。实现所需行为的一种方法是反序列化为不允许重复值的类型,例如:

public class UniqueKeysDictionary<TKey, TValue>
    : Dictionary<TKey, TValue>
    , IDictionary<TKey, TValue>
{
    TValue IDictionary<TKey, TValue>.this[TKey key]
    {
        get { return base[key]; }
        set { base.Add(key, value); }
    }
}

A fully working example can be found here

此解决方案的一个重要问题是它违反了contract of the indexer,其行为应该是覆盖该值。

另一种方法是将GenericDictionaryNodeDeserializer的实现替换为使用Add()方法而不是索引器的方法。这是different example that shows how to replace a node deserializer

的相关部分
var deserializer = new Deserializer();

var objectDeserializer = deserializer.NodeDeserializers
    .Select((d, i) => new {
        Deserializer = d as ObjectNodeDeserializer,
        Index = i
    })
    .First(d => d.Deserializer != null);

deserializer.NodeDeserializers[objectDeserializer.Index] =
    new ValidatingNodeDeserializer(objectDeserializer.Deserializer);

答案 1 :(得分:0)

有一个涉及linter的解决方案,但我不确定它是否与之相关 因为它不会导致在YamlDotNet中抛出异常。我会发布它 无论如何,因为它可以避免替换执行 GenericDictionaryNodeDeserializer

这是yamllint命令行工具:

sudo pip install yamllint

具体来说,它有一个规则key-duplicates来检测重复的密钥:

$ cat test.yml
foo: bar
foo: baz

$ yamllint test.yml
test.yml
  2:1       error    duplication of key "foo" in mapping  (key-duplicates)

答案 2 :(得分:0)

UniqueKeysDictionary示例对我不起作用,从第二个示例开始,尚不清楚如何验证。但是我发现如果任何重复项被禁止并且可以两次加载文件是可以接受的简单得多的方法:

    private T DeserializeAndValidate<T>(StreamReader reader)
    {
        var yaml = new YamlStream();
        yaml.Load(reader); // throws if duplicates are found

        reader.BaseStream.Seek(0, SeekOrigin.Begin);
        using (var reader2 = new StreamReader(reader.BaseStream))
        {
            var deserializer = new Deserializer();
            var data = deserializer.Deserialize<T>(reader2);
            return data;
        }
    }