【YAML】
YAML（əl，尾音类似camel骆驼）是一个可读性高，用来表达资料序列化的格式。YAML参考了其他多种语言，包括：C语言、Python、Perl，并从XML、电子邮件的数据格式（RFC 2822）中获得灵感。Clark Evans在2001年首次发表了这种语言，另外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操作。其让人最容易上手的特色是巧妙避开各种封闭符号，如：引号、各种括号等，这些符号在巢状结构时会变得复杂而难以辨认。
== 范例 ==
=== 简单的文件 ===
资料结构可以用类似大纲的缩排方式呈现
---
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的语法）。
--- # 购物清单
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提供了节点参考（*）和杂凑合并（
#眼部雷射手术之标准程序
---
- step:  &id001                  # 定义锚点标签 &id001
instrument:      Lasik 2000
pulseEnergy:     5.4
pulseDuration:   12
repetition:      1000
spotSize:        1mm
- step:
# 加入其他键值
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                     # 布林值"真"
h: Yes we have No bananas  # 字串（包含"Yes"和"No"）
===== 其他特殊资料形态 =====
除了一般的资料形态之外，使用者也可以使用一些较为进阶的型态，但不保证可被每种解析器分析。使用时和强迫转型类似，要在形态名称之前加上两个惊叹号（
）。有几种重要的形态在本篇没有讨论，包括集合（sets），有序映照（ordered maps），时间戳记（timestamps）以及十六进位资料（hexadecimal）。下面这个范例则是位元资料（binary）
---
picture:
R0lGODdhDQAIAIAAAAAAANn
Z2SwAAAAADQAIAAACF4SDGQ
ar3xxbJ9p0qa7R0YxwzaFME
1IAADs=
===== 使用者自行扩充的资料形态 =====
许多YAML的实现允许使用者自订资料形态。在将一个物件序列化时，这个方法还颇方便的。某些区域资料形态可能不存在预设的资料形态中，不过这种型态在特定的YAML应用程式中是有定义的。这种区域资料形态用惊叹号（ ! ）表示。
---
myObject:
myClass { name: Joe, age: 15}
=== 语法 ===
在yaml.org（英文）可以找到轻巧而好用的小抄（亦是用YAML表示）及格式说明。下面的内容，是关于基本元件的摘要。
* 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版的子集,，同时非常接近 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。
---
example: >
HTML goes into YAML without modification
message: |
"Three is always greater than two,
even for large values of two"
--Author Unknown
相反的，要将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将缩排视为一个单一的空白，这可能会取得比其他标记语言更好的压缩比。此外，极深的缩排可以完全避免的是： (1)使用“内置格式”（即简称类JSON格式）而无缩排；或 (2)使用关联锚点展开阶层以形成一个摊平的格式，使得YAML解析器能透明地重组成完整的数据结构。
==== 安全性 ====
YAML是纯粹用来表达资料的语言，所以内部不会存代码注射的可执行命令。这代表剖析器会相当（至少）安全的解析文件，而不用担心潜在与执行命令相关的安全漏洞。举例来说，JSON是JavaScript的子集，因此可能有人想使用JavaScript本身的剖析器直接eval，不过这样一来就造成许多代码注射的漏洞。虽然在所有资料序列语言中，安全解析本质上是可能的，但可执行性却正是这样一个恶名昭彰的缺陷；而YAML缺乏相关的命令语言，可能是一个相对安全的利益。
=== 资料处理和呈现 ===
XML和YAML规范提供非常不同的逻辑模型来进行资料结点的展现、处理及储存。
== 实作与函式库 ==
=== 移植性 ===
简单的YAML档案（例如：简单的键值对）不需要完整的YAML剖析器，便可以被正则表达式解析。许多常用的程式语言──纯用某个语言，让函式库具有可携性──都有的YAML的产生器和剖析器。当效能比较重要时，也有许多和C语言绑定的函式库可使用。
=== C语言函式库 ===
*libYAML 2007-06时，这个YAML的函式库渐趋稳定，并被YAML格式作者推荐。
*SYCK 这个实现支援大部分1.0版的格式，并且被广泛的使用。它使用高阶解释型语言进行最佳化。在2005之后，这个专案已经不再更新，不过仍可使用。
=== 其他函式库 ===
下面几种程式语言都有与YAML相关的函式库:
*C++
**用C++将libYaml包装
*Go
**go-yaml 借鉴 C 库 libyaml 设计的 Go 语言移植。
*Haskell
** Haskell Reference wrappers
*Java
**jvyaml 以Syck为基础设计。
**JYaml 纯Java的实现。
*JavaScript
**原生的JavaScript即可产生YAML，但不能解析。
**YAML JavaScript 同时支持产生和解析。
*Objective-C
**Cocoa-Syck
*OCaml
**OCaml-Syck
*Lua
**Lua-Syck
*Perl
**CPAN YAML 一个通用的介面，被数个YAML解析器使用。
**YAML::Tiny YAML简化版的实现。拥有小巧轻快的优点──比完整功能的YAML实现快上许多，并用纯Perl写成。
**YAML::Syck 与SYCK函式库绑定。提供快速、功能丰富（highly featured）的YAML解析器。
**YAML::XS 与LibYaml绑定。提供1.1版更好的相容性。
*PHP
**Spyc 纯PHP的实现。
**PHP-Syck（与SYCK函式库绑定）
**sfYaml 为symfony项目重写的Spyc, 可独立使用，可以产生和解析YAML文件。
*Python
**PyYaml 纯Python，或可选用LibYAML的函式库。
** PySyck 与SYCK绑定。
*Ruby（从1.8版开始，YAML解析器成为标准函式库之一。以SYCK为基础。）
**Ya2YAML 具有完全的UTF-8支持
*R
**CRAN YAML 以SYCK为基础。
*.NET
** .NET Parser
** YamlDotNet
*Scala
**scala-yaml
*Tcl
**在Tcl 8.4中可用
*XML YAXML (当前仍在设计中)
=== 常见错误与使用细节 ===
*编辑器：
**建议使用能将跳格字元自动转换成空白字元的编辑器，并且使用定宽度的字型。
**编辑器要能正确的处理UTF-8和UTF16编码（或是使用纯ASCII编码──它同时是UTF-8的子集）.
*字串：
**YAML的字串不需使用引号，这可以增加可读性，并避免巢状的跳脱字元。然而，这有时也会导致错误，例如，字串本身是一个暧昧的字眼（像数字或布林值）；或在短句中意外的出现YAML的结构符号（常见的例子是由惊叹号起始的句子，或是包含冒号-空白的句子："!Caca de vaca!"、"Caution: lions ahead"）。这在发布YAML档案时并不造成困扰，但在制作小型指令码和人工编辑档案时，这问题却会常常出现。比较好的方法是善用区块符号（"|" or ">"）而不要使用单行字串，来避免这种暧昧的表示方法。
*预期实做的特性
== 参看 ==
其他标记语言：
*JSON，可以说是YAML的子集。
*XML
*Simple Outline XML
*OGDL
*S-表达式
*Plist，由NEXTSTEP改写成的资料序列语言。
*SDL