YAML是『YAML Ain't Markup Language』的缩写,又一个递回式缩写的例子。发音是『Camel』,也就是英文骆驼的发音。通常,我们看到xxML的标准,都会想到这是不是又一个所谓的Markup Language。刚好相反,正如其名称所显示的,YAML是与Markup Language相反,他是要使用不同的方式来表示Markup Language所能够做到的功能。简单的说,YAML利用适当文字的缩排,及一些基本符号来达到Markup Language的所能够表示阶层以及自订结构的功能。
所谓的Markup Language,的确可以让机器很容易的进行处理。但是要让人类能够轻易的理解,似乎并非这么的容易。YAML就是除了要让机器可以容易处理,也让人类可以很容易的了解以及编辑。 总体来说,YAML的设计目的如下:
- YAML的文件能够很容易被人类所读取及了解。
- YAML可用来表示程式语言的原生资料结构。
- YAML的资料可以在不同的程式语言间移植。
- YAML有一个一致的模型来支援一般的工具。
- YAML能够使用串流的方式(stream-based)来处理。
- YAML具有丰富的表达能力及可扩充性。
- YAML可以容易被实作及使用。
YAML如果没有特别的指定,是使用Unicode作为其预设使用字元集。 一份YAML文件可以由好几个无关的文件所组成。依据YAML的规定,每份文件的启始需用"---"表示之。而结尾需用"..."表示之。有时结尾可以省略,当遇到另一个"---"出现,或是档案结尾,就表示目前这份文件结束了。例如:
--- This is a test. This document is used to introduce YAML. --- You can understand how to use YAML. ...
对于程式语言来说,所有的资料结构,原则上都可以用下面三种方式来表示:
- Mappings (hashes/dictionaries)
- Sequences (arrays/lists)
- Scalars (strings/numbers)
所谓的Mapping主要有两个部分所组成一个是Key,另一个Value。一组Key与Value称为一个Key/Value pair。这样的一组pair代表一组资料,一个Mapping有许许多多的Key/Value pair所组成。而Sequence所代表的是一个一个资料所形成的串列。Scalars则是我们常见的数字及字串等资料。
先让我们看一下Mapping的用法。因为,Mapping由两个部分所组成,Key及Value。在YAML中一个Key/Value Pair是使用冒号":"将这两者予以分隔。假设我们将个人资料用YAML来表示。可以表示成下面的方式:
Name: Gary Lee Birth: 1970-01-01 Score: 0.92
是不是很容易理解呢?其实这种表示法在MIME这种E-Mail标准中使用。所以,对于机器来说这样的表示法处理起来并不会有特别的困难。另外,对于YAML来说,多余的空白字元会被忽略的,所以对于上面的例子来说,用下面几种写法也是一样的。
Name: Gary Lee Birth: 1970-01-01 Score: 0.92
或
Name : Gary Lee Birth : 970-01-01 Score : 0.92
虽说空白字元是多余的。不过在冒号后面至少要有一个空白字元。这是YAML所强制规定的。 接着我们来看一下Sequence的表示方式。依据YAML的规定,Sequence的每个项目前面都应该使用"-"来作为识别符号。与Mapping相同的是,在"-"后面也需要有至少一个空白字元。
举例来说,我们有几个人名:Gary, David, Tom, Jim等。用Sequences来表示就如下所示:
- Gary - David - Tom - Jim
当然,程式内的资料结构往往没有这么简单,举例来说,像是Sequences中的Sequences,或是Mapping中的Mapping这样的资料,要如何表示呢?YAML另外制订了两个方式来表示简单的Sequence及Mapping。
简易的Sequence表示法:
[item1, item2, ..., itemN]
所以,一个Sequence中的Sequence可以写成下面这样:
- [Name, Birth, Score] - [Gary, 1977-02-12, 1.0] - [David, 1972-05-21, 0.93] - [Tom, 1979-12-12, 0.82]
另外,简易的Mapping表示法:
{Key1: Value1, Key2: Value2, ..., KeyN: ValueN}
所以,Mapping中的Mapping可以用下面的写法:
Gary: {Birth: 1977-02-12, Score: 1.0} David: {Birth: 1972-05-21, Score: 0.93} Tom: { Birth: 1979-12-12, Score: 0.82 }
有些时候,Mapping所使用的Key可能不是单纯的型态。Mapping的Key也可以是Sequence 或是其他更复杂的资料型态。只是这种Key必需在前面加上"?"的符号。例如:
? [Gary, Tom, Jim] : { Birth: 2004-04-20, City: Taipei }
在YAML中,也支援注解,所谓的注解就是用来说明资料本身的项目。并不代表资料本身。要使用注解就是使用"#"。例如:
# Gary's profile. Gary: { Birth: 1977-02-12, Score: 1.0 }
在YAML用一种简化的方式可以让使用者重复使用定义过的Node。首先,您需要给打算重复使用的Node一个名字。这个名字前面需要用"&"作为起始。然后要重复使用时,就使用"*"加上该名字。例如:
Name: &GL Gary Lee Birth: 1970-01-01 Score: 0.92 Alias: *GL
当然,以上的功能是不足以应付更复杂的资料表示方式,甚至是像XML具有扩充的能力。因此,YAML提供了更复杂的资料表示方式。资料结构一般都会使用阶层式的方式来表示资料。对于XML来说,就是使用巢状式标签来表示。但是YAML用了另外一种人类更容易的方式来表示。也就是『缩排』(indentation)。
YAML建议缩排不要使用Tab,而是使用一般的空白字元。这是因为Tab容易因为编辑器的不同,而产生不同排版效果。这样容易被误解。
我们看一下的范例:
Name: Gary Profile: Birth: 1975-04-43 Addr: - City: Taipei Road: Chung-Shoang Number: 20 Flood: 3 - City: TaoYuan Road: LongChung Number: 10 Flood: 2 Blood Type: A Score: 0.98
其实,不用多说,我相信读者也看的出来这些资料的阶层关系。这就是YAML所强调的,可以很容易的被人类所读懂。这边比较需要说明的是Address。我们前面说过"-"是用来表示Sequences。所以,Addr的Value一共有两个项目,也就是说有两个地址。
您可以依照自己的需要制订任意的阶层。当然也可以在各阶层之下混用各种YAML所支援的资料型态。
有些时候,资料太多时,一行可能放不下。这时候可能要分成多行。在YAML中提供了两种方式可以让你把一个资料分成多行。第一个方式是使用"|"符号在资料的最前面。例如:
Self_Intro: | Hi. My name is gary. This article is used to help you understand how to use YAML.
另外,还有一种方式是使用">"符号。
Self_Intro: > Hi. My name is gary. This article is used to help you understand how to use YAML.
这两种方式有什么不同呢?唯一的差别在于"|"符号会保留『换行』。但是,在">"中,换行字元会被视为空白字元。
一般的情况,没有特别指定的话,YAML会依据下面的方式来辨别资料型态。
整数: 标准(canonical): 12345 十进位(decimal): +12,345 六十进位法(sexagesimal): 3:25:45 八进位(octal): 014 十六进位(hexadecimal): 0xC 浮点数: 标准(canonical): 1.23 科学记号(exponential): 12.3015e+02 六十进位法(sexagesimal): 20:30.15 固定表示法(fixed): 1,230.15 负的无限数(negative infinity): (-inf) 非数字(not a number): (NaN) 其他: null: ~ 真(true): y 伪(false): n 字串(string): '12345' 时间: 标准(canonical): 2001-12-15T02:59:43.1Z ISO 8601所定义的标准表示法(iso8601): 2001-12-14t21:59:43.10-05:00 间隔表示法(spaced): 2001-12-14 21:59:43.10 -05:00 日期(date): 2002-12-14
有些时候,你也可以直接指定要使用型态。此时,您需要在只指定的资料前面加上"!"符号,并且写上型态的名称。例如:
birth: !date 2004-04-29 picture: !binary | R0lGODlhDAAMAIQAAP//9/X 17unp5WZmZgAAAOfn515eXv Pz7Y6OjuDg4J+fn5OTk6enp 56enmleECcgggoBADs=
另外,有些时候你或许要使用预先定义的好的资料型态,而这个资料型态可能是别的URL所指定的档案中所定义的。此时,您需要在文件的开头指定要参考哪里的档案。并且在使用指定的型态时,前面加上"^"符号。例如:
--- !clarkevans.com,2002/graph/^shape - !^circle center: &ORIGIN {x: 73, y: 129} radius: 7 - !^line start: *ORIGIN finish: { x: 89, y: 102 }
最后,我们用一个较大的范例作个结尾:
--- Name: Tom Lee Profile: Birth: 1975-04-43 Addr: - City: Taipei Road: Chung-Shoang Number: 20 Flood: 3 - City: TaoYuan Road: LongChung Number: 10 Flood: 2 Blood Type: A Relative: - Type: Mother Name: Peggy Birth: 1943-12-1 Notes: - Living in U.S. - Have five children. - Type: Brother Name: Jim Birth: 1942-12-3 Notes: ~ Photo: - !binary | R0lGODlhDAAMAIQAAP//9/X 17unp5WZmZgAAAOfn515eXv Pz7Y6OjuDg4J+fn5OTk6enp 56enmleECcgggoBADs= Score: 0.98 ...