YAML預(yù)研文檔
YAML概要
YAML是"YAML Ain't a Markup Language"(YAML不是一種置標(biāo)語(yǔ)言)的遞歸縮寫颤专,早先YAML的意思其實(shí)是:"Yet Another Markup Language"(另外一種置標(biāo)語(yǔ)言),但為了強(qiáng)調(diào)這種語(yǔ)言以數(shù)據(jù)做為中心,而不是以置標(biāo)語(yǔ)言為重點(diǎn)淘讥,而用返璞詞重新命名抱冷,YAML的官方定義很簡(jiǎn)單近上,即一種人性化的數(shù)據(jù)格式定義語(yǔ)言儡毕,其主要功能用途類似于XML或JSON填具,YAML使用空白字符和分行來(lái)分隔數(shù)據(jù)集歇,且巧妙避開(kāi)各種封閉符號(hào)搀罢,如:引號(hào)康嘉、括號(hào)等仆抵,以避免這些符號(hào)在復(fù)雜層次結(jié)構(gòu)中變得難以辨認(rèn)甫窟。YAML的語(yǔ)法與高階語(yǔ)言類似密浑,可以很簡(jiǎn)單地表述序列(java中的list)、雜湊表(java中的map)粗井、標(biāo)量(java中的基本類型等)數(shù)據(jù)結(jié)構(gòu)尔破,它重點(diǎn)強(qiáng)調(diào)可閱讀性。
YAML vs XML
與YAML相似的數(shù)據(jù)格式定義語(yǔ)言是XML浇衬,YAML比XML優(yōu)越性表現(xiàn)在
優(yōu)勢(shì):
- YAML的可讀性好
- YAML和腳本語(yǔ)言的交互性好
- YAML使用實(shí)現(xiàn)語(yǔ)言的數(shù)據(jù)類型
- YAML有一個(gè)一致的信息模型
- YAML易于實(shí)現(xiàn)
上面5條是XML不足的地方懒构,同時(shí),YAML也具有XML的下列優(yōu)點(diǎn):
- YAML可以基于流來(lái)處理
- YAML表達(dá)能力強(qiáng)耘擂,擴(kuò)展性好
YAML類似于XML的數(shù)據(jù)描述語(yǔ)言胆剧,語(yǔ)法比XML簡(jiǎn)單很多,YAML試圖用一種比XML更敏捷的方式醉冤,來(lái)完成XML所完成的任務(wù)秩霍。
YAML vs JSON
JSON的語(yǔ)法其實(shí)是YAML的子集篙悯,大部分的JSON文件都可以被YAML的剖析器剖析。雖然大部分的數(shù)據(jù)分層形式也可以使用類似JSON的格式铃绒,不過(guò)YAML并不建議這樣使用鸽照,除非這樣編寫能讓文件可讀性增加,更重要的是匿垄,YAML的許多擴(kuò)展在JSON是找不到的移宅,如:進(jìn)階資料形態(tài)、關(guān)系錨點(diǎn)椿疗、字串不需要引號(hào)漏峰、映射資料形態(tài)會(huì)儲(chǔ)存鍵值的順序等。
YAML用途
腳本語(yǔ)言
由于實(shí)現(xiàn)簡(jiǎn)單届榄,解析成本很低浅乔,YAML特別適合在腳本語(yǔ)言中使用。列一下現(xiàn)有的語(yǔ)言實(shí)現(xiàn):Ruby铝条,Java靖苇,Perl,Python班缰,PHP贤壁,OCaml,JavaScript埠忘,除了Java脾拆,其他都是腳本語(yǔ)言。
序列化
YAML比較適合做序列化莹妒。因?yàn)樗撬拗髡Z(yǔ)言數(shù)據(jù)類型直轉(zhuǎn)的名船。
配置文件
YAML做配置文件也不錯(cuò)。寫YAML要比寫XML快得多(無(wú)需關(guān)注標(biāo)簽或引號(hào))旨怠,并且比ini文檔功能更強(qiáng)渠驼。
調(diào)試
由于其很強(qiáng)的閱讀性,用于調(diào)試過(guò)程中dump出信息供分析也是一種比較方便的做法鉴腻。
YAML缺陷與不足
YAML沒(méi)有自己的數(shù)據(jù)類型的定義迷扇,而是使用實(shí)現(xiàn)語(yǔ)言的數(shù)據(jù)類型。一個(gè)YAML文件爽哎,在不同語(yǔ)言中解析后得到的數(shù)據(jù)類型可能會(huì)不同谋梭,由于其兼容性問(wèn)題,不同語(yǔ)言間的數(shù)據(jù)流轉(zhuǎn)不建議使用YAML倦青。
YAML語(yǔ)法與范例
- YAML使用可打印的Unicode字符,可使用UTF-8或UTF-16
- 使用空白字符(不能使用
Tab
)分層盹舞,同層元素左側(cè)對(duì)齊- 單行注解由井字號(hào)(
#
)開(kāi)始产镐,可以出現(xiàn)在行中任何位置- 每個(gè)清單成員以單行表示隘庄,并用短杠+空白(
-
)起始- 每個(gè)雜湊表的成員用冒號(hào)+空白(
:
)分開(kāi)鍵和值- 雜湊表的鍵值可以用問(wèn)號(hào) (
?
)起始,表示多個(gè)詞匯組成的鍵值- 字串一般不使用引號(hào)癣亚,但必要的時(shí)候可以用引號(hào)框住
- 使用雙引號(hào)表示字串時(shí)丑掺,可用倒斜線(
\
)進(jìn)行特殊字符轉(zhuǎn)義- 區(qū)塊的字串用縮排和修飾詞(非必要)來(lái)和其他資料分隔,有新行保留(使用符號(hào)
|
)或新行折疊(使用符號(hào)>
)兩種方式- 在單一檔案中述雾,可用連續(xù)三個(gè)連字號(hào)(
---
)區(qū)分多個(gè)檔案- 可選擇性的連續(xù)三個(gè)點(diǎn)號(hào)(
...
)用來(lái)表示檔案結(jié)尾(在流式傳輸時(shí)非常有用街州,不需要關(guān)閉流即可知道到達(dá)結(jié)尾處)- 重復(fù)的內(nèi)容可使從參考標(biāo)記星號(hào) (
*
)復(fù)制到錨點(diǎn)標(biāo)記(&
)- 指定格式可以使用兩個(gè)驚嘆號(hào) ( !! ),后面接上名稱
receipt: Oz-Ware Purchase Invoice
date: 2007-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
price: 100.27
quantity: 1
bill-to: &id001
street: |
123 Tornado Alley
Suite 16
city: East Westville
state: KS
ship-to: *id001
specialDelivery: >
Follow the Yellow Brick
Road to the Emerald City.
Pay no attention to the
man behind the curtain.
...
這個(gè)文件的的頂層由七個(gè)鍵值組成:其中一個(gè)鍵值"items"玻孟,是個(gè)兩個(gè)元素構(gòu)成的清單唆缴,清單中的兩個(gè)元素同時(shí)也是包含了四個(gè)鍵值的雜湊表。
文件中重復(fù)的部分處理方式:使用錨點(diǎn)(&)和參考(*)標(biāo)簽將"bill-to"雜湊表的內(nèi)容復(fù)制到"ship-to"雜湊表黍翎。也可以在文件中加入選擇性的空行面徽,以增加可讀性。
YAML的JAVA實(shí)現(xiàn)
YAML已經(jīng)有了多種語(yǔ)言不少實(shí)現(xiàn)匣掸,詳見(jiàn)YAML官網(wǎng)趟紊。
一般YAML文件擴(kuò)展名為.yaml,比如John.yaml碰酝,其內(nèi)容為:
name: John Smith
age: 37
children:
- name: Jimmy Smith
age: 15
- name: Jenny Smith
age: 12
spouse:
name: Jane Smith
age: 25
由于yaml的超強(qiáng)可讀性霎匈,我們了解到:John今年37歲,兩個(gè)孩子Jimmy 和Jenny活潑可愛(ài)送爸,妻子Jane年輕美貌铛嘱,而且年僅25歲,一個(gè)幸福的四口之家碱璃。
對(duì)John.yaml進(jìn)行java描述弄痹,抽象出一個(gè)Person類,如下:
public class Person {
private String name;
private int age;
private Person sponse;
private Person[] children;
// setXXX, getXXX方法略.
}
現(xiàn)在我們使用java裝配一個(gè)Jone:
Person john = new Person();
john.setAge(37);
john.setName("John Smith");
Person sponse = new Person();
sponse.setName("Jane Smith");
sponse.setAge(25);
john.setSponse(sponse);
Person[] children = {new Person(), new Person()};
children[0].setName("Jimmy Smith");
children[0].setAge(15);
children[1].setName("Jenny Smith");
children[1].setAge(12);
john.setChildren(children);
使用SnakeYAML實(shí)現(xiàn)
項(xiàng)目主頁(yè):http://code.google.com/p/snakeyaml/
使用手冊(cè):https://code.google.com/p/snakeyaml/wiki/Documentation
SnakeYAML是一個(gè)標(biāo)準(zhǔn)的YAML的java實(shí)現(xiàn)嵌器,它有以下特點(diǎn):
- 完全支持YAML 1.1肛真,可以跑通規(guī)范中的所有示例
- 支持YAML的所有類型
- 支持UTF-8/UTF-16的輸入和輸出
- 提供了本地java對(duì)象的序列化和反序列化的高層API
- 提供相對(duì)合理的錯(cuò)誤提示信息
使用SnakeYAML將john dump出來(lái),如果有引用相同對(duì)象爽航,則dump出到y(tǒng)aml文件會(huì)自動(dòng)使用&
和*
進(jìn)行錨點(diǎn)和引用:
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
Yaml yaml = new Yaml(options);
//Yaml yaml = new Yaml();
String dump = yaml.dump(john);
System.out.println(dump);
內(nèi)容如下:
!!Person
age: 37
children:
- age: 15
children: null
name: Jimmy Smith
sponse: null
- age: 12
children: null
name: Jenny Smith
sponse: null
name: John Smith
sponse:
age: 25
children: null
name: Jane Smith
sponse: null
現(xiàn)在用SnakeYAML把yaml load進(jìn)來(lái)蚓让,如果yaml文件中使用了&
和*
,則會(huì)自動(dòng)對(duì)load出來(lái)的對(duì)象賦相同的值:
Yaml yaml = new Yaml();
Object load = yaml.load(new FileInputStream(new File("jhon.yaml")));
System.out.println(load.getClass());
System.out.println(yaml.dump(load));
或
Yaml yaml = new Yaml(options);
Person person = yaml.loadAs(inputStream, Person.class);
System.out.println(person.getSponse().getChildren().length);
如果一個(gè)yaml文件中有多個(gè)文檔讥珍,由---
分割历极,解析如下:
Yaml yaml = new Yaml();
int counter = 0;
for (Object data : yaml.loadAll(input)) {
System.out.println(data);
counter++;
}
保存一個(gè)Map對(duì)象:
Map<String, Object> data = new HashMap<String, Object>();
data.put("name", "Silenthand Olleander");
data.put("race", "Human");
data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });
Yaml yaml = new Yaml();
String output = yaml.dump(data);
System.out.println(output);
// or
StringWriter writer = new StringWriter();
yaml.dump(data, writer);
System.out.println(writer.toString());
將多個(gè)文檔dump出到同一個(gè)yaml文件中去:
List<Integer> docs = new LinkedList<Integer>();
for (int i = 1; i < 4; i++) {
docs.add(i);
}
DumperOptions options = new DumperOptions();
//options.setCanonical(true);
options.explicitStart(true);
Yaml yaml = new Yaml(options);
System.out.println(yaml.dump(docs));
System.out.println(yaml.dumpAll(docs.iterator()));
--- [1, 2, 3]
--- 1
--- 2
--- 3
YAML與java類型對(duì)照表:
YAML | JAVA |
---|---|
!null | null |
!!bool | Boolean |
!!int | Integer, Long, BigInteger |
!!float | Double |
!!binary | String |
!!timestamp | java.util.Date, java.sql.Date, java.sql.Timestamp |
!!omap, !!pairs | List of Object[] |
!!set | Set |
!!str | String |
!!seq | List |
!!map | Map |
集合的默認(rèn)實(shí)現(xiàn)是:
- List: ArrayList
- Map: LinkedHashMap
使用JYaml實(shí)現(xiàn)
JYaml(最新版本是2007年的,可以考慮放棄了)衷佃,使用JYaml把Jone “Dump” 出來(lái):
File dumpfile = new File("John_dump.yaml");
Yaml.dump(john, dumpfile);
下面我們看看John_dump.yaml是什么樣子:
--- !yaml.test.internal.Person
age: 37
children: !yaml.test.internal.Person[]
- !yaml.test.internal.Person
age: 15
name: Jimmy Smith
- !yaml.test.internal.Person
age: 12
name: Jenny Smith
name: John Smith
sponse: !yaml.test.internal.Person
age: 25
name: Jane Smith
其中!yaml.test.internal.Person是一些類型的信息趟卸。load的時(shí)候需要用。
現(xiàn)在用JYaml把Jone_dump.yaml load進(jìn)來(lái):
Person john2 = (Person) Yaml.loadType(dumpfile, Person.class);
還可以用下面的代碼dump出沒(méi)有類型信息的John.yaml:
Yaml.dump(john,dumpfile, true);
我們?cè)賮?lái)看看JYaml對(duì)流處理的支持,為簡(jiǎn)便起見(jiàn)锄列,我們只是把同一個(gè)john寫10次:
YamlEncoder enc = new YamlEncoder(new FileOutputStream(dumpfile));
for(int i=0; i<10; i++){
john.setAge(37+i);
enc.writeObject(john);
enc.flush();
}
enc.close();
下面再把這十個(gè)對(duì)象一個(gè)一個(gè)讀出來(lái)(注意while循環(huán)退出的方式):
YamlDecoder dec = new YamlDecoder(new FileInputStream(dumpfile));
int age = 37;
while(true){
try{
john = (Person) dec.readObject();
assertEquals(age, john.getAge());
age++;
}catch(EOFException eofe){
break;
}
}
【其他參考】
原文鏈接:http://blog.csdn.net/conquer0715/article/details/42108061
YAML 語(yǔ)言教程
JS-YAML及其在線 Demo