前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >YAML 快速上手

YAML 快速上手

作者头像
恋喵大鲤鱼
发布2024-06-17 09:28:44
1360
发布2024-06-17 09:28:44
举报
文章被收录于专栏:C/C++基础C/C++基础
YAML(YAML Ain’t a Markup Language)是专门用来写配置文件的语言,简洁强大,相比于 JSON 和 XML,更加便于开发人员读写。

YAML 配置文件后缀为.yml 或 .yaml。

1.语法

YAML 的基本语法规则如下:

  • 数据结构采用键值对的形式 key: value。
  • 键冒号后面要加空格(一般为 1 个空格)。
  • 字母大小写敏感。
  • 使用缩进表示层级关系。
  • 缩进只允许使用空格,不允许使用 Tab 键。
  • 缩进空格数可以任意,只要相同层级的元素左侧对齐即可。
  • 字符串值一般不使用引号,必要时可使用。使用双引号表示字符串时,会转义字符串中的特殊字符(例如\n)。使用单引号时不会转义字符串中的特殊字符。
  • 数组中的每个元素单独一行,并以 - 开头。或使用方括号,元素用逗号隔开。注意短横杆和逗号后面都要有空格。
  • 对象中的每个成员单独一行,使用键值对形式。或者使用大括号并用逗号分开。
  • 文档以三个连字符---表示开始,以三个点号...表示结束,二者都是可选的。
  • 文档前面可能会有指令,在这种情况下,需要使用---来表示指令的结束。指令是一个%后跟一个标识符和一些形参。
  • 目前只有两个指令:%YAML指定文档的 YAML 版本,%TAG用于 tag 简写。二者都很少使用。
  • #表示注释,从这个字符一直到行尾,都会被解析器忽略。

2.历史版本

版本

发布日期

YAML 1.0

29 January 2004

YAML 1.1

18 January 2005

YAML 1.2.0

21 July 2009

YAML 1.2.1

1 October 2009

YAML 1.2.2

1 October 2021

3.数据结构

YAML 支持的数据结构有三种:

  • 对象:键值对的集合,又称为映射(mapping)、散列(hashes)、字典(dictionary)。
  • 数组:一组按次序排列的值,又称为序列(sequence)、列表(list)。
  • 标量:单个不可再分的值

下面分别介绍这三种数据结构。

对象

对象的一组键值对,使用冒号结构表示。

代码语言:javascript
复制
name: Steve

YAML 也允许另一种写法,将所有键值对写成一个行内对象。

代码语言:javascript
复制
who: { name: Steve, age: 18 }

当然,如果对象元素太多一行放不下,那么可以换行。

代码语言:javascript
复制
who:
  name: Steve
  age: 18

数组

一组以连字符开头的行,构成一个数组。注意,连字符后需添加空格。

代码语言:javascript
复制
animals:
  - Cat
  - Dog
  - Goldfish

连字符前可以没有缩进,也就是说下面这种写法也是 OK 的,但是还是建议缩进,因为更加易读。

代码语言:javascript
复制
animals:
- Cat
- Dog
- Goldfish

数组也可以采用行内表示法。

代码语言:javascript
复制
animal: [Cat,Dog,Goldfish]

如果数组元素是一个数组,则可以在连字符下面再缩进输入一个数组。

代码语言:javascript
复制
animals:
  -
    - Cat
    - Dog
  -
    - Fish
    - Goldfish

如果是行内表示,则为:

代码语言:javascript
复制
animals: [[Cat,Dog],[Fish,Goldfish]]

如果数组元素是一个对象,可以写作:

代码语言:javascript
复制
animals:
  - species: dog
    name: foo
  - species: cat
    name: bar

对应的 JSON 为:

代码语言:javascript
复制
{
    "animals": [
        {
            "species": "dog",
            "name": "foo"
        },
        {
            "species": "cat",
            "name": "bar"
        }
    ]
}

复合结构

对象和数组可以结合使用,形成复合结构。

代码语言:javascript
复制
languages:
 - Ruby
 - Perl
 - Python 
websites:
 YAML: yaml.org 
 Ruby: ruby-lang.org 
 Python: python.org 
 Perl: use.perl.org 

对应的 JSON 表示如下:

代码语言:javascript
复制
{
  "languages": [
    "Ruby",
    "Perl",
    "Python"
  ],
  "websites": {
    "YAML": "yaml.org",
    "Ruby": "ruby-lang.org",
    "Python": "python.org",
    "Perl": "use.perl.org"
  }
}

标量

标量是最基本、不可再分的值。有以下 7 种:

  • 字符串
  • 布尔值
  • 整数
  • 浮点数
  • Null
  • 时间
  • 日期

使用一个例子来快速了解标量的基本使用:

代码语言:javascript
复制
boolean: 
    - TRUE	# true、True 都可以
    - FALSE	# false、False 都可以
float:
    - 3.14			# 数值直接以字面量的形式表示
    - 6.8523015e+5	# 可以使用科学计数法
int:
    - 123							# 数值直接以字面量的形式表示
    - 0b1010_0111_0100_1010_1110	# 二进制表示
null:
    nodeName: 'node'
    parent: ~  		 # 使用~表示 null
string:
    - hello			 # 字符串默认不使用引号
    - "Hello world"  # 使用双引号或单引号包裹含有空格或特殊字符(如冒号)的字符串
    - newline
      newline1		 # 字符串可以拆成多行,每一换行符会被转化成一个空格
date:
    - 2018-02-17     # 日期必须使用 ISO 8601 格式,即 yyyy-MM-dd
datetime:
    - 2018-02-17T15:02:31+08:00    # 时间使用 ISO 8601 格式,时间和日期之间使用 T 连接,+08:00 表示时区

YAML 字符串有三种表示方式:

  • 无引号
  • 双引号
  • 单引号

字符串默认不需要引号,但是如果字符串包含空格或特殊字符(如冒号),需要加引号。

双引号字符串允许在字符串中使用转义序列来表示特殊字符,例如 \n 表示换行,\t 表示制表符,以及 \" 表示双引号。

单引号字符串被视为纯粹的字面字符串,不支持转义序列。

如果字符串含有单引号,可以使用双引号包裹,反之亦然。

4.引用

锚点 & 和别名 *,可以用来完成引用。

代码语言:javascript
复制
defaults: &defaults
  adapter:  postgres
  host:     localhost

development:
  database: myapp_development
  <<: *defaults

等同于下面的配置。

代码语言:javascript
复制
defaults:
  adapter:  postgres
  host:     localhost

development:
  database: myapp_development
  adapter:  postgres
  host:     localhost

& 用来建立锚点(defaults),<< 表示合并到当前数据,* 用来引用锚点。

5.文本块

如果想引入多行的文本块,可以使用 ||+|->>+>-

  • |

当内容换行时,保留换行符。

如果最后一行有多个换行符,只保留一个换行符。

代码语言:javascript
复制
linefeed1: |
  some
  text
linefeed2: |
  some
  text
  
linefeed3: |
  some

  text

对应的 JSON 为:

代码语言:javascript
复制
{
    "linefeed1": "some\ntext\n",
    "linefeed2": "some\ntext\n",
    "linefeed3": "some\n\ntext\n"
}
  • |+

当内容换行时,保留换行符。

与 | 的区别是,如果最后一行有多个换行符,则保留实际数目。

代码语言:javascript
复制
linefeed1: |+
  some
  text
linefeed2: |+
  some
  text
  
linefeed3: |+
  some

  text

对应的 JSON 为:

代码语言:javascript
复制
{
    "linefeed1": "some\ntext\n",
    "linefeed2": "some\ntext\n\n",
    "linefeed3": "some\n\ntext\n"
}
  • |-

当内容换行时,保留换行符,但最后的换行符不保留。

代码语言:javascript
复制
linefeed1: |-
  some
  text
linefeed2: |-
  some
  text
  
linefeed3: |-
  some

  text

对应的 JSON 为:

代码语言:javascript
复制
{
    "linefeed1": "some\ntext",
    "linefeed2": "some\ntext",
    "linefeed3": "some\n\ntext"
}
  • >

当内容换行时,替换为空格,但保留最后一行的换行符。

如果最后一行有多个换行符,只保留一个换行符。

代码语言:javascript
复制
linefeed1: >
  some
  text
linefeed2: >
  some
  text
  
linefeed3: >
  some

  text

对应的 JSON 为:

代码语言:javascript
复制
{
    "linefeed1": "some text\n",
    "linefeed2": "some text\n",
    "linefeed3": "some\ntext\n"
}
  • >+

当内容换行时,替换为空格,但保留最后一行的换行符。

与 > 的区别是,如果最后一行有多个换行符,则保留实际数目。

代码语言:javascript
复制
linefeed1: >+
  some
  text
linefeed2: >+
  some
  text
  
linefeed3: >+
  some

  text

对应的 JSON 为:

代码语言:javascript
复制
{
    "linefeed1": "some text\n",
    "linefeed2": "some text\n\n",
    "linefeed3": "some\ntext\n"
}
  • >-(缺省行为)

当内容换行时,替换为空格,不保留最后一行的换行符。

代码语言:javascript
复制
linefeed1: >-
  some
  text
linefeed2: >-
  some
  text
  
linefeed3: >-
  some

  text

对应的 JSON 为:

代码语言:javascript
复制
{
    "linefeed1": "some text",
    "linefeed2": "some text",
    "linefeed3": "some\ntext"
}

注意:以上 6 个特殊字符,|->- 用得最多。

6.显示指定类型

有时需要显示指定某些值的类型,可以使用 !(感叹号)显式指定类型。

! 单叹号通常是自定义类型,!! 双叹号是内置类型。

代码语言:javascript
复制
# !!str 指定为字符串
string.value: !!str HelloWorld!
# !!timestamp 指定为日期时间类型
datetime.value: !!timestamp 2021-04-13T02:31:00+08:00

内置的类型如下:

代码语言:javascript
复制
!!int:整数类型
!!float:浮点类型
!!bool:布尔类型
!!str:字符串类型
!!binary:二进制类型
!!timestamp:日期时间类型
!!null:空值
!!set:集合类型
!!omap,!!pairs:键值列表或对象列表
!!seq:序列
!!map:散列表类型

7.单文件多文档

一个 yaml 文件可以包含多个 yaml 文档,使用三个连字符---分隔。

代码语言:javascript
复制
a: 10
b: 
	- 1
	- 2
	- 3
---
a: 20
b: 
	- 4
	- 5 

这种情况在 K8S 和 SpringBoot 中非常常见。

比如 SpringBoot 在一个 application.yml 文件中,通过 — 分隔多个不同配置,根据 spring.profiles.active 的值来决定启用哪个配置。

代码语言:javascript
复制
# 公共配置
spring:
  profiles:
    active: prod #使用名为 prod 的配置,这里可以切换成 dev。
  datasource:
    url: jdbc:mysql://localhost:3306/test_db?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
    password: 123456
    username: root
---
# 开发环境配置
spring:
  profiles: dev #profiles属性代表配置的名称。

server:
  port: 8080
---
# 生产环境配置
spring:
  profiles: prod

server:
  port: 80

8.解析

下面以 YAML 表示一个简单的后台服务配置:

代码语言:javascript
复制
name: UserProfileServer
maxconns: 1000
queuecap: 10000
queuetimeout: 300
loginfo:
  loglevel: ERROR
  logsize: 10M
  lognum: 10
  logpath: /usr/local/app/log

下面以 Go 语言为例,解析上面的 YAML 配置。

因为 Go 官方并没有提供解析 YAML 的标准库,所以这里基于第三方开源库 go-yaml 来完成对 YAML 文件的解析。

第一步,将 YAML 配置文件的内容在 Convert YAML to Go struct 转换为 Go struct。

代码语言:javascript
复制
type Server struct {
	Name         string `yaml:"name"`
	Maxconns     int    `yaml:"maxconns"`
	Queuecap     int    `yaml:"queuecap"`
	Queuetimeout int    `yaml:"queuetimeout"`
	Loginfo      struct {
		Loglevel string `yaml:"loglevel"`
		Logsize  string `yaml:"logsize"`
		Lognum   int    `yaml:"lognum"`
		Logpath  string `yaml:"logpath"`
	} `yaml:"loginfo"`
}

第二步,利用第三方开源库 go-yaml 来完成对 YAML 文件的解析。

代码语言:javascript
复制
package main

import(
	"io/ioutil"
	"fmt"
	"os"	

	yaml "gopkg.in/yaml.v3"
)

func main() {
  file, err := os.Open("server.yaml")
  if err != nil {
    fmt.Printf("error:%v\n", err)
    return
  }
  defer file.Close()

  data, err := ioutil.ReadAll(file)
  if err != nil {
    fmt.Printf("error:%v\n", err)
    return
  }
  v := Server{}
  err = yaml.Unmarshal(data, &v)
  if err != nil {
    fmt.Printf("error:%v\n", err)
    return
  }
  fmt.Printf("%+v\n", v)
}

运行输出:

代码语言:javascript
复制
{Name:UserProfileServer Maxconns:1000 Queuecap:10000 Queuetimeout:300 Loginfo:{Loglevel:ERROR Logsize:10M Lognum:10 Logpath:/usr/local/app/log}}

9.完整示例

代码语言:javascript
复制
%YAML 1.2
---
receipt:     Oz-Ware Purchase Invoice
date:        2012-08-06
customer:
    given:   Dorothy
    family:  Gale
   
items:
    - part_no:   A4786
      descrip:   Water Bucket (Filled)
      price:     1.47
      quantity:  4

    - part_no:   E1628
      descrip:   High Heeled "Ruby" Slippers
      size:      8
      price:     133.7
      quantity:  1

bill-to:  &id001
    street: | 
            123 Tornado Alley
            Suite 16
    city:   East Centerville
    state:  KS

ship-to:  *id001   

specialDelivery:  >
    Follow the Yellow Brick
    Road to the Emerald City.
    Pay no attention to the
    man behind the curtain.
...

注意在 YAML 中,字符串不一定要用双引号标示。另外,在缩进中空白字符的数目并不是非常重要,只要相同层次结构的元素左侧对齐就可以了(不过不能使用 TAB 字符)。

%YAML 1.2 表示版本。

这个文件的顶层由七个键值组成:其中一个键值"items",是两个元素构成的数组(或称清单),这数组中的两个元素同时也是包含了四个键值的散列表。

文件中重复的部分用这个方法处理:使用锚点(&)和引用(*)标签将"bill-to"散列表的内容复制到"ship-to"散列表。也可以在文件中加入选择性的空行,以增加可读性。

在一个文件中,可同时包含多个文件,并用---分隔。选择性的符号...可以用来表示文件结尾(在流通信中,这非常有用,可以在不关闭流的情况下,发送结束信号)。


参考文献

The Official YAML Web Site Convert YAML to JSON go-yaml - Github Convert YAML to Go struct YAML 详解与实战-CSDN YAML - 维基百科,自由的百科全书 Brief YAML reference — Camel 0.1.2 documentation

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-06-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • YAML(YAML Ain’t a Markup Language)是专门用来写配置文件的语言,简洁强大,相比于 JSON 和 XML,更加便于开发人员读写。
  • 1.语法
  • 2.历史版本
  • 3.数据结构
    • 对象
      • 数组
        • 复合结构
          • 标量
          • 4.引用
          • 5.文本块
          • 6.显示指定类型
          • 7.单文件多文档
          • 8.解析
          • 9.完整示例
          • 参考文献
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档