在 C# 中合并 YAML
Merging YAML in C#
我想将两个 YAML 文件合并为一个,这样可以避免重复并合并属性。例如,有两个 yaml 文件,如下所示:
yaml1:
first_name: "John"
last_name: "Smith"
enabled: false
roles:
- user
yaml2:
enabled: true
roles:
- user
- admin
我希望得到以下结果:
first_name: "John"
last_name: "Smith"
enabled: true
roles:
- user
- admin
到目前为止,我能够将 YAML 转换为 JSON 并使用 this example, however, I wanted to know a way using the C# YAML libraries (like yamldotnet and SharpYaml)。
我已经使用 Yamldotnet 实现了它,然后使用以下算法:
使用第一个yaml作为基础
尝试用第二个覆盖第一个yaml
2.1 如果是新字段添加
2.2 如果该字段存在且不是集合,则覆盖它
2.3 如果字段存在且是集合,则合并集合
2.3.1 如果新值不是集合,则加入集合
2.3.2 如果新值是一个集合,则将每个不重复的元素添加到集合中。出于这个原因,我使用了 HashSet
,一个不允许重复项目的集合。
代码:
static void Main(string[] args)
{
var deserializer = new DeserializerBuilder()
.WithNamingConvention(new CamelCaseNamingConvention())
.Build();
var object1 = deserializer.Deserialize<Dictionary<string,object>>(@"---
first_name: ""John""
last_name: ""Smith""
enabled: false
roles:
- user
...");
var object2 = deserializer.Deserialize<Dictionary<string, object>>(@"---
enabled: true
roles:
- user
- admin
...");
foreach (var tuple in object2)
{
if (!object1.ContainsKey(tuple.Key))
{
object1.Add(tuple.Key, tuple.Value);
continue;
}
var oldValue = object1[tuple.Key];
if (!(oldValue is ICollection))
{
object1[tuple.Key] = tuple.Value;
continue;
}
//Merge collection
var mergeCollection = new HashSet<object>(oldValue as IEnumerable<object>);
if (!(tuple.Value is ICollection))
mergeCollection.Add(tuple.Value);
else
{
foreach (var item in tuple.Value as IEnumerable)
{
mergeCollection.Add(item);
}
}
object1[tuple.Key] = mergeCollection;
}
var result = new SerializerBuilder().Build().Serialize(object1);
}
希望对您有所帮助:)
使用 YamlDotNet,如果文档有其部分未使用的唯一类型,这个技巧可能会有所帮助:
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.ObjectFactories;
public Document Load(string[] contents) {
var document = new Document();
var factory = new DefaultObjectFactory();
var deserializer = new DeserializerBuilder()
.WithObjectFactory(type => type == typeof(Document) ? document : factory.Create(type))
.Build();
foreach (var content in contents) {
deserializer.Deserialize<Document>(content);
}
return document;
}
我想将两个 YAML 文件合并为一个,这样可以避免重复并合并属性。例如,有两个 yaml 文件,如下所示:
yaml1:
first_name: "John"
last_name: "Smith"
enabled: false
roles:
- user
yaml2:
enabled: true
roles:
- user
- admin
我希望得到以下结果:
first_name: "John"
last_name: "Smith"
enabled: true
roles:
- user
- admin
到目前为止,我能够将 YAML 转换为 JSON 并使用 this example, however, I wanted to know a way using the C# YAML libraries (like yamldotnet and SharpYaml)。
我已经使用 Yamldotnet 实现了它,然后使用以下算法:
使用第一个yaml作为基础
尝试用第二个覆盖第一个yaml
2.1 如果是新字段添加
2.2 如果该字段存在且不是集合,则覆盖它
2.3 如果字段存在且是集合,则合并集合
2.3.1 如果新值不是集合,则加入集合
2.3.2 如果新值是一个集合,则将每个不重复的元素添加到集合中。出于这个原因,我使用了
HashSet
,一个不允许重复项目的集合。
代码:
static void Main(string[] args)
{
var deserializer = new DeserializerBuilder()
.WithNamingConvention(new CamelCaseNamingConvention())
.Build();
var object1 = deserializer.Deserialize<Dictionary<string,object>>(@"---
first_name: ""John""
last_name: ""Smith""
enabled: false
roles:
- user
...");
var object2 = deserializer.Deserialize<Dictionary<string, object>>(@"---
enabled: true
roles:
- user
- admin
...");
foreach (var tuple in object2)
{
if (!object1.ContainsKey(tuple.Key))
{
object1.Add(tuple.Key, tuple.Value);
continue;
}
var oldValue = object1[tuple.Key];
if (!(oldValue is ICollection))
{
object1[tuple.Key] = tuple.Value;
continue;
}
//Merge collection
var mergeCollection = new HashSet<object>(oldValue as IEnumerable<object>);
if (!(tuple.Value is ICollection))
mergeCollection.Add(tuple.Value);
else
{
foreach (var item in tuple.Value as IEnumerable)
{
mergeCollection.Add(item);
}
}
object1[tuple.Key] = mergeCollection;
}
var result = new SerializerBuilder().Build().Serialize(object1);
}
希望对您有所帮助:)
使用 YamlDotNet,如果文档有其部分未使用的唯一类型,这个技巧可能会有所帮助:
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.ObjectFactories;
public Document Load(string[] contents) {
var document = new Document();
var factory = new DefaultObjectFactory();
var deserializer = new DeserializerBuilder()
.WithObjectFactory(type => type == typeof(Document) ? document : factory.Create(type))
.Build();
foreach (var content in contents) {
deserializer.Deserialize<Document>(content);
}
return document;
}