YAML 语法简介与 C# 操作示例
〇、简介
YAML(Yet Another Markup Language)另一种标记语言。
YAML 是一种较为人性化的数据序列化语言,可以配合目前大多数编程语言使用。YAML 的语法比较简洁直观,特点是使用空格来表达层次结构,其最大优势在于数据结构方面的表达,所以 YAML 更多应用于编写配置文件,其文件一般以 .yml 为后缀。
特点:
- 易于阅读:YAML 使用缩进和比较简洁的语法来表示数据结构,使得它比许多其他数据格式更容易阅读和理解。
- 数据结构友好:YAML 天然支持标量(如字符串、整数、浮点数)、列表(数组)和映射(字典)等数据结构。
- 无类型标签:YAML 通过上下文来推断值的类型,不需要显式的类型标签。
- 可交互:YAML 可以在不同的编程语言之间进行交互,因为它有广泛的语言支持。
- 表达能力强:YAML 可以表示复杂的数据结构,并且可以通过锚点和别名来重用数据。
- 可伸缩性:YAML 可以很容易地扩展到新的数据类型,而不需要改变现有的解析器。
YAML 的使用场景包括但不限于:应用程序的配置、数据交换格式、文档撰写、自动化脚本、云计算和服务编排等等。
一、YAML 语法
1.1 基本语法
- 大小写敏感。
- 使用缩进表示层级关系。
- 缩进时不允许使用Tab键,只允许使用空格。
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可。
# YAML
one:
two: 2
three:
four: 4
five: 5
// 转成 JSON 后的格式
"one": {
"two": 2,
"three": {
"four": 4,
"five": 5
}
}
- 用 # 标识注释,且只能单行
# 我是一行注释
# 我是另一行注释
- 一个 YAML 文件可以包含多个文档
每个文档均以“---”三个横杠开始,如果一个文件中仅一个文档,则可省略。
每个文档并不必须使用结束符“...”来表示结束,但是对于网络传输或者流来说,作为明确结束的符号,有利于软件处理。(例如,不需要知道流关闭就能知道文档结束)
---
# 这是第一份文档内容
one: 1
# 其他内容...
...
---
# 这是第二份文档内容
two: 2
# 其他内容...
1.2 数据结构与类型
1.2.1 对象 Mapping
标识以键值对(key: value)形式出现的数据。
- 格式
在键和值中间加入标识,冒号+空格(: )。
# YAML
key: value
// JSON
{
"key": "value"
}
- 多层嵌套数据
用缩进表示层级关系
# YAML
key:
child-key1: value1
child-key2: value2
// JSON
{
"key": {
"child-key1": "value1",
"child-key2": "value2",
}
}
- 用一对 {} 花括号包裹,表示一个键值表
键值对之间用逗号+空格(, )分隔,类似 JSON。
# YAML
key: { child-key1: value1, child-key2: value2 }
// JSON
{
"key": {
"child-key1": "value1",
"child-key2": "value2"
}
}
- 问号+空格(? )表示复杂的键
当键是一个列表或键值表时,就需要使用本符号来标记。
# 使用一个列表作为键
[blue, reg, green]: Color
# 等价于
? - blue
- reg
- gree
: Color
// JSON
{
"blue,reg,gree": "Color"
}
- 多种组合表示
每个结构都可以嵌套组成复杂的表示结构。
# YAML
div:
- border: {color: red, width: 2px}
- background: {color: green}
- padding: [0, 10px, 0, 10px]
// JSON
{
"div": [
{
"border": {
"color": "red",
"width": "2px"
}
},
{
"background": {
"color": "green"
}
},
{
"padding": [0, "10px", 0, "10px"]
}
]
}
# YAML
items:
- item: cpu
model: i3
price: ¥800.00
- item: HD
model: WD
price: ¥450.00
// JSON
{
"items": [
{
"item": "cpu",
"model": "i3",
"price": "¥800.00"
},
{
"item": "HD",
"model": "WD",
"price": "¥450.00"
}
]
}
1.2.2 数组 Sequence
- 横线+空格(- )开头的数据组成一个数组
# YAML 区块格式(Block Format)
values:
- value1
- value2
- value3
# YAML 内联格式(Inline Format)
values: [value1, value2, value3]
// JSON
{
"values": [
"value1",
"value2",
"value3"
]
}
- 多维数组
# YAML
values:
-
- value1
- value2
-
- value3
- value4
// JSON
{
"values": [
[
"value1",
"value2"
],
[
"value3",
"value4"
]
]
}
- 数组组合
# YAML
- [blue, red, green] # 列表项本身也是一个列表
- [Age, Bag]
- site: {osc:www.oschina.net, baidu: www.baidu.com} # 这里是同 键值表 组合表示
// JSON
[
[
"blue",
"red",
"green"
],
[
"Age",
"Bag"
],
{
"site": {
"osc:www.oschina.net": null,
"baidu": "www.baidu.com"
}
}
]
- 复合结构
# YAML
languages:
- Ruby
- Perl
- Python
websites:
YAML: yaml.org
Ruby: ruby-lang.org
Python: python.org
Perl: use.perl.org
// JSON
{
"languages": [
"Ruby",
"Perl",
"Python"
],
"websites": {
"YAML": "yaml.org",
"Ruby": "ruby-lang.org",
"Python": "python.org",
"Perl": "use.perl.org"
}
}
1.2.3 标量 Scalars 基本数据类型-str、bool、int、float、null、datetime...
本章节包含以下部分简介:字符串 String、布尔值 boolean、整数 Integer、浮点数 Float、空 Null、日期时间 datetime、类型强制转换等。
- 字符串(string、str)
字符串是最常见,也是最复杂的一种数据类型。
字符串一般不需要用引号包裹,但是如果字符串中使用了反斜杠“\”开头的转义字符就必须使用引号包裹。
# YAML
strings:
- Hello without quote # 不用引号包裹
- Hello
world # 拆成多行后会自动在中间添加空格
- 'Hello with single quotes' # 单引号包裹
- "Hello with double quotes" # 双引号包裹
- "I am fine. \u263A" # 使用双引号包裹时支持 Unicode 编码
- "\x0d\x0a is \r\n" # 使用双引号包裹时还支持 Hex 编码
- 'He said: "Hello!"' # 单双引号支持嵌套"
// JSON
{
"strings": [
"Hello without quote",
"Hello world",
"Hello with single quotes",
"Hello with double quotes",
"I am fine. ",
"\r\n is \r\n",
"He said: \"Hello!\""
]
}
用竖线符“ | ”来表示保留换行(Newlines preserved)。
每行的前边缩进和后边的空白会被去掉,而额外的缩进和行后的空格会被保留。
# YAML
lines: |
我是第一行
我是第二行
我是吴彦祖
我是第四行
我是第五行
// JSON
{
"lines": "我是第一行 \n我是第二行\n 我是吴彦祖\n 我是第四行\n我是第五行\n"
}
用右尖括号“ > ”来表示折叠换行(Newlines folded)。
只有空白行才会被识别为换行,原来的换行符都会被转换成空格。最后也会以换行符结束。
# YAML
lines: >
我是第一行
我也是第一行
我仍是第一行
我依旧是第一行
我是第二行
这么巧我也是第二行
// JSON
{
"lines": "我是第一行 我也是第一行 我仍是第一行 我依旧是第一行\n我是第二行 这么巧我也是第二行\n"
}
- 布尔值(Boolean、bool)
经测试,只有全部大写、全部小写、首字母大写这三种情况,可以自动识别为布尔值。其他情况均转成字符串,如下:
# YAML
boolean:
- true
- True
- TRUE
- TRue
- false
- False
- FALSE
- FAlse
// JSON
{
"boolean": [
true,
true,
true,
"TRue",
false,
false,
false,
"FAlse"
]
}
- 整数(Integer、int)
YAML 允许二进制的整数,但前边需要带上标识:‘0b’。
# YAML
int:
- 666
- 0b0010_1110 # 二进制表示
//JSON
{
"int": [
666,
46
]
}
- 浮点数(Floating-point、float)
允许使用科学计数法,如下代码:
# YAML
float:
- 3.14
- 6.8523015e+5 # 使用科学计数法
// JSON
{
"float": [
3.14,
685230.15
]
}
- 空(Null)
# YAML
nulls:
- null
- Null
- ~
- # 未指定值
// JSON
{
"nulls": [
null,
null,
null,
null
]
}
- 日期时间(date、datetime)
没有 +8 小时的标记时,默认就是协调世界时(UTC),也就是标准时间,转换成 JSON 都是按照协调世界时的格式,如下代码:
# YAML
dates:
- 2024-03-05 # 协调世界时(UTC)
- 2024-03-05T20:00:00 # 协调世界时(UTC)
- 2024-03-05T20:00:00+08:00 # +8 小时就是北京时间
- 2024-03-05T20:00:00.10+08:00
- 2024-03-05 20:00:00.10 +8
// JSON
{
"dates": [
"2024-03-05T00:00:00.000Z",
"2024-03-05T20:00:00.000Z",
"2024-03-05T12:00:00.000Z",
"2024-03-05T12:00:00.100Z",
"2024-03-05T12:00:00.100Z"
]
}
- 类型转换(双叹号:!!)
YAML 支持使用严格类型标签:“!!”(格式:双感叹号+目标类型),来强制转换类型,如下代码:
# YAML
strings_convert:
- !!float '666' # 字符串转浮点数
- '666'
- !!str 666 # 整数转为字符串
- !!str 666.66 # 浮点数转为字符串
- !!str true # 布尔值转为字符串
- !!bool 'true' # 字符串转布尔值
// JSON
{
"strings_convert": [
666,
"666",
"666",
"666.66",
"true",
true
]
}
1.3 数据重用和合并(&、*、<<)
为了保持内容的简洁,避免过多重复的定义,YAML 提供了由锚点标签“&”和引用标签“*”组成的语法,利用这套语法可以快速引用相同的一些数据。如下代码:
# YAML
a: &anchor # 设置锚点
one: 1
two: 2
three: 3
b: *anchor # 引用锚点
// JSON
{
"a": {
"one": 1,
"two": 2,
"three": 3
},
"b": {
"one": 1,
"two": 2,
"three": 3
}
}
配合合并标签“<<”使用可以与任意数据进行合并,可以把这套操作,类比为面向对象语言中的继承。如下代码:
# YAML
human: &base # 添加名为 base 的锚点
body: 1
hair: 999
singer:
<<: *base # 引用 base 锚点,实例化时会自动展开
skill: sing # 添加额外的属性
programer:
<<: *base # 引用 base 锚点,实例化时会自动展开
hair: 6 # 覆写 base 中的属性
skill: code # 添加额外的属性
// JSON
{
"human": {
"body": 1,
"hair": 999
},
"singer": {
"body": 1,
"hair": 999,
"skill": "sing"
},
"programer": {
"body": 1,
"hair": 6,
"skill": "code"
}
}
参考:https://zhuanlan.zhihu.com/p/145173920 https://www.jianshu.com/p/413576dc837e https://zhuanlan.zhihu.com/p/75067291 https://ruanyifeng.com/blog/2016/07/yaml.html
测试 yaml 转 json:https://www.lddgo.net/convert/yaml-to-json
二、C# 读取 YAML 配置文件示例
知道了 YAML 的特点和语法,下面就来上马试试看吧。
2.1 安装必要的动态库 YamlDotNet
首先通过 NuGet 安装依赖:YamlDotNet,这个动态库是比较专门为 C# 操作 YAML 定制的,官方支持非常好。
2.2 YAML 示例文件
如下文件中,一个主节点中包含两个子节点:
assetBundles: # 主节点
- name: myname # 子节点-1
size: 123
variant: ''
version: 1
md5: sdhbuuhkhekghddfgkshjgn
dependencies: []
local: false
assets:
- Assets1/Birthday_FUMSIAMO.png
- Assets1/Partner_lock.png
- Assets1/shop_01.png
- name: myname2 # 子节点-2
size: 1232
variant: ''
version: 2
md5: sdhbuuhkhekghddfgkshjgn
dependencies: [1,2]
local: false
assets:
- Assets2/Birthday_FUMSIAMO.png
- Assets2/Partner_lock.png
- Assets2/shop_01.png
2.2 实际的操作代码
2.2.1 先看测试代码和测试结果
// 必要的引用
using System;
using System.Text;
using System.Collections.Generic;
using System.IO;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
// 测试一下 【读取、修改、保存】
static void Main(string[] args)
{
var serializer = new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build();
var deserializer = new DeserializerBuilder().WithNamingConvention(UnderscoredNamingConvention.Instance).Build();
var ymlFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "asset_table.yml");
if (File.Exists(ymlFile))
{
var ymlContent = File.ReadAllText(ymlFile); // 读取 yaml 文件内容
var buildConfig = deserializer.Deserialize<BuildConfigFile>(ymlContent); // 序列化
if (buildConfig != null)
{
foreach (var item in buildConfig.assetBundles)
{
// 获取配置内容并修改
if(item.name== "myname")
item.name = "myname_new";
else if(item.name=="myname2")
item.name = "myname2_new";
}
// 序列化成新的 yaml 文本并保存
var newYamlContent = serializer.Serialize(buildConfig);
File.WriteAllText(ymlFile, newYamlContent);
}
}
}
测试结果:
注意:修改后的文件存在调试文件夹中:\bin\Debug\net7.0\asset_table.yml,在项目中的 asset_table.yml 文件依然是没有变化。
2.2.2 根据示例 YAML 文件输出基本数据模型
public class BuildConfigFile
{
public class AssetBundleItem
{
[YamlMember(Alias = "name")]
public string name { get; set; }
[YamlMember(Alias = "size")]
public long size { get; set; }
[YamlMember(Alias = "variant")]
public string variant { get; set; }
[YamlMember(Alias = "version")]
public long version { get; set; }
[YamlMember(Alias = "md5")]
public string md5 { get; set; }
[YamlMember(Alias = "md5bytes")]
public string md5bytes { get; set; }
[YamlMember(Alias = "dependencies")]
public string[] dependencies { get; set; }
[YamlMember(Alias = "local")]
public bool local { get; set; }
[YamlMember(Alias = "assets")]
public string[] assets { get; set; }
}
[YamlMember(Alias = "assetBundles")]
public List<AssetBundleItem> assetBundles { get; set; }
}
2.2.3 最后是压轴的 YAML 操作类
public static class YamlHelper
{
private static ISerializer _serializer;
private static IDeserializer _deserializer;
static YamlHelper()
{
_serializer = new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build();
_deserializer = new DeserializerBuilder().WithNamingConvention(UnderscoredNamingConvention.Instance).Build();
}
public static string Serialize(object target)
{
return _serializer.Serialize(target);
}
public static void SerializeToFile(object target, string filePath)
{
var content = Serialize(target);
File.WriteAllText(filePath, content, Encoding.UTF8);
}
public static T Deserialize<T>(string yaml)
{
return _deserializer.Deserialize<T>(yaml);
}
public static T DeserializeFromFile<T>(string filePath)
{
var yaml = File.ReadAllText(filePath, Encoding.UTF8);
return Deserialize<T>(yaml);
}
}
2.3 遇到的一个报错“Property 'assetBundles' not found on type 'TimerDispose.BuildConfigFile'.”
第一次运行没问题,但重复运行程序时,就会报出这个错误:
原因:是由于生成新的 YAML 文件中主节点由原本的 asset_bundles 更新成 assetBundles。数据模型中设置为 Alias = "asset_bundles",因此无法读取成功。
因此,这个报错的主要意思就是,根据设定好的数据模型,因字段对应不上而识别失败。
参考:https://blog.csdn.net/rjcql/article/details/134341930
YAML 语法简介与 C# 操作示例的更多相关文章
- Android系统Recovery工作原理之使用update.zip升级过程---updater-script脚本语法简介以及执行流程(转)
目前update-script脚本格式是edify,其与amend有何区别,暂不讨论,我们只分析其中主要的语法,以及脚本的流程控制. 一.update-script脚本语法简介: 我们顺着所生成的脚本 ...
- Android系统Recovery工作原理之使用update.zip升级过程分析(九)---updater-script脚本语法简介以及执行流程【转】
本文转载自:http://blog.csdn.net/mu0206mu/article/details/7465603 Android系统Recovery工作原理之使用update.zip ...
- YAML文件简介
编程免不了要写配置文件,怎么写配置也是一门学问. YAML 是专门用来写配置文件的语言,非常简洁和强大,远比 JSON 格式方便. 本文介绍 YAML 的语法,以 JS-YAML 的实现为例.你可以去 ...
- ansible中yaml语法应用
4.yaml语法应用 ansible的playbook编写是yaml语言编写,掌握yaml语法是编写playbook的必要条件,格式要求和Python相似,具体教程参考如下 yaml语言教程 附上一个 ...
- YAML语法基础(K8s基础)
对于YAML语言,网上有很多将YAML转换为JSON格式的在线转换器,以下内容都可直接验证,另外若有兴趣更深入学习YAML,可到其官方站点去学习,下面介绍的仅仅是比较常用的内容,并非YAML语法的全部 ...
- ansible-playbook的YAML语法学习
YAML:可以将你打算对多机器的批量操作放到一个文件中,顺序执行,可以根据机器做到根据机器信息判断执行,其他命令执行结果判断执行. YAML有着严格的层级要求,稍微有个缩进问题就会无法运行,所以学习过 ...
- YAML语法使用,JSR303数据校验
YAML YAML是 "YAML Ain't a Markup Language" (YAML不是一种置标语言)的递归缩写 # yaml配置 server: prot: YAML语 ...
- Azure Bicep(二)语法简介
一,引言 上一篇文章有介绍到 Azure Bicep 的部署问题,文中也只是演示部署范围为 Sub,并将演示的 Azure Resource Group 到 Azure.给定 Bicep 文件,可以部 ...
- Hudi 数据湖的插入,更新,查询,分析操作示例
Hudi 数据湖的插入,更新,查询,分析操作示例 作者:Grey 原文地址: 博客园:Hudi 数据湖的插入,更新,查询,分析操作示例 CSDN:Hudi 数据湖的插入,更新,查询,分析操作示例 前置 ...
- YAML 语法
YAML 语法 来源:yaml 这个页面提供一个正确的 YAML 语法的基本概述, 它被用来描述一个 playbooks(我们的配置管理语言). 我们使用 YAML 是因为它像 XML 或 JSON ...
随机推荐
- 每日一库:GORM简介
GORM(Go Object-Relational Mapping)是一个用于Go语言的ORM库,它提供了一种简单.优雅的方式来操作数据库.GORM支持多种数据库,包括MySQL.PostgreSQL ...
- Unity的SpriteAtlas实践
我的环境 Unity引擎版本:Unity2019.3.7f1 AssetBundles-Browser 于2021-1-14拉取,github上最后提交日期是2019-12-14,在本文简称:ABBr ...
- 从零开始配置 vim(9)——初始配置
虽然本系列文章叫做从0开始配置vim,似乎我们从一开始就要写vimrc配置文件,但是我们并没有这么做.我们先经过几篇文章了解了下面的几个内容 如何设置vim属性,从而改变vim的特征 配置快捷键,以提 ...
- 从零开始匹配vim(1)——选项设置
前面我们算是对 vimscript 做了一个入门,并且实现了一个 输出 hello world 的语句.现在我们继续进行 vimscript 的学习. set语句 之前在介绍 vim 基础的时候,我们 ...
- 遥感图像处理笔记之【Automatic Flood Detection from Satellite Images Using Deep Learning】
遥感图像处理学习(7) 前言 遥感系列第7篇.遥感图像处理方向的学习者可以参考或者复刻 本文初编辑于2023年12月29日 2024年1月24日搬运至本人博客园平台 文章标题:Automatic Fl ...
- IDEA破解(无限重启激活时间版)
下载地址[将下载的目录打成zip压缩包后使用]:「ide-eval-resetter」https://www.aliyundrive.com/s/UFHpDX5d6Xv 点击链接保存,或者复制本段内容 ...
- 【C语言深度解剖】一篇解决程序的环境【编译+链接详解】让面试官给我们竖起大拇指
文章目录 程序的翻译环境 翻译环境详解 编译 预编译 编译 汇编 关于形成符号表 链接 运行环境 尾声 [C语言深度解剖][Linux操作系统]程序的环境[编译+链接详解] 那么这里博主先安利一下一些 ...
- CentOS7环境下MySQL的主从配置
CentOS7环境下MySQL的主从配置 一.什么叫主从复制 通过在主服务器和从服务器之间切分处理客户查询的负荷,可以得到更好的客户响应时间.通俗点说就是select查询发送到从服务器,修改数据的语句 ...
- Java 运算符 - 除法
1. 除法运算符 Java中的除法运算符是"/"符号,表示将左侧操作数除以右侧操作数. 2. 整数除法 在Java中,整数除法的结果是一个整数,即只保留除法的整数部分,舍去小数部分 ...
- 到什么程度才叫精通 Linux?
大家好,我是陶朱公Boy,一个认真生活,总想超越自己的程序员. 前言 知乎上有一个提问:到什么程度才叫精通 Linux? ↓↓↓ 今天,我们就 ...