YAML
YAML(/ˈjæməl/)是一个可读性高,用来表达数据串行化的格式。YAML参考了其他多种语言,包括:C语言、Python、Perl,并从XML、电子邮件的数据格式(RFC 2822[1])中获得灵感。Clark Evans在2001年首次发表了这种语言[2],另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者[3]。目前已经有数种编程语言或脚本语言支持(或者说解析)这种语言。
![]() | |
.yaml, .yml | |
尚未注册 | |
首次发布 | 2001年5月11日 |
最新版本 | 1.2 (Revision 1.2.2) 2021年10月1日 |
格式类型 | 数据交换 |
免费格式? | 是 |
网站 | yaml |
YAML是"YAML Ain't a Markup Language"(YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)[4],但为了强调这种语言以数据为中心,而不是以标记语言为重点,而用反向缩略语重命名。
功能
YAML的语法和其他高端语言类似,并且可以简单表达清单、散列表,纯量等数据形态。[5]它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种设置档、倾印调试内容、文档大纲(例如:许多电子邮件标题格式和YAML非常接近)。尽管它比较适合用来表达阶层式(hierarchical model)的数据结构,不过也有精致的语法可以表示关联性(relational model)的数据。[6]由于YAML使用空白字符和分行来分隔数据,使得它特别适合用grep/Python/Perl/Ruby操作。其让人最容易上手的特色是巧妙避开各种封闭符号,如:引号、各种括号等,这些符号在嵌套结构时会变得复杂而难以辨认。
范例
简单的文档
数据结构可以用类似大纲的缩进方式呈现
---
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字符)。这个文档的顶层由七个键值组成:其中一个键值"items",是两个元素构成的数组(或称清单),这清单中的两个元素同时也是包含了四个键值的哈希表。文档中重复的部分用这个方法处理:使用锚点(&)和引用(*)标签将"bill-to"哈希表的内容拷贝到"ship-to"哈希表。也可以在文档中加入选择性的空行,以增加可读性。在一个文件中,可同时包含多个文档,并用"---
"分隔。选择性的符号"...
"可以用来表示文件结尾(在利用串流的通信中,这非常有用,可以在不关闭串流的情况下,发送结束信号)。
语言的构成元素
YAML的基本组件
YAML提供缩进/区块以及内置(inline)两种格式,来表示清单和哈希表。以下展示几种YAML的基本组件。
清单(数组)
习惯上清单比较常用区块格式(block format)表示,也就是用短杠+空白字符作为起始。
--- # 最喜爱的电影
- Casablanca
- North by Northwest
- Notorious
另外还有一种内置格式(inline format)可以选择──用方括号围住,并用逗号+空白区隔(类似JSON的语法)。[7]
--- # 购物清单
[milk, pumpkin pie, eggs, juice]
关联数组
键值和数据由冒号及空白字符分开。区块形式(常使用于YAML数据文档中)使用缩进和换行符分隔key: value对。内置形式(常使用于YAML数据串流中)在大括号中使用逗号+空白字符分隔key: value对。
--- # 区块形式
name: John Smith
age: 33
--- # 内置形式
{name: John Smith, age: 33}
区块的字符
再次强调,字符串不需要包在引号之内。
有两种语法可以书写多行文本(multi-line strings),一种为保留换行(使用|
字符),另一种为折叠换行(使用>
字符)。两种语法在其特殊字符之后都必须接着换行。
保留换行(Newlines preserved)
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 # 所以他小心翼翼的吐在天花板上
根据缺省,每行开头的缩进(以首行为基准)和行末空白会被去除,而不同的缩进会保留差异。
折叠换行(Newlines folded)
data: >
Wrapped text # 折叠的文本
will be folded # 将会被收
into a single # 进单一一个
paragraph # 段落
Blank lines denote # 空白的行代表
paragraph breaks # 段落之间的区隔
和保留换行不同的是,只有空白行才视为换行,原本的换行字符会被转换成空白字符,而行首缩进会被去除。
于清单中使用哈希表
- {name: John Smith, age: 33}
- name: Mary Smith
age: 27
于哈希表中使用清单
men: [John Smith, Bill Jones]
women:
- Mary Smith
- Susan Williams
YAML的高端组件
这部分算是一个后续的讨论,在比较各种数数据列语言时,YAML最常被提到的特色有两个:关系树和数据形态。
数据合并和参考
为了维持文档的简洁,并避免数据输入的错误,YAML提供了节点参考(*)和哈希合并(<<)参考到其他节点标签的锚点标记(&)。参考会将树状结构加入锚点标记的内容,并可以在所有数据结构中运作(可以参考上面"ship-to"的范例)合并只有哈希表可以使用,可以将键值自锚点标记拷贝到指定的哈希表中。
当数据被instantiate合并和参考会被剖析器自动展开。
#眼部雷射手术之标准进程
---
- 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
数据形态
由于自动判定数据形态的功能,严格型态(也就是用户有声明的数据形态)很难在大部分的YAML文档中看到。数据型态可以被区分成三大类:原码(core),定义(defined),用户定义(user-defined)。原码可以自动被解析器分析(例如:浮点数,整数,字符串,清单,映射,...)。有一些高端的数据形态──例如比特数据──在YAML中有被「定义」,但不是每一种解析器都有支持。最后,YAML支持用户自定的区域变量,包括:自订的类别,结构或基本型态(例如:四倍精度的浮点数)。
强迫转型
YAML的自动判定数据形态是哪一种实体。但有时用户会想要将数据强迫转型成自定的某种型态。最常见的状况是字符串,有时候可能看起来像数字或布尔值,这种时候可以使用双引号,或是使用严格型态标签。
---
a: 123 # 整数
b: "123" # 字符串(使用双引号)
c: 123.0 # 浮点数
d: !!float 123 # 浮点数,使用!!表达的严格型态
e: !!str 123 # 字符串,使用严格型态
f: !!str Yes # 字符串,使用严格型态
g: Yes # 布尔值"真"(yaml1.1)或字符串"Yes"(yaml1.2)
h: Yes we have No bananas # 字符串(包含"Yes"和"No")
其他特殊数据形态
除了一般的数据形态之外,用户也可以使用一些较为高端的型态,但不保证可被每种解析器分析。使用时和强迫转型类似,要在形态名称之前加上两个惊叹号(!!)。有几种重要的形态在本篇没有讨论,包括集合(sets),有序映照(ordered maps),时间戳记(timestamps)以及十六进位数据(hexadecimal)。下面这个范例则是比特数据(binary)
---
picture: !!binary |
R0lGODdhDQAIAIAAAAAAANn
Z2SwAAAAADQAIAAACF4SDGQ
ar3xxbJ9p0qa7R0YxwzaFME
1IAADs=
用户自行扩充的数据形态
许多YAML的实现允许用户自订数据形态。在将一个对象串行化时,这个方法还颇方便的。某些区域数据形态可能不存在缺省的数据形态中,不过这种型态在特定的YAML应用程序中是有定义的。这种区域数据形态用惊叹号( !
)表示。
---
myObject: !myClass { name: Joe, age: 15}
语法
在yaml.org[8](英文)可以找到轻巧而好用的小抄[9](亦是用YAML表示)及格式说明[10]。下面的内容,是关于基本组件的摘要。
- YAML使用可打印的Unicode字符,可使用UTF-8或UTF-16。
- 使用空白字符为文档缩进来表示结构;不过不能使用跳格字符(TAB)。
- 注解由井字号( # )开始,可以出现在一行中的任何位置,而且范围只有一行(也就是一般所谓的单行注解)
- 每个清单成员以单行表示,并用短杠+空白( - )起始。或使用方括号( [ ] ),并用逗号+空白( , )分开成员。
- 每个哈希表的成员用冒号+空白( : )分开键值和内容。或使用大括号( { } ),并用逗号+空白( , )分开。
- 哈希表的键值可以用问号 ( ? )起始,用来明确的表示多个词汇组成的键值。
- 字符串平常并不使用引号,但必要的时候可以用双引号 ( " )或单引号 ( ' )框住。
- 使用双引号表示字符串时,可用倒斜线( \ )开始的转义字符(这跟C语言类似)表示特殊字符。
- 区块的字符串用缩进和修饰词(非必要)来和其他数据分隔,有新行保留(preserve)(使用符号 | )或新行折叠(flod)(使用符号 > )两种方式。
- 在单一文件中,可用连续三个连字号(---)区分多个文件。
- 另外,还有选择性的连续三个点号( ... )用来表示文件结尾。
- 重复的内容可使从参考标记星号 ( * )拷贝到锚点标记( & )。
- 指定格式可以使用两个惊叹号 ( !! ),后面接上名称。
- 文件中的单一文档可以使用指导指令,使用方法是百分比符号( % )。有两个指导指令在YAML1.1版中被定义:
- %YAML 指导指令,用来识别文档的YAML版本。
- %TAG 指导指令,被用在URI的前缀标记。这个方法在标记节点的型态时相当有用。
YAML在使用逗号及冒号时,后面都必须接一个空白字符,所以可以在字符串或数值中自由加入分隔符号(例如:5,280或http://www.wikipedia.org)而不需要使用引号。
另外还有两个特殊符号在YAML中被保留,有可能在未来的版本被使用--( @ )和( ` )。
与其他数据串行化格式比较
虽然YAML是参考JSON,XML和SDL等语言,不过跟这些语言比起来,YAML仍有自己的特色。
JSON
JSON的语法是YAML1.2版的子集[11],,同时非常接近[12] YAML1.0与1.1版的子集,因此大部分的JSON文档都可以被YAML的剖析器剖析。[13]这是因为JSON的语法结构和YAML的内置格式相同。虽然大范围的分层也可以使用类似JSON的内置格式,不过YAML标准并不建议这样使用,除非这样编写能让文档可读性增加。YAML的许多扩展在JSON是找不到的,如:高端数据形态、关系锚点、字符串不需要双引号、映射数据形态会保存键值的顺序。
XML和SDL
XML和SDL标签概念,在YAML中是找不到的。对于数据结构串行(尽管这是有争议的),标签属性的特色就是可以将数据及复杂数据附加信息分离,并将各种原生数据结构(如:哈希表、数组)用同一种语言表示。YAML则以数据的可扩展性作为替代。(包括为了仿真对象的类别型态)在YAML本身的规范中,并没有类似XML的语言定义文档刚要(language-defined document schema descriptors)──例如验证自己本身的结构是否正确的文档。不过,YAML纲要描述语言(YAML schema descriptor language)是存在[14]的。另外还有YAXML──用XML描述YAML的结构──可以让XML Schema与XSLT转换程序应用在YAML之上。况且,在一般使用的情况下,YAML丰富的定义型态之语法已经提供了足够的方式,来辨认YAML文档是否正确。
缩进划界
由于YAML的运作主要依赖大纲式的缩进来决定结构,这有效解决了界定符冲突(Delimiter collision)的问题。YAML的数据形态不依赖引号之特点,使的YAML文档可以利用区块,轻易的插入各种其他类型文档,如:XML、SDL、JSON,甚至插入另一篇YAML。
---
example: >
HTML goes into YAML without modification
message: |
<blockquote style="font: italic 12pt Times">
<p>"Three is always greater than two,
even for large values of two"</p>
<p>--Author Unknown</p>
</blockquote>
相反的,要将YAML置入XML或SDL中时,需要将所有空白字符和位势符号(potential sigils,如:<,>和&)转换成实体语法;要将YAML置入JSON中,需要用引号框住,并转换内部的所有引号。
非阶层式的数据模型
跟SDL、JSON等,每个子结点只能有单一一个父节点的阶层式模型不同,YAML提供了一个简单的关系体制,可以从树状结构的其他地方,重复相同的数据,而不必显示那些冗余的结构。这点和XML中的IDRef类似[15]YAML剖析器在将YAML转换成对象时,会自动将那些参考数据的结构展开,所以程序在使用时并不会查觉到哪些数据是解码自这种结构。XML则不会将这种结构展开。这种表示法可以增加程序的可读性,并且,在那种『大部分参数维持和上次相同,只有少数改变』的设置档及通信协定中,可以减少数据输入错误。一个例子是:『送货地点』和『购买地点』在发票的纪录中几乎都是相同的数据。
实际的考量
YAML是「行导向的」,因此,就算想由现有进程的混乱输出,转换成YAML格式,并保留大部分的原始文档之外观,也非常简单。因为他不需要平衡封闭的标签、括弧及引号,可以从很简单的利用程序,从报表产生YAML。同样,空格分隔可让使用行导向的命令如:grep、Awk、perl、ruby,和Python,来应急性的过滤YAML文档时更加方便。
特别是与标记语言不同的,连续的YAML区块导向往往是格式良好的YAML文档本身。这使得很容易撰写那种「在开始提取的具体记录之前,不需要'读取全部文档内容'」的解析器(通常需要平衡起始和关闭标签、寻找引号和跳脱字符)。当处理一个单一静态的,整个存在内存中的数据结构将很大,或为提取一个项目来重建的整个结构,代价相当昂贵的记录档,这种特性是相当方便的。
值得讨论的是,尽管它的缩进方式似乎复杂化了深度很大的嵌套层次, YAML将缩进视为一个单一的空白,这可能会取得比其他标记语言更好的压缩比。此外,极深的缩进可以完全避免的是: (1)使用“内置格式”(即简称类JSON格式)而无缩进;或 (2)使用关联锚点展开阶层以形成一个摊平的格式,使得YAML解析器能透明地重组成完整的数据结构。
安全性
YAML是纯粹用来表达数据的语言,所以内部不会存代码注射的可运行命令。[16]这代表剖析器会相当(至少)安全的解析文档,而不用担心潜在与运行命令相关的安全漏洞。举例来说,JSON是JavaScript的子集,因此可能有人想使用JavaScript本身的剖析器直接eval,不过这样一来就造成许多代码注射的漏洞。虽然在所有数据串行语言中,安全解析本质上是可能的,但可运行性却正是这样一个恶名昭彰的缺陷;而YAML缺乏相关的命令语言,可能是一个相对安全的利益。
实作与函数库
移植性
简单的YAML文件(例如:简单的键值对)不需要完整的YAML剖析器,便可以被正则表达式解析。许多常用的编程语言──纯用某个语言,让函数库具有可携性──都有的YAML的产生器和剖析器。当性能比较重要时,也有许多和C语言绑定的函数库可使用。
C语言函数库
其他函数库
下面几种编程语言都有与YAML相关的函数库:
- C++
- 用C++将libYaml包装[23]
- Go
- go-yaml[24] 借鉴 C 库 libyaml 设计的 Go 语言移植。
- Haskell
- Haskell Reference wrappers[25]
- Java
- JavaScript
- 原生的JavaScript即可产生YAML,但不能解析。
- YAML JavaScript[28] 同时支持产生和解析。
- Objective-C
- Cocoa-Syck[29]
- OCaml
- OCaml-Syck[30]
- Lua
- Lua-Syck[31]
- Perl
- PHP
- Python
- Ruby(从1.8版开始,YAML解析器成为标准函数库之一。以SYCK为基础。)
- R
- CRAN YAML[42] 以SYCK为基础。
- .NET
- Scala
- scala-yaml[45]
- Tcl
- 在Tcl 8.4中可用[46]
- XML YAXML[47] (当前仍在设计中)
常见错误与使用细节
- 编辑器:
- 建议使用能将跳格字符自动转换成空白字符的编辑器,并且使用定宽度的字体。
- 编辑器要能正确的处理UTF-8和UTF16编码(或是使用纯ASCII编码──它同时是UTF-8的子集).
- 字符串:
- YAML的字符串不需使用引号,这可以增加可读性,并避免嵌套的转义字符。然而,这有时也会导致错误,例如,字符串本身是一个暧昧的字眼(像数字或布尔值);或在短句中意外的出现YAML的结构符号(常见的例子是由惊叹号起始的句子,或是包含冒号-空白的句子:"
!Caca de vaca!
"、"Caution: lions ahead
")。这在发布YAML文件时并不造成困扰,但在制作小型脚本和人工编辑文件时,这问题却会常常出现。比较好的方法是善用区块符号("|" or ">")而不要使用单行字符串,来避免这种暧昧的表示方法。
- YAML的字符串不需使用引号,这可以增加可读性,并避免嵌套的转义字符。然而,这有时也会导致错误,例如,字符串本身是一个暧昧的字眼(像数字或布尔值);或在短句中意外的出现YAML的结构符号(常见的例子是由惊叹号起始的句子,或是包含冒号-空白的句子:"
- 预期实做的特性
注释
- 2822 (页面存档备份,存于)
- Evans, Clark. . Yahoo! Tech groups(雅虎技术群组): sml-dev. 2001-05-11 [2008-08-02]. (原始内容存档于2013-09-07).
- . [2010-06-16]. (原始内容存档于2022-04-03).
- . [2008-11-24]. (原始内容存档于2022-03-06).
- 在英文原文中,将下列几组词汇交替使用:(清单"list"和数组"array"), (哈希表"hash"、字典"dictionary"、映射"mapping")和(字符串"string"和纯量"scalar")。在其他编程语言,这几组字的意义未必等价。中文则统一使用相同的词汇。
- 阶层式(hierarchical model)对应到树状结构时,只会有一个固定、整体性的结果。举例说明:用阶层式来表达电影的演员名单,每个演员都只能归类到一个电影名称;或是每个电影只能归类给一位演员(虽然这样很怪)。YAML同时也允许使用关联式数据(relational model)。
- . [2013-05-15]. (原始内容存档于2008-09-14).
- yaml.org (页面存档备份,存于)
- 小抄 (页面存档备份,存于)
- 格式说明 (页面存档备份,存于)
- . [2008-12-01]. (原始内容存档于2008-05-16).
- 这些语法非常细微且很少出现在文档中:JSON允许扩充字符集,如:UTF32;YAML在分隔符号──如引号、等号、冒号──后方需要接空白字符,而JSON不需要;一些非标准的JSON实现允许Javascript风格的的大范围注解/*...*/。处理这种边界情形或许需要在将其当成内置格式的YAML剖析前进行简单的JSON前处理。
- . [2008-09-28]. (原始内容存档于2008-09-14).
- 存在 (页面存档备份,存于)
- . [2008-09-28]. (原始内容存档于2022-05-15).
- 提案中的"yield"(迭代器)标签可以允许简单的算术运算
- . [2007-11-04]. (原始内容存档于2020-01-10).
- . [2007-11-04]. (原始内容存档于2021-04-19).
- . [2007-11-04]. (原始内容存档于2022-05-01).
- libYAML (页面存档备份,存于)
- YAML的创造者Clark Evans推荐
- SYCK (页面存档备份,存于)
- 用C++将libYaml包装
- go-yaml (页面存档备份,存于)
- Haskell Reference wrappers
- jvyaml
- JYaml
- YAML JavaScript (页面存档备份,存于)
- Cocoa-Syck
- OCaml-Syck (页面存档备份,存于)
- Lua-Syck
- CPAN YAML (页面存档备份,存于)
- YAML::Tiny (页面存档备份,存于)
- YAML::Syck (页面存档备份,存于)
- YAML::XS (页面存档备份,存于)
- Spyc
- PHP-Syck (页面存档备份,存于)
- sfYaml
- . [2008-09-28]. (原始内容存档于2008-09-17).
- . [2022-06-03]. (原始内容存档于2021-05-11).
- Ya2YAML
- CRAN YAML (页面存档备份,存于)
- YAML .NET Parser (页面存档备份,存于)
- . www.nuget.org. [2022-09-14]. (原始内容存档于2022-09-16) (英语).
- scala-yaml (页面存档备份,存于)
- 在Tcl 8.4中可用
- YAXML (页面存档备份,存于)
外部链接
- YAML.org (页面存档备份,存于)
- YAML Specification (页面存档备份,存于)
- YAML Cookbook--Equivalent data structures in YAML and Ruby
- YAML in Five Minutes (页面存档备份,存于)
- YAML improves on XML (页面存档备份,存于) Intro to YAML in Python
- YAML as a superset of JSON
- Kwalify Schema definition for YAML (页面存档备份,存于)
- Lists in 5 minutes (页面存档备份,存于)
- YAML Validator (页面存档备份,存于)