〇、简介

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# 操作示例的更多相关文章

  1. Android系统Recovery工作原理之使用update.zip升级过程---updater-script脚本语法简介以及执行流程(转)

    目前update-script脚本格式是edify,其与amend有何区别,暂不讨论,我们只分析其中主要的语法,以及脚本的流程控制. 一.update-script脚本语法简介: 我们顺着所生成的脚本 ...

  2. Android系统Recovery工作原理之使用update.zip升级过程分析(九)---updater-script脚本语法简介以及执行流程【转】

    本文转载自:http://blog.csdn.net/mu0206mu/article/details/7465603       Android系统Recovery工作原理之使用update.zip ...

  3. YAML文件简介

    编程免不了要写配置文件,怎么写配置也是一门学问. YAML 是专门用来写配置文件的语言,非常简洁和强大,远比 JSON 格式方便. 本文介绍 YAML 的语法,以 JS-YAML 的实现为例.你可以去 ...

  4. ansible中yaml语法应用

    4.yaml语法应用 ansible的playbook编写是yaml语言编写,掌握yaml语法是编写playbook的必要条件,格式要求和Python相似,具体教程参考如下 yaml语言教程 附上一个 ...

  5. YAML语法基础(K8s基础)

    对于YAML语言,网上有很多将YAML转换为JSON格式的在线转换器,以下内容都可直接验证,另外若有兴趣更深入学习YAML,可到其官方站点去学习,下面介绍的仅仅是比较常用的内容,并非YAML语法的全部 ...

  6. ansible-playbook的YAML语法学习

    YAML:可以将你打算对多机器的批量操作放到一个文件中,顺序执行,可以根据机器做到根据机器信息判断执行,其他命令执行结果判断执行. YAML有着严格的层级要求,稍微有个缩进问题就会无法运行,所以学习过 ...

  7. YAML语法使用,JSR303数据校验

    YAML YAML是 "YAML Ain't a Markup Language" (YAML不是一种置标语言)的递归缩写 # yaml配置 server: prot: YAML语 ...

  8. Azure Bicep(二)语法简介

    一,引言 上一篇文章有介绍到 Azure Bicep 的部署问题,文中也只是演示部署范围为 Sub,并将演示的 Azure Resource Group 到 Azure.给定 Bicep 文件,可以部 ...

  9. Hudi 数据湖的插入,更新,查询,分析操作示例

    Hudi 数据湖的插入,更新,查询,分析操作示例 作者:Grey 原文地址: 博客园:Hudi 数据湖的插入,更新,查询,分析操作示例 CSDN:Hudi 数据湖的插入,更新,查询,分析操作示例 前置 ...

  10. YAML 语法

    YAML 语法 来源:yaml 这个页面提供一个正确的 YAML 语法的基本概述, 它被用来描述一个 playbooks(我们的配置管理语言). 我们使用 YAML 是因为它像 XML 或 JSON ...

随机推荐

  1. 每日一库:GORM简介

    GORM(Go Object-Relational Mapping)是一个用于Go语言的ORM库,它提供了一种简单.优雅的方式来操作数据库.GORM支持多种数据库,包括MySQL.PostgreSQL ...

  2. Unity的SpriteAtlas实践

    我的环境 Unity引擎版本:Unity2019.3.7f1 AssetBundles-Browser 于2021-1-14拉取,github上最后提交日期是2019-12-14,在本文简称:ABBr ...

  3. 从零开始配置 vim(9)——初始配置

    虽然本系列文章叫做从0开始配置vim,似乎我们从一开始就要写vimrc配置文件,但是我们并没有这么做.我们先经过几篇文章了解了下面的几个内容 如何设置vim属性,从而改变vim的特征 配置快捷键,以提 ...

  4. 从零开始匹配vim(1)——选项设置

    前面我们算是对 vimscript 做了一个入门,并且实现了一个 输出 hello world 的语句.现在我们继续进行 vimscript 的学习. set语句 之前在介绍 vim 基础的时候,我们 ...

  5. 遥感图像处理笔记之【Automatic Flood Detection from Satellite Images Using Deep Learning】

    遥感图像处理学习(7) 前言 遥感系列第7篇.遥感图像处理方向的学习者可以参考或者复刻 本文初编辑于2023年12月29日 2024年1月24日搬运至本人博客园平台 文章标题:Automatic Fl ...

  6. IDEA破解(无限重启激活时间版)

    下载地址[将下载的目录打成zip压缩包后使用]:「ide-eval-resetter」https://www.aliyundrive.com/s/UFHpDX5d6Xv 点击链接保存,或者复制本段内容 ...

  7. 【C语言深度解剖】一篇解决程序的环境【编译+链接详解】让面试官给我们竖起大拇指

    文章目录 程序的翻译环境 翻译环境详解 编译 预编译 编译 汇编 关于形成符号表 链接 运行环境 尾声 [C语言深度解剖][Linux操作系统]程序的环境[编译+链接详解] 那么这里博主先安利一下一些 ...

  8. CentOS7环境下MySQL的主从配置

    CentOS7环境下MySQL的主从配置 一.什么叫主从复制 通过在主服务器和从服务器之间切分处理客户查询的负荷,可以得到更好的客户响应时间.通俗点说就是select查询发送到从服务器,修改数据的语句 ...

  9. Java 运算符 - 除法

    1. 除法运算符 Java中的除法运算符是"/"符号,表示将左侧操作数除以右侧操作数. 2. 整数除法 在Java中,整数除法的结果是一个整数,即只保留除法的整数部分,舍去小数部分 ...

  10. 到什么程度才叫精通 Linux?

    大家好,我是陶朱公Boy,一个认真生活,总想超越自己的程序员. 前言 知乎上有一个提问:到什么程度才叫精通 Linux?                              ↓↓↓ 今天,我们就 ...