YAML

**YAML**（/ˈjæmə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 操作。其讓人最容易上手的特色是巧妙避開各種封閉符號，如：引號、各種括號等，這些符號在巢狀結構時會變得複雜而難以辨認。

## 範例

### 簡單的檔案

資料結構可以用類似大綱的縮排方式呈現

注意在 YAML 中，字串不一定要用雙引號標示。另外，在縮排中空白字元的數目並不是非常重要，只要相同階層的元素左側對齊就可以了（不過不能使用 TAB 字元）。這個檔案的頂層由七個鍵值組成：其中一個鍵值 "items"，是兩個元素構成的陣列（或稱清單），這清單中的兩個元素同時也是包含了四個鍵值的雜湊表。檔案中重複的部分用這個方法處理：使用錨點（**&**）和參照（**\***）標籤將 "bill-to" 雜湊表的內容複製到 "ship-to" 雜湊表。也可以在檔案中加入選擇性的空行，以增加可讀性。在一個檔案中，可同時包含多個檔案，並用 "`**---**`"分隔。選擇性的符號"`**...**`" 可以用來表示檔案結尾（在利用串流的通訊中，這非常有用，可以在不關閉串流的情況下，發送結束訊號）。

## 語言的構成元素

### YAML 的基本元件

YAML 提供縮排／區塊以及內建（inline）兩種格式，來表示清單和雜湊表。以下展示幾種 YAML 的基本原件。

#### 清單（陣列）

習慣上清單比較常用區塊格式（block format）表示，也就是用短槓 + 空白字元作為起始。

另外還有一種內建格式（inline format）可以選擇──用方括號圍住，並用逗號 + 空白區隔（類似 JSON 的語法）。

#### 關聯陣列

鍵值和資料由冒號及空白字元分開。區塊形式（常使用於 YAML 資料文件中）使用縮進和換行符分隔 **key: value** 對。內建形式（常使用於 YAML 資料串流中）在大括號中使用逗號 + 空白字元分隔 **key: value** 對。

#### 區塊的字元

再次強調，字串不需要包在引號之內。

有兩種語法可以書寫多行文字（multi-line strings），一種為保留換行（使用 `|` 字元），另一種為摺疊換行（使用 `>` 字元）。兩種語法在其特殊字元之後都必須接著換行。

##### 保留換行 (Newlines preserved)

根據預設，每行開頭的縮排（以首行為基準）和行末空白會被去除，而不同的縮排會保留差異。

##### 摺疊換行 (Newlines folded)

和保留換行不同的是，只有空白行才視為換行，原本的換行字元會被轉換成空白字元，而行首縮排會被去除。

#### 階層化的元素

##### 於清單中使用雜湊表

##### 於雜湊表中使用清單

### YAML 的進階元件

這部分算是一個後續的討論，在比較各種數資料列語言時，YAML 最常被提到的特色有兩個：關係樹和資料形態。

#### 樹狀結構之間的互動參照

##### 資料合併和參考

為了維持檔案的簡潔，並避免資料輸入的錯誤，YAML 提供了節點參考（\*）和雜湊合併（<<）參考到其他節點標籤的錨點標記（&）。參考會將樹狀結構加入錨點標記的內容，並可以在所有資料結構中運作（可以參考上面 "ship-to" 的範例）合併只有雜湊表可以使用，可以將鍵值自錨點標記複製到指定的雜湊表中。

當資料被 instantiate 合併和參考會被剖析器自動展開。

#### 資料形態

由於自動判定資料形態的功能，嚴格型態（也就是使用者有宣告的資料形態）很難在大部分的 YAML 檔案中看到。資料型態可以被區分成三大類：原碼（core），定義（defined），使用者定義（user-defined）。原碼可以自動被解析器分析（例如：浮點數，整數，字串，清單，對映，...）。有一些進階的資料形態──例如位元資料──在 YAML 中有被「定義」，但不是每一種解析器都有支援。最後，YAML 支援使用者自訂的區域變數，包括：自訂的類別，結構或基本型態（例如：四倍精度的浮點數）。

##### 強迫轉型

YAML 的自動判定資料形態是哪一種實體。但有時使用者會想要將資料強迫轉型成自訂的某種型態。最常見的狀況是字串，有時候可能看起來像數字或布林值，這種時候可以使用雙引號，或是使用嚴格型態標籤。

##### 其他特殊資料形態

除了一般的資料形態之外，使用者也可以使用一些較為進階的型態，但不保證可被每種解析器分析。使用時和強迫轉型類似，要在形態名稱之前加上兩個驚嘆號（!!）。有幾種重要的形態在本篇沒有討論，包括集合（sets），有序映照（ordered maps），時間戳記（timestamps）以及十六進位資料（hexadecimal）。下面這個範例則是位元資料（binary）

##### 使用者自行擴充的資料形態

許多 YAML 的實現允許使用者自訂資料形態。在將一個物件序列化時，這個方法還頗方便的。某些區域資料形態可能不存在預設的資料形態中，不過這種型態在特定的 YAML 應用程式中是有定義的。這種區域資料形態用驚嘆號（**`!`**）表示。

### 語法

在 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。

相反的，要將 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 相關的函式庫:

### 常見錯誤與使用細節

* **編輯器：**
  * 建議使用能將跳格字元自動轉換成空白字元的編輯器，並且使用定寬度的字型。
  * 編輯器要能正確的處理 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

## 注釋

## 外部連結

* YAML.org （頁面存檔備份，存於網際網路檔案館）
* YAML Specification （頁面存檔備份，存於網際網路檔案館）
* YAML Cookbook--Equivalent data structures in YAML and Ruby
* YAML in Five Minutes （頁面存檔備份，存於網際網路檔案館）
* YAML improves on XML （頁面存檔備份，存於網際網路檔案館） Intro to YAML in Python
* YAML as a superset of JSON
* Kwalify Schema definition for YAML （頁面存檔備份，存於網際網路檔案館）
* Lists in 5 minutes （頁面存檔備份，存於網際網路檔案館）
* YAML Validator （頁面存檔備份，存於網際網路檔案館）