Слияние YAML в 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 и использовать этот пример, однако я хотел узнать, как использовать библиотеки CAM YAML (такие как yamldotnet и SharpYaml).
1 ответ
Я добился этого с помощью 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;
}