YAML是
“
另一种
标记语
言
”的外语缩写
[1]
(见前方参考资料原文内容);但为了强调这种语言以数据做为中心,而不是以置标语言为重点,而用
返璞词重新命名。它是一种直观的能够被电脑识别的数据序列化格式,是一个可读性高并且容易被人类阅读,容易和
脚本语言交互,用来表达资料序列的编程语言。
中文名
-
另一种标记语言
外文名
-
Yet Another Markup Language
中文
缩写
-
标言
外语
缩写
-
YAML
诞生
Clark Evans在2001年5月在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。
命名
YAML是"YAML Ain't a Markup Language"(YAML不是一种置标语言)的递归缩写。
在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种置标语言),
功能
YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表,标量等资料形态、。
它使用空白符号缩排和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种设定档、倾印除错内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。
尽管它比较适合用来表达阶层式(hierarchical model)的数据结构,不过也有精致的语法可以表示关联性(relational model)的资料。
由于YAML使用空白字符和分行来分隔资料,使的他特别适合用grep、Python、Perl、Ruby操作。
其让人最容易上手的特色是巧妙避开各种封闭符号,如:引号、各种括号等,这些符号在嵌套结构中会变得复杂而难以辨认。
多行缩进
数据结构可以用类似大纲的缩排方式呈现,结构通过缩进来表示,连续的项目通过减号“-”来表示,map结构里面的key/value对用冒号“:”来分隔。样例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
house:
family:
name: Doe
parents:
- John
- Jane
children:
- Paul
- Mark
- Simone
address:
number: 34
street: Main Street
city: Nowheretown
zipcode: 12345
|
注意:
-
字串不一定要用双引号标识;
-
在缩排中空白字符的数目并不是非常重要,只要相同阶层的元素左侧对齐就可以了(不过不能使用TAB字符);
-
允许在文件中加入选择性的空行,以增加可读性;
-
在一个档案中,可同时包含多个文件,并用“——”分隔;
-
选择性的符号“...”可以用来表示档案结尾(在利用串流的通讯中,这非常有用,可以在不关闭串流的情况下,发送结束讯号)。
单行缩写
YAML也有用来描述好几行相同结构的数据的缩写语法,数组用'[]'包括起来,hash用'{}'来包括。因此,上面的这个YAML能够缩写成这样:
1
2
3
|
house:
family: { name: Doe, parents: [John, Jane], children: [Paul, Mark, Simone] }
address: { number:
34
, street: Main Street, city: Nowheretown, zipcode:
12345
}
|
脚本语言
由于实现简单,解析成本很低,YAML特别适合在
脚本语言中使用。列一下现有的语言实现:Ruby,Java,Perl,Python,PHP,OCaml,JavaScript,除了Java,其他都是脚本语言。
序列化
YAML比较适合做序列化。因为它是
宿主语言数据类型直转的。
配置文件
YAML做配置文件也不错。写YAML要比写XML快得多(无需关注标签或引号),并且比ini文档功能更强。
比如Ruby on Rails的配置就选用的YAML。对ROR而言,这很自然,也很省事.
由于兼容性问题,不同语言间的数据流转建议不要用YAML.
虽然YAML是参考JSON,XML和SDL等语言,不过跟这些语言比起来,YAML仍有自己的特色。
JSON
JSON的语法是YAML1.2版的子集,同时非常接近YAML1.0与1.1版的子集,因此大部分的JSON文件都可以被YAML的剖析器剖析。这是因为JSON的语法结构和YAML的内置格式相同。虽然大范围的分层也可以使用类似JSON的内置格式,不过这并YAML标准并不建议这样使用,除非这样编写能让文件可读性增加。YAML的许多扩展在JSON是找不到的,如:进阶资料形态、关系锚点、字串不需要双引号、映射资料形态会储存键值的顺序。
XML和SDL
XML和SDL标签概念,在YAML中是找不到的。对于数据结构序列(尽管这是有争议的),标签属性的特色就是可以将资料及复杂资料附加资讯分离,并将各种原生数据结构(如:杂凑表、阵列)用同一种语言表示。YAML则以资料的可扩展性作为替代。(包括为了模拟物件的类别型态)在YAML本身的规范中,并没有类似XML的语言定义文件纲要(language-defined document schema descriptors)──例如验证自己本身的结构是否正确的文件。不过,YAML纲要描述语言(YAML schema descriptor language)是存在的。另外还有YAXML──用XML描述YAML的结构──可以让XML Schema与XSLT转换程式应用在YAML之上。况且,在一般使用的情况下,YAML丰富的定义型态之语法已经提供了足够的方式来辨认YAML文件是否正确。
缩排划界
由于YAML的运作主要依赖大纲式的缩排来决定结构,这有效解决了界定符冲突(Delimiter collision)的问题。YAML的资料形态不依赖引号之特点,使的YAML文件可以利用区块,轻易的插入各种其他类型文件,如:XML、SDL、JSON,甚至插入另一篇YAML。
相反的,要将YAML置入XML或SDL中时,需要将所有空白字符和位势符号(potential sigils,如:<,>和&)转换成实体语法;要将YAML置入JSON中,需要用引号框住,并转换内部的所有引号。
非阶层式的资料模型
跟SDL、JSON等,每个子结点只能有单一一个父节点的阶层式模型不同,YAML提供了一个简单的关系体制,可以从树状结构的其他地方,重复相同的资料,而不必显示那些冗余的结构。这点和XML中的IDRef类似,YAML剖析器在将YAML转换成物件时,会自动将那些参考资料的结构展开,所以程式在使用时并不会查觉到哪些资料是解码自这种结构。XML则不会将这种结构展开。这种表示法可以增加程式的可读性,并且,在那种“大部分参数维持和上次相同,只有少数改变”的设定档及通讯协定中,可以减少数据输入错误。一个例子是:“送货地点”和“购买地点”在发票的纪录中几乎都是相同的资料。
实际的考量
YAML是“行导向的”,因此,就算想由现有程序的混乱输出,转换成YAML格式,并保留大部分的原始文件之外观,也非常简单。因为他不需要平衡封闭的标签、括号及引号,可以从很简单的利用程式,从报表产生YAML。同样,空格分隔可让使用行导向的命令如:grep、Awk、perl、ruby,和Python,来应急性的过滤YAML文件时更加方便。
特别是与标记语言不同的,连续的YAML区块导向往往是格式良好的YAML文件本身。这使得很容易撰写那种“在开始提取的具体记录之前,不需要‘读取全部文件内容’”的解析器(通常需要平衡起始和关闭标签、寻找引号和跳脱字符)。当处理一个单一静态的,整个存在内存中的数据结构将很大,或为提取一个项目来重建的整个结构,代价相当昂贵的记录档,这种特性是相当方便的。
值得讨论的是,尽管它的缩排方式似乎复杂化了深度很大的巢状层次,YAML将缩排视为一个单一的空白,这可能会取得比其他标记语言更好的压缩比。此外,极深的缩排可以完全避免的是:
安全性
YAML是纯粹用来表达资料的语言,所以内部不会存
代码注入的可执行命令。这代表剖析器会相当(至少)安全的解析文件,而不用担心潜在与执行命令相关的安全漏洞。举例来说,JSON是JavaScript的子集,使用JavaScript本身的剖析器是相当诱人的,不过也造成许多代码注入的漏洞。虽然在所有资料序列语言中,安全解析本质上是可能的,但可执行性却正是这样一个恶名昭彰的缺陷;而YAML缺乏相关的命令语言,可能相对安全。
资料处理和呈现
XML和YAML规范提供非常不同的逻辑模型来进行资料结点的展现、处理及储存。
移植性
简单的YAML档案(例如:简单的键值对)不需要完整的YAML剖析器,便可以被RegEx解析。许多常用的编程语言──纯用某个语言,让函式库具有可携性──都有的YAML的产生器和剖析器。当效能比较重要时,也有许多和C语言绑定的函式库可使用。
C语言
2007-06时,这个YAML的函式库渐趋稳定,并被YAML格式作者推荐使用[13]。
这个实现支持大部分1.0版的格式,并且被广泛的使用。它使用高阶interpreted languages进行最佳化。在2005之后,这个专案已经不再更新,不过仍可使用。
Perl
一个通用的接口,被数个YAML剖析器使用。
YAML简化版的实现。拥有小巧轻快的优点──比完整功能的YAML实现快上许多──并用纯Perl写成。
与SYCK函式库绑定。提供快速,highly featured的YAML剖析器。
与LibYaml绑定。提供1.1版更好的相容性。
PHP
纯PHP的实现。
与SYCK函式库绑定。
为symfony项目重写的Spyc, 可独立使用, 可以产生和剖析YAML文件。
Python
纯Python,或可选用LibYAML的函式库。
与SYCK绑定。
Ruby
从1.8版开始,YAML剖析器成为标准函式库之一。以SYCK为基础。
with full UTF-8 support
Java
以Syck为基础,and patterned off ruby-yaml
纯Java的实现。
R
以SYCK为基础。
JavaScript
原生的JavaScript即可产生YAML,但不能剖析。
产生和剖析。
.NET
待补充。
OCaml
C++
用C++将libYaml包装。
Objective-C
Lua
Haskell
XML
currently draft only。
常见错误与使用细节
建议使用能将跳格字符自动转换成空白字符的编辑器,并且使用定宽度的字型。
编辑器要能正确的处理UTF-8和UTF16编码(或是使用纯ASCII编码──它同时是UTF-8的子集)。
YAML的字串不需使用引号,这可以增加可读性,并避免巢状的跳脱字符。然而,这有时也会导致错误,例如,字串本身是一个暧昧的字眼(像数字或布林值);或在短句中意外的出现YAML的结构符号(常见的例子是由惊叹号起始的句子,或是包含冒号-空白的句子:"!Caca de vaca!"、"Caution: lions ahead")。这在发布YAML档案时并不造成困扰,但在制作小型指令码和人工编辑档案时,这问题还蛮常出现的。比较好的方法是善用区块符号("|" or ">")而不要使用单行字串,来避免这种暧昧的表达示。
相关概念
YAML没有自己的数据类型的定义,而是使用实现语言的数据类型。
例如,上面的那个YAML配置,在不同语言中解析后得到的数据类型并不相同。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
$house
=
array
(
'family'
=>
array
(
'name'
=>
'Doe'
,
'parents'
=>
array
(
'John'
,
'Jane'
),
'children'
=>
array
(
'Paul'
,
'Mark'
,
'Simone'
)
),
'address'
=>
array
(
'number'
=> 34,
'street'
=>
'Main Street'
,
'city'
=>
'Nowheretown'
,
'zipcode'
=>
'12345'
)
);
|
1
2
3
4
|
house = {
family: { name: Doe, parents: [John, Jane], children: [Paul, Mark, Simone] },
address: { number: 34, street: Main Street, city: Nowheretown, zipcode: 12345 }
}
|
讨论
这一点, 有可能是出奇制胜的地方,也可能是一个败笔。如果兼容性保证的不好的话,YAML数据在不同语言间流转会有问题。如果兼容性好的话,YAML就会成为不同语言间数据流通的桥梁。建议YAML官方设立兼容认证机制,每个语言的实现必须通过认证。
假如兼容性没问题的话,YAML就太完美了。轻巧,敏捷,高效,简便,通用。这才是理想中的数据模型。当然就现在而言,这还只是个理想。
xample 2.1. Sequence of Scalars (ball players)
- Mark McGwire
- Sammy Sosa
- Ken Griffey
|
Example 2.2. Mapping Scalars to Scalars (player statistics)
hr: 65 # Home runs
avg: 0.278 # Batting average
rbi: 147 # Runs Batted In
|
Example 2.3. Mapping Scalars to Sequences (ball clubs in each league)
american:
- Boston Red Sox
- Detroit Tigers
- New York Yankees
national:
- New York Mets
- Chicago Cubs
- Atlanta Braves
|
Example 2.4. Sequence of Mappings (players’ statistics)
-
name: Mark McGwire
hr: 65
avg: 0.278
-
name: Sammy Sosa
hr: 63
avg: 0.288
|
YAML also has flow styles, using explicit indicators rather than indentation to denote scope. The flow sequence is written as a comma separated list within square brackets. In a similar manner, the flow mapping uses curly braces.
Example 2.5. Sequence of Sequences
- [name , hr, avg ]
- [Mark McGwire, 65, 0.278]
- [Sammy Sosa , 63, 0.288]
|
Example 2.6. Mapping of Mappings
Mark McGwire: {hr: 65, avg: 0.278}
Sammy Sosa: {
hr: 63,
avg: 0.288
}
|
YAML uses three dashes (“---
”) to separate directives from document content. This also serves to signal the start of a document if no directives are present. Three dots ( “...
”) indicate the end of a document without starting a new one, for use in communication channels.
Example 2.7. Two Documents in a Stream (each with a leading comment)
# Ranking of 1998 home runs
---
- Mark McGwire
- Sammy Sosa
- Ken Griffey
# Team ranking
---
- Chicago Cubs
- St Louis Cardinals
|
Example 2.8. Play by Play Feed from a Game
---
time: 20:03:20
player: Sammy Sosa
action: strike (miss)
...
---
time: 20:03:47
player: Sammy Sosa
action: grand slam
...
|
Repeated nodes (objects) are first identified by an anchor (marked with the ampersand - “&
”), and are then aliased (referenced with an asterisk - “*
”) thereafter.
Example 2.9. Single Document with Two Comments
---
hr: # 1998 hr ranking
- Mark McGwire
- Sammy Sosa
rbi:
# 1998 rbi ranking
- Sammy Sosa
- Ken Griffey
|
Example 2.10. Node for “Sammy Sosa ” appears twice in this document
---
hr:
- Mark McGwire
# Following node labeled SS
- &SS Sammy Sosa
rbi:
- *SS # Subsequent occurrence
- Ken Griffey
|
A question mark and space (“?
”) indicate a complex mapping key. Within a block collection, key: value pairs can start immediately following the dash, colon, or question mark.
Example 2.11. Mapping between Sequences
? - Detroit Tigers
- Chicago cubs
:
- 2001-07-23
? [ New York Yankees,
Atlanta Braves ]
: [ 2001-07-02, 2001-08-12,
2001-08-14 ]
|
Example 2.12. Compact Nested Mapping
---
# Products purchased
- item : Super Hoop
quantity: 1
- item : Basketball
quantity: 4
- item : Big Shoes
quantity: 1
|
Scalar content can be written in block notation, using a literal style (indicated by |
”) where all line breaks are significant. Alternatively, they can be written with the folded style (denoted by “>
”) where each line break isfolded to a space unless it ends an empty or a more-indented line.
Example 2.13. In literals, newlines are preserved
# ASCII Art
--- |
\//||\/||
// || ||__
|
Example 2.14. In the folded scalars, newlines become spaces
--- >
Mark McGwire's
year was crippled
by a knee injury.
|
Example 2.15. Folded newlines are preserved for "more indented" and blank lines
>
Sammy Sosa completed another
fine season with great stats.
63 Home Runs
0.288 Batting Average
What a year!
|
Example 2.16. Indentation determines scope
name: Mark McGwire
accomplishment: >
Mark set a major league
home run record in 1998.
stats: |
65 Home Runs
0.278 Batting Average
|
YAML’s flow scalars include the plain style (most examples thus far) and two quoted styles. The double-quoted style provides escape sequences. The single-quoted style is useful when escaping is not needed. All flow scalars can span multiple lines; line breaks are always folded.
Example 2.17. Quoted Scalars
unicode: "Sosa did fine.\u263A"
control: "\b1998\t1999\t2000\n"
hex esc: "\x0d\x0a is \r\n"
single: '"Howdy!" he cried.'
quoted: ' # Not a ''comment''.'
tie-fighter: '|\-*-/|'
|
Example 2.18. Multi-line Flow Scalars
plain:
This unquoted scalar
spans many lines.
quoted: "So does this
quoted scalar.\n"
|
In YAML, untagged nodes are given a type depending on the application. The examples in this specification generally use the seq
, map
and str
types from the fail safe schema. A few examples also use the int
, float
, and null
types from theJSON schema. The repository includes additional types such as binary
, omap
, set
and others.
Example 2.19. Integers
canonical: 12345
decimal: +12345
octal: 0o14
hexadecimal: 0xC
|
Example 2.20. Floating Point
canonical: 1.23015e+3
exponential: 12.3015e+02
fixed: 1230.15
negative infinity: -.inf
not a number: .NaN
|
Example 2.21. Miscellaneous
null:
booleans: [ true, false ]
string: '012345'
|
Example 2.22. Timestamps
canonical: 2001-12-15T02:59:43.1Z
iso8601: 2001-12-14t21:59:43.10-05:00
spaced: 2001-12-14 21:59:43.10 -5
date: 2002-12-14
|
Explicit typing is denoted with a tag using the exclamation point (“!
”) symbol. Global tags are URIs and may be specified in a tag shorthand notation using a handle. Application-specific local tags may also be used.
Example 2.23. Various Explicit Tags
---
not-date: !!str 2002-04-28
picture: !!binary |
R0lGODlhDAAMAIQAAP//9/X
17unp5WZmZgAAAOfn515eXv
Pz7Y6OjuDg4J+fn5OTk6enp
56enmleECcgggoBADs=
application specific tag: !something |
The semantics of the tag
above may be different for
different documents.
|
Example 2.24. Global Tags
%TAG ! tag:clarkevans.com,2002:
--- !shape
# Use the ! handle for presenting
# tag:clarkevans.com,2002:circle
- !circle
center: &ORIGIN {x: 73, y: 129}
radius: 7
- !line
start: *ORIGIN
finish: { x: 89, y: 102 }
- !label
start: *ORIGIN
color: 0xFFEEBB
text: Pretty vector drawing.
|
Example 2.25. Unordered Sets
# Sets are represented as a
# Mapping where each key is
# associated with a null value
--- !!set
? Mark McGwire
? Sammy Sosa
? Ken Griff
|
Example 2.26. Ordered Mappings
# Ordered maps are represented as
# A sequence of mappings, with
# each mapping having one key
--- !!omap
- Mark McGwire: 65
- Sammy Sosa: 63
- Ken Griffy: 58
|
Below are two full-length examples of YAML. On the left is a sample invoice; on the right is a sample log file.
Example 2.27. Invoice
--- !<tag:clarkevans.com,2002:invoice>
invoice: 34843
date : 2001-01-23
bill-to: &id001
given : Chris
family : Dumars
address:
lines: |
458 Walkman Dr.
Suite #292
city : Royal Oak
state : MI
postal : 48046
ship-to: *id001
product:
- sku : BL394D
quantity : 4
description : Basketball
price : 450.00
- sku : BL4438H
quantity : 1
description : Super Hoop
price : 2392.00
tax : 251.42
total: 4443.52
comments:
Late afternoon is best.
Backup contact is Nancy
Billsmer @ 338-4338.
|
Example 2.28. Log File
---
Time: 2001-11-23 15:01:42 -5
User: ed
Warning:
This is an error message
for the log file
---
Time: 2001-11-23 15:02:31 -5
User: ed
Warning:
A slightly different error
message.
---
Date: 2001-11-23 15:03:17 -5
User: ed
Fatal:
Unknown variable "bar"
Stack:
- file: TopClass.py
line: 23
code: |
x = MoreObject("345\n")
- file: MoreClass.py
line: 58
code: |-
foo = bar
|
http://www.yaml.org/spec/1.2/spec.html