YAML - 简介

1. YAML基础

1.1. 概述

Yaml是一个可读性高,用来表达数据序列的格式,有17年历史

YAML是"YAML Ain’t a Markup Language”(不是一个标记语言)的缩写,强调这种语言以数据做为中心,而不是以标记语言为重点

1.2. 特点

  • YAML使用空白字符和分行来分隔数据,缩进中空白字符的数目并不是非常重要,只要相同层次结构的元素左侧对齐就可以了(不过不能使用TAB字符)
  • 可以简单表达清单、散列表,标量等数据形态
  • 比较适合用来表达层次结构式(hierarchical model)的数据结构,不过也有精致的语法可以表示关系性(relational model)的数据

1.3. 基本语法

---
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.
...

1.4. 语法说明

  • 缩进中空白字符的数目并不是非常重要,只要相同层次结构的元素左侧对齐就可以了(不能使用TAB字符)
  • YAML使用可打印的Unicode字符,可使用UTF-8或UTF-16
  • YAML在使用逗号及冒号时,后面都必须接一个空白字符
  • 注解由井字号( # )开始,可以出现在一行中的任何位置,而且范围只有一行(也就是一般所谓的单行注解)
  • 字符串平常并不使用引号,但必要的时候可以用双引号 ( " )或单引号 ( ' )框住
    • 倒斜线(\ )开始的转义字符,表示特殊字符。
  • 支持数组、散列表
    • 每个清单成员以单行表示,并用短杠+空白( - )起始。或使用方括号( [ ] ),并用逗号+空白(, )分开成员。
    • 每个散列表的成员用冒号+空白( : )分开键值和内容。或使用大括号( { } ),并用逗号+空白(, )分开。
  • 区块的字符串用缩进和修饰符(非必要)来和其他数据分隔
    • 新行保留(preserve)(使用符号 |
    • 新行折叠(flod)(使用符号 > )两种方式
  • 指定格式可以使用两个惊叹号 ( !! ),后面接上名称
  • 重复的部分用这个方法处理:使用锚点(&)和引用(*)标签
    • 重复的内容可使从参考标记星号 ( *)复制到锚点标记( &
  • 在单一文件中
    • 可用连续三个连字号(---)区分多个文件
    • 有选择性的连续三个点号( ... )用来表示文件结尾
  • 可以在文件中加入选择性的空行,以增加可读性
  • 文件中的单一文件可以使用指导指令,使用方法是百分比符号( % )
  • 另外还有两个特殊符号在YAML中被保留,有可能在未来的版本被使用–( @ )和( ` )。

2. YAML构成元素

2.1. 数组清单

  • 区块格式:短杠+空白字符作为起始
  • 内置格式:逗号+空白区隔
--- # 最喜愛的電影
- Casablanca
- North by Northwest

--- # 購物清單 
[milk, pumpkin pie, eggs, juice]

2.2. 散列表

  • 区块形式(常使用与YAML数据文档中)使用缩进和换行符分隔key: value对。
  • 内置形式(常使用与YAML数据流中)在大括号中使用逗号+空白字符分隔key: value对
--- # 區塊形式
name: John Smith
age: 33

--- # 內置形式
{name: John Smith, age: 33}

2.3. 字符串以及区块字符

字符串不需要包在引号之内,多行字符书写方式:

  • 保存新行(使用|字符),前方的引领空白符号(leading white space)必须排成条状
  • 折叠新行(使用>字符),引领空白字符则会被自动消去,换行字符会被转换成空白字符
data: |                                     # 譯者注:這是一首著名的五行民謠(limerick)
   There once was a man from Darjeeling     # 這裡曾有一個人來自大吉嶺
   Who got on a bus bound for Ealing        # 他搭上一班往伊靈的公車
       It said on the door                  # 門上這麼說的
       "Please don't spit on the floor"     # "請勿在地上吐痰"
   So he carefully spat on the ceiling      # 所以他小心翼翼的吐在天花板上

data: >
   Wrapped text         # 摺疊的文字
   will be folded       # 將會被收
   into a single        # 進單一一個
   paragraph            # 段落
   
   Blank lines denote   # 空白的行代表
   paragraph breaks     # 段落之間的區隔

2.4. 层次化结构

// 在清单中使用散列表
- {name: John Smith, age: 33}
- name: Mary Smith
  age: 27

// 在散列表中使用清单
men: [John Smith, Bill Jones]
women:
  - Mary Smith
  - Susan Williams

2.5. 引用

YAML最常被提到的特色有两个:关系树数据形态

2.6. 数据合并和引用

YAML提供了结点参考(*)和散列合并(<<)引用到其他结点标签的锚点标记(&

  • 定义锚点,&锚点名称
  • 引用锚点,*锚点名称
  • 引用锚点,进行数据合并,<< *锚点名称
// 眼部雷射手術之標準程序
---
- step:  &id001                  # 定義錨點標籤 &id001
    instrument:      Lasik 2000
    pulseEnergy:     5.4
    pulseDuration:   12
    repetition:      1000
    spotSize:        1mm
- step:
     <<: *id001                  # 合併鍵值:使用在錨點標籤定義的內容
     spotSize:       2mm         # 覆寫"spotSize"鍵值
- step:
     <<: *id001                  # 合併鍵值:使用在錨點標籤定義的內容
     pulseEnergy:    500.0       # 覆寫鍵值
     alert: >                    # 加入其他鍵值
           warn patient of 
           audible pop

2.7. YAML常见数据类型

YAML数据类型有三大类:原码(core),定义(defined),用户定义(user-defined):

  • 原码可以自动被解析器分析(例如:浮点数,整数,字符串,清单,映射,…)
  • 高级的数据形态──例如比特数据(在YAML中有被“定义”,但不是每一种解析器都有支持)
  • YAML支持用户自定的区域变量,包括:自定义的类别,结构或基本类型

强制类型转换:

有时用户会想要将数据强制转型成自定的某种类型。最常见的状况是字符串,有时候可能看起来像数字或布尔值。

---
a: 123                     # 整數
b: "123"                   # 字串(使用雙括號)
c: 123.0                   # 浮點數
d: !!float 123             # 浮點數,使用!!表達的嚴格型態
e: !!str 123               # 字串,使用嚴格型態
f: !!str Yes               # 字串,使用嚴格型態
g: Yes                     # 布林值"真"
h: Yes we have No bananas  # 字串(包含"Yes"和"No")

2.8. 其他不常见的数据类型

除了一般的数据形态之外,用户也可以使用一些较为高级的类型,但不保证可被每种解析器分析。使用时和强制转型类似,要在形态名称之前加上两个惊叹号(!!)。

不常见的数据类型有:

  • 集合(sets)
  • 有序映照(ordered maps)
  • 时间戳记(timestamps)
  • 十六进制数据(hexadecimal)
  • 比特数据(binary)
// 比特数据(binary)
---
picture: !!binary |
 R0lGODlhDAAMAIQAAP//9/X
 17unp5WZmZgAAAOfn515eXv
 Pz7Y6OjuDg4J+fn5OTk6enp
 56enmleECcgggoBADs=mZmE

2.9. 用户自定义的数据类型

将一个对象序列化时,这个方法还颇方便的,这种数据形态用惊叹号( ! )表示

---
myObject:  !myClass{name: Joe, age: 15}

3. YAML和其他数据格式的差别

与JSON、XML格式对比

  • JSON,是YAML1.2的子集,YAML的许多扩展在JSON是找不到的,如:高级数据形态、关系锚点、字符串不需要双引号、映射数据形态会存储键值的顺序。
  • XML和SDL标签概念,在YAML中是找不到的。
  • YAML的数据形态不依赖引号之特点,使的YAML文件可以利用区块,轻易的插入各种其他类型文件,如:XML、SDL、JSON,相反的,要将YAML置入XML或SDL中时,需要将所有空白字符和位势符号(potential sigils,如:<,>和&)转换成实体语法;要将YAML置入JSON中,需要用引号框住,并转换内部的所有引号。
  • YAML提供了一个简单的关系引用,重复相同的数据,而不必显示那些冗余的结构
  • YAML极深的缩进可以完全避免的是:
    • (1)使用“内置格式”(即简称类JSON格式)而无缩进;
    • (2)使用关系锚点展开层次结构以形成一个摊平的格式,使得YAML解析器能透明地重组成完整的数据结构。
  • 安全方面
    • YAML是纯粹用来表达数据的语言,所以内部不会存代码注射的可执行命令
    • JSON是JavaScript的子集,因此可能有人想使用JavaScript本身的剖析器直接eval,不过这样一来容易造成许多代码注射的漏洞

3.1. 参考

  • 官档:https://yaml.org/spec/1.2/spec.html#id2761803
  • 参考:https://zh.wikipedia.org/wiki/YAML
  • Y分钟学习:https://learnxinyminutes.com/docs/zh-cn/yaml-cn/