YAML

YAML

YAML(/ˈjæməl/,尾音類似camel駱駝)是一個可讀性高,用來表達數據序列化的格式。YAML參考了其他多種語言,包括:C語言PythonPerl,並從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 Ain't Markup Language
  • 中文縮寫:標言
  • 外語縮寫:YAML
功能,示例,簡單的檔案,YAML的高級組件,語法,介紹,誕生,命名,功能,格式,多行縮進,單行縮寫,適用場景,腳本語言,序列化,配置檔案,語言比較,JSON,XML和SDL,縮排劃界,非階層式的資料模型,實際的考量,安全性,資料處理和呈現,函式庫,移植性,C語言,Perl,PHP,Python,Ruby,Java,R,JavaScript,.NET,OCaml,C++,Objective-C,Lua,Haskell,XML,Go,常見錯誤與使用細節,宿主語言,相關概念,討論,

功能

YAML的語法和其他高級語言類似,並且可以簡單表達清單、散列表,標量等數據形態。它使用空白符號縮進和大量依賴外觀的特色,特別適合用來表達或編輯數據結構、各種配置檔案、傾印調試內容、檔案大綱(例如:許多電子郵件標題格式和YAML非常接近)。儘管它比較適合用來表達層次結構式(hierarchical model)的數據結構,不過也有精緻的語法可以表示關係性(relational model)的數據。由於YAML使用空白字元和分行來分隔數據,使得它特別適合用grep/Python/Perl/Ruby操作。其讓人最容易上手的特色是巧妙避開各種封閉符號,如:引號、各種括弧等,這些符號在嵌套結構時會變得複雜而難以辨認。

示例

簡單的檔案

數據結構可以用類似大綱的縮進方式呈現
---receipt:     Oz-Ware Purchase Invoicedate:        2012-08-06customer:    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:  1bill-to:  &id001    street: |             123 Tornado Alley            Suite 16    city:   East Centerville    state:  KSship-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最常被提到的特色有兩個:關係樹和數據形態。
樹狀結構之間的互動引用
數據合併和參考
為了維持檔案的簡潔,並避免數據輸入的錯誤,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                     # 布林值"真"h: Yes we have No bananas  # 字串(包含"Yes"和"No")

語法

在yaml.org(英文)可以找到輕巧而好用的小抄(亦是用YAML表示)及格式說明。下面的內容,是關於基本組件的摘要。
  • YAML使用可列印的Unicode字元,可使用UTF-8UTF-16
  • 使用空白字元為檔案縮進來表示結構;不過不能使用跳格字元(TAB)。
  • 註解由井字號(#)開始,可以出現在一行中的任何位置,而且範圍只有一行(也就是一般所謂的單行註解)
  • 每個清單成員以單行表示,並用短槓+空白(- )起始。或使用方括弧[]),並用逗號+空白(, )分開成員。
  • 每個散列表的成員用冒號+空白(: )分開鍵值和內容。或使用大括弧({ }),並用逗號+空白(, )分開。
  • 散列表的鍵值可以用問號(?)起始,用來明確的表示多個辭彙組成的鍵值。
字元串平常並不使用引號,但必要的時候可以用雙引號(")或單引號(')框住。
  • 使用雙引號表示字元串時,可用倒斜線(\)開始的轉義字元(這跟C語言類似)表示特殊字元。
區塊的字元串用縮進和修飾符(非必要)來和其他數據分隔,有新行保留(preserve)(使用符號|)或新行摺疊(flod)(使用符號>)兩種方式。
在單一檔案中,可用連續三個連字號---)區分多個檔案。
  • 另外,還有選擇性的連續三個點號(...)用來表示檔案結尾。
重複的內容可使從參考標記星號(*)複製到錨點標記(&)。
指定格式可以使用兩個驚嘆號(!!),後面接上名稱。
檔案中的單一檔案可以使用指導指令,使用方法是百分比符號(%)。有兩個指導指令在YAML1.1版中被定義:
  • %YAML 指導指令,用來識別檔案的YAML版本。
  • %TAG 指導指令,被用在URI的前綴標記。這個方法在標記節點的類型時相當有用。
YAML在使用逗號及冒號時,後面都必須接一個空白字元,所以可以在字元串或數值中自由加入分隔設定號(例如:5,280或http://www.wikipedia.org)而不需要使用引號。
另外還有兩個特殊符號在YAML中被保留,有可能在未來的版本被使用--(@)和(`)。

介紹

誕生

YAML參考了其他多種語言,包括:XMLC語言PythonPerl以及電子郵件格式RFC2822。
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對用冒號“:”來分隔。樣例如下:
house:  family:    name: Doe    parents:      - John      - Jane    children:      - Paul      - Mark      - Simone  address:    number: 34    street: Main Street    city: Nowheretown    zipcode: 12345
注意:
  1. 字串不一定要用雙引號標識;
  2. 在縮排中空白字元的數目並不是非常重要,只要相同階層的元素左側對齊就可以了(不過不能使用TAB字元);
  3. 允許在檔案中加入選擇性的空行,以增加可讀性;
  4. 在一個檔案中,可同時包含多個檔案,並用“——”分隔;
  5. 選擇性的符號“...”可以用來表示檔案結尾(在利用串流的通訊中,這非常有用,可以在不關閉串流的情況下,傳送結束訊號)。

單行縮寫

YAML也有用來描述好幾行相同結構的數據的縮寫語法,數組用'[]'包括起來,hash用'{}'來包括。因此,上面的這個YAML能夠縮寫成這樣:
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,Go 。除了Java 和 Go,其他都是腳本語言。

序列化

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將縮排視為一個單一的空白,這可能會取得比其他標記語言更好的壓縮比。此外,極深的縮排可以完全避免的是:
  • 使用“內置格式”(即簡稱類JSON格式)而無縮排;
  • 使用關聯錨點展開階層以形成一個攤平的格式,使得YAML解析器能透明地重組成完整的數據結構。

安全性

YAML是純粹用來表達資料的語言,所以內部不會存代碼注入的可執行命令。這代表剖析器會相當(至少)安全的解析檔案,而不用擔心潛在與執行命令相關的安全漏洞。舉例來說,JSON是JavaScript的子集,使用JavaScript本身的剖析器是相當誘人的,不過也造成許多代碼注入的漏洞。雖然在所有資料序列語言中,安全解析本質上是可能的,但可執行性卻正是這樣一個惡名昭彰的缺陷;而YAML缺乏相關的命令語言,可能相對安全。

資料處理和呈現

XML和YAML規範提供非常不同的邏輯模型來進行資料結點的展現、處理及儲存。

函式庫

移植性

簡單的YAML檔案(例如:簡單的鍵值對)不需要完整的YAML剖析器,便可以被RegEx解析。許多常用的程式語言──純用某個語言,讓函式庫具有可攜性──都有的YAML的產生器和剖析器。當效能比較重要時,也有許多和C語言綁定的函式庫可使用。

C語言

  • libYAML
2007-06時,這個YAML的函式庫漸趨穩定,並被YAML格式作者推薦使用[13]。
  • SYCK
這個實現支持大部分1.0版的格式,並且被廣泛的使用。它使用高階interpreted languages進行最佳化。在2005之後,這個專案已經不再更新,不過仍可使用。

Perl

  • 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
with full UTF-8 support

Java

  • jvyaml
以Syck為基礎,and patterned off ruby-yaml
  • JYaml
純Java的實現。

R

  • CRAN YAML
以SYCK為基礎。

JavaScript

原生的JavaScript即可產生YAML,但不能剖析。
  • YAML JavaScript
產生和剖析。

.NET

待補充。

OCaml

  • OCaml-Syck

C++

用C++將libYaml包裝。

Objective-C

  • Cocoa-Syck

Lua

  • Lua-Syck

Haskell

  • Haskell Reference wrappers

XML

  • YAXML
currently draft only。

Go

  • Go-yaml

常見錯誤與使用細節

  • 編輯器
建議使用能將跳格字元自動轉換成空白字元的編輯器,並且使用定寬度的字型。
編輯器要能正確的處理UTF-8和UTF16編碼(或是使用純ASCII編碼──它同時是UTF-8的子集)。
  • 字串
YAML的字串不需使用引號,這可以避免使用複雜的轉義字元,以增加可讀性。然而,這有時也會導致錯誤,例如,字串本身是一個曖昧的字眼(像數字或布爾值);或在短句中意外的出現YAML的結構符號(常見的例子是由驚嘆號起始的句子,或是包含冒號-空白的句子:"!Caca de vaca!"、"Caution: lions ahead")。這在發布YAML檔案時並不造成困擾,但在製作小型指令碼和人工編輯檔案時,這問題還蠻常出現的。比較好的方法是善用區塊符號("|" or ">")而不要使用單行字串,來避免這種曖昧的表達方式。
  • 預期實做的特性

宿主語言

相關概念

YAML沒有自己的數據類型的定義,而是使用實現語言的數據類型。
例如,上面的那個YAML配置,在不同語言中解析後得到的數據類型並不相同。
  • PHP
$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'));
  • PYTHON
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就太完美了。輕巧,敏捷,高效,簡便,通用。這才是理想中的數據模型。當然就現在而言,這還只是個理想。

相關詞條

熱門詞條

聯絡我們