項目中需要將Yaml文件反序列化爲自定義的強類型對象進而對其內容進行修改。
這裏參考https://blog.walterlv.com/post/serialize-and-deserialize-yaml.html
.NET 並沒有原生提供對 YAML 的序列化和反序列化。雖然 YAML 文件的解析並不難,不過如果不是處於特別的理由(比如性能),使用現有的庫解析 YAML 是比較好的選擇。
本文推薦使用 YamlDotNet 序列化和反序列化 YAML。
本文內容
YAML 元數據
作爲示例,我拿出我在去年寫的一篇博客的元數據進行分析:
layout: post
title: "利用 TypeConverter,轉換字符串和各種類型只需寫一個函數"
date_published: 2017-01-17 18:13:00 +0800
date: 2018-04-23 07:31:32 +0800
categories: dotnet
permalink: /dotnet/2017/01/17/convert-using-type-converter.html
keywords: dotnet typeconverter
description: 使用 TypeConverter 實現字符串轉各種類型。
注意,實際上元數據是包含開始標籤和結束標籤的。yaml 元數據以 ---
包裹,toml 元數據以 +++
包裹。
由於從 Markdown 中解析出 YAML 元數據不是本文的重點,所以我放到最後一起說明。
定義 .NET 類型
我們需要先定義 .NET 類型,以便 YamlDotNet 進行序列化和反序列化。
public sealed class YamlFrontMeta
{
[YamlMember(Alias = "title", ApplyNamingConventions = false)]
public string Title { get; set; }
[YamlMember(Alias = "date", ApplyNamingConventions = false)]
public string Date { get; set; }
[YamlMember(Alias = "date_published", ApplyNamingConventions = false)]
public string PublishDate { get; set; }
[YamlMember(Alias = "layout", ApplyNamingConventions = false)]
public string Layout { get; set; }
[YamlMember(Alias = "permalink", ApplyNamingConventions = false)]
public string PermanentUrl { get; set; }
[YamlMember(Alias = "categories", ApplyNamingConventions = false)]
public string Categories { get; set; }
[YamlMember(Alias = "tags", ApplyNamingConventions = false)]
public string Tags { get; set; }
[YamlMember(Alias = "keywords", ApplyNamingConventions = false)]
public string Keywords { get; set; }
[YamlMember(Alias = "description", ApplyNamingConventions = false)]
public string Description { get; set; }
[YamlMember(Alias = "versions", ApplyNamingConventions = false)]
public List<VersionsInfo> Versions { get; set; }
[YamlMember(Alias = "published", ApplyNamingConventions = false)]
public bool IsPublished { get; set; } = true;
[YamlMember(Alias = "sitemap", ApplyNamingConventions = false)]
public bool IsInSiteMap { get; set; } = true;
}
.NET 類型中的屬性必須是 YAML 文件中屬性的超集。
以上 ApplyNamingConventions
屬性的默認值是 true
,這爲了解決一些命名約束上的問題,詳見:YamlMember Alias isn’t applied when using the CamelCaseNamingConvention · Issue #228 · aaubry/YamlDotNet。
另外,如果 YAML 屬性中包含數組,則需要將屬性的類型設置爲集合類型。
title: "Good Framework Rely on Good Api —— Six API Design Principles"
date_published: 2018-06-30 19:09:53 +0800
date: 2018-08-12 16:04:26 +0800
categories: dotnet framework
versions:
- 中文: /post/framework-api-design.html
- English: #
public sealed class VersionInfo
{
[YamlMember(Alias = "current", ApplyNamingConventions = false)]
public string Current { get; set; }
}
public sealed class VersionsInfo
{
[YamlMember(Alias = "中文", ApplyNamingConventions = false)]
public string Chinese { get; set; }
[YamlMember(Alias = "English", ApplyNamingConventions = false)]
public string English { get; set; }
}
序列化與反序列化
使用 Deserializer
類型可以反序列化一個 YAML 元數據。
var deserializer = new Deserializer();
var matter = deserializer.Deserialize<YamlFrontMeta>(yamlText);
使用 Serializer
類型可以序列化一個 YAML 元數據到字符串。這樣,就能更新博客的 YAML 元數據部分了。
var serializer = new Serializer();
var yamlText = serializer.Serialize(matter);