TOML v0.5.0
Tom 的直觀、極簡語言。
作者:Tom Preston-Werner。
自版本 0.5.0 起,TOML 應被視為極為穩定。目標是讓版本 1.0.0 向後相容於版本 0.5.0(在人類能力範圍內)。強烈建議所有實作都相容於 0.5.0,以便在版本 1.0.0 推出時,轉換過程能更為順利。
目標
TOML 的目標是成為一種極簡的設定檔格式,由於語意直觀,因此容易閱讀。TOML 的設計目的是要能明確地對應到雜湊表。TOML 應易於解析為各種語言中的資料結構。
範例
# This is a TOML document.
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# Indentation (tabs and/or spaces) is allowed but not required
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [ ["gamma", "delta"], [1, 2] ]
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
]
規格
- TOML 區分大小寫。
- TOML 檔案必須是有效的 UTF-8 編碼 Unicode 文件。
- 空白字元表示 tab(0x09)或空白(0x20)。
- 換行符號表示 LF(0x0A)或 CRLF(0x0D0A)。
註解
雜湊符號標示該行剩餘部分為註解。
# This is a full-line comment
key = "value" # This is a comment at the end of a line
金鑰/值對
TOML 文件的主要建構區塊是金鑰/值對。
金鑰位於等號符號的左側,而值位於右側。金鑰名稱和值周圍的空白字元會被忽略。金鑰、等號符號和值必須在同一行(儘管某些值可以斷行成多行)。
key = "value"
值必須為下列類型之一:字串、整數、浮點數、布林值、日期時間、陣列或內嵌表格。未指定的值無效。
key = # INVALID
金鑰
金鑰可以是未加引號、加引號或點分。
未加引號的金鑰只能包含 ASCII 字母、ASCII 數字、底線和連字號(A-Za-z0-9_-
)。請注意,未加引號的金鑰可以只由 ASCII 數字組成,例如 1234
,但永遠會被解釋為字串。
key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value"
加引號的金鑰遵循與基本字串或字面字串完全相同的規則,並允許您使用更廣泛的金鑰名稱。最佳作法是在絕對必要時才使用未加引號的金鑰。
"127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value"
未加引號的金鑰不能為空,但允許加引號的金鑰為空(儘管不建議這麼做)。
= "no key name" # INVALID
"" = "blank" # VALID but discouraged
'' = 'blank' # VALID but discouraged
點綴的鍵是一連串的裸鍵或帶引號的鍵,以點號連接。這允許將類似的屬性分組在一起
name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true
在 JSON 領域中,這將提供以下結構
{
"name": "Orange",
"physical": {
"color": "orange",
"shape": "round"
},
"site": {
"google.com": true
}
}
點分隔部分周圍的空白會被忽略,但是,最佳做法是不使用任何多餘的空白。
多次定義一個鍵是無效的。
# DO NOT DO THIS
name = "Tom"
name = "Pradyun"
只要一個鍵尚未被直接定義,你仍然可以寫入它和它裡面的名稱。
a.b.c = 1
a.d = 2
# THIS IS INVALID
a.b = 1
a.b.c = 2
字串
有四種表達字串的方法:基本、多行基本、字面和多行字面。所有字串都必須只包含有效的 UTF-8 字元。
基本字串用引號包圍。任何 Unicode 字元都可以使用,除了必須跳脫的字元:引號、反斜線和控制字元(U+0000 到 U+001F、U+007F)。
str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."
為了方便,一些熱門字元有緊湊的跳脫序列。
\b - backspace (U+0008)
\t - tab (U+0009)
\n - linefeed (U+000A)
\f - form feed (U+000C)
\r - carriage return (U+000D)
\" - quote (U+0022)
\\ - backslash (U+005C)
\uXXXX - unicode (U+XXXX)
\UXXXXXXXX - unicode (U+XXXXXXXX)
任何 Unicode 字元都可以用 \uXXXX
或 \UXXXXXXXX
形式跳脫。跳脫碼必須是有效的 Unicode 純量值。
上面未列出的所有其他跳脫序列都是保留的,如果使用,TOML 應產生錯誤。
有時你需要表達文字段落(例如翻譯檔)或希望將很長的字串分成多行。TOML 讓這變得容易。
多行基本字串兩側都有三個引號,並允許換行。開頭分隔符號後面的換行符號將被修剪。所有其他空白和換行字元保持不變。
str1 = """
Roses are red
Violets are blue"""
TOML 解析器應該可以自由地將換行符號標準化為對其平台有意義的任何內容。
# On a Unix system, the above multi-line string will most likely be the same as:
str2 = "Roses are red\nViolets are blue"
# On a Windows system, it will most likely be equivalent to:
str3 = "Roses are red\r\nViolets are blue"
要撰寫長字串而不會引入多餘的空白,請使用「行尾反斜線」。當一行上最後一個非空白字元為 \
時,它將與所有空白(包括換行符號)一起被修剪,直到下一個非空白字元或關閉分隔符號。所有對基本字串有效的跳脫序列也對多行基本字串有效。
# The following strings are byte-for-byte equivalent:
str1 = "The quick brown fox jumps over the lazy dog."
str2 = """
The quick brown \
fox jumps over \
the lazy dog."""
str3 = """\
The quick brown \
fox jumps over \
the lazy dog.\
"""
任何 Unicode 字元都可以使用,除了必須跳脫的字元:反斜線和控制字元(U+0000 到 U+001F、U+007F)。引號不需要跳脫,除非它們的存在會產生過早的關閉分隔符號。
如果您經常指定 Windows 路徑或正規表示式,那麼必須跳脫反斜線會很快變得乏味且容易出錯。為了提供協助,TOML 支援完全不允許跳脫的文字字串。
文字字串以單引號包圍。與基本字串一樣,它們必須出現在單一行上
# What you see is what you get.
winpath = 'C:\Users\nodejs\templates'
winpath2 = '\\ServerX\admin$\system32\'
quoted = 'Tom "Dubs" Preston-Werner'
regex = '<\i\c*\s*>'
由於沒有跳脫,因此無法在以單引號包圍的文字字串中撰寫單引號。幸運的是,TOML 支援解決此問題的多行版本文字字串。
多行文字字串兩側都以三個單引號包圍,並允許換行。與文字字串一樣,完全沒有跳脫。緊接在開啟分隔符號後的換行會被修剪。分隔符號之間的所有其他內容都會照樣解譯,不進行修改。
regex2 = '''I [dw]on't need \d{2} apples'''
lines = '''
The first newline is
trimmed in raw strings.
All other whitespace
is preserved.
'''
文字字串中不允許使用 tab 以外的控制字元。因此,對於二進位資料,建議您使用 Base64 或其他適當的 ASCII 或 UTF-8 編碼。該編碼的處理方式將取決於應用程式。
整數
整數是整數。正數前面可以加上正號。負數前面加上負號。
int1 = +99
int2 = 42
int3 = 0
int4 = -17
對於大數字,您可以在數字之間使用底線來增強可讀性。每個底線兩側都必須至少有一個數字。
int5 = 1_000
int6 = 5_349_221
int7 = 1_2_3_4_5 # VALID but discouraged
不允許前導零。整數值 -0
和 +0
有效,且與未加前綴的零相同。
非負整數值也可以用十六進位、八進位或二進位表示。在這些格式中,允許前導零(在字首之後)。十六進位值不分大小寫。數字之間允許使用底線(但在字首和值之間不允許)。
# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef
# octal with prefix `0o`
oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions
# binary with prefix `0b`
bin1 = 0b11010110
預期 64 位元(有號長整數)範圍(−9,223,372,036,854,775,808 到 9,223,372,036,854,775,807)。
浮點數
浮點數應實作為 IEEE 754 binary64 值。
浮點數包含一個整數部分(遵循與整數值相同的規則),後接小數部分和/或指數部分。如果小數部分和指數部分都存在,則小數部分必須在指數部分之前。
# fractional
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01
# exponent
flt4 = 5e+22
flt5 = 1e6
flt6 = -2E-2
# both
flt7 = 6.626e-34
小數部分是小數點後接一個或多個數字。
指數部分是大寫或小寫的 E,後接整數部分(遵循與整數值相同的規則)。
與整數類似,您可以使用底線來增強可讀性。每個底線兩側都必須至少有一個數字。
flt8 = 9_224_617.445_991_228_313
浮點數值 -0.0
和 +0.0
有效,且應根據 IEEE 754 進行對應。
也可以表示特殊浮點數值。它們總是小寫。
# infinity
sf1 = inf # positive infinity
sf2 = +inf # positive infinity
sf3 = -inf # negative infinity
# not a number
sf4 = nan # actual sNaN/qNaN encoding is implementation specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation specific
布林值
布林值只是您習慣的代碼。總是小寫。
bool1 = true
bool2 = false
偏移日期時間
若要明確表示特定時間點,您可以使用 RFC 3339 格式的日期時間和偏移量。
odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00
為了可讀性,您可以用空格取代日期和時間之間的 T 分隔符號(如 RFC 3339 第 5.6 節所允許)。
odt4 = 1979-05-27 07:32:00Z
小數秒的精確度取決於實作,但預期至少有毫秒精確度。如果值包含實作無法支援的更高精確度,則必須截斷額外的精確度,而不是四捨五入。
當地日期時間
如果您從 RFC 3339 格式的日期時間中省略偏移量,它將表示給定的日期時間,而不與任何偏移量或時區相關。在沒有其他資訊的情況下,無法將其轉換為時間點。如果需要,轉換為時間點取決於實作。
ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999
小數秒的精確度取決於實作,但預期至少有毫秒精確度。如果值包含實作無法支援的更高精確度,則必須截斷額外的精確度,而不是四捨五入。
當地日期
如果您僅包含 RFC 3339 格式的日期時間的日期部分,它將表示整個那天,而不與任何偏移量或時區相關。
ld1 = 1979-05-27
當地時間
如果您只包含 RFC 3339 格式日期時間的時間部分,它將表示該時間,而不與任何特定日期或任何偏移量或時區有關。
lt1 = 07:32:00
lt2 = 00:32:00.999999
小數秒的精確度取決於實作,但預期至少有毫秒精確度。如果值包含實作無法支援的更高精確度,則必須截斷額外的精確度,而不是四捨五入。
陣列
陣列是包含值在內的方括號。空格會被忽略。元素以逗號分隔。資料類型不能混用(定義字串的不同方式應被視為同種類型,具有不同元素類型的陣列也應如此)。
arr1 = [ 1, 2, 3 ]
arr2 = [ "red", "yellow", "green" ]
arr3 = [ [ 1, 2 ], [3, 4, 5] ]
arr4 = [ "all", 'strings', """are the same""", '''type''']
arr5 = [ [ 1, 2 ], ["a", "b", "c"] ]
arr6 = [ 1, 2.0 ] # INVALID
陣列也可以是多行的。陣列最後一個值之後的終止逗號(也稱為尾隨逗號)是可以的。在值和關閉括號之前可以有任意數量的換行符和註解。
arr7 = [
1, 2, 3
]
arr8 = [
1,
2, # this is ok
]
表格
表格(也稱為雜湊表或字典)是鍵值對的集合。它們出現在單獨一行的方括號中。您可以將它們與陣列區分開來,因為陣列永遠只會是值。
[table]
在該表格下方,直到下一個表格或 EOF 是該表格的鍵值。表格中的鍵值對不能保證以任何特定順序出現。
[table-1]
key1 = "some string"
key2 = 123
[table-2]
key1 = "another string"
key2 = 456
表格的命名規則與鍵相同(請參閱上面鍵的定義)。
[dog."tater.man"]
type.name = "pug"
在 JSON 領域中,這將提供以下結構
{ "dog": { "tater.man": { "type": { "name": "pug" } } } }
鍵周圍的空格會被忽略,但是,最佳做法是不使用任何多餘的空格。
[a.b.c] # this is best practice
[ d.e.f ] # same as [d.e.f]
[ g . h . i ] # same as [g.h.i]
[ j . "ʞ" . 'l' ] # same as [j."ʞ".'l']
如果您不想要,您不需要指定所有超級表格。TOML 知道如何為您執行此操作。
# [x] you
# [x.y] don't
# [x.y.z] need these
[x.y.z.w] # for this to work
允許空表格,並且其中根本沒有鍵值對。
與鍵一樣,您不能定義任何表格超過一次。這樣做是無效的。
# DO NOT DO THIS
[a]
b = 1
[a]
c = 2
# DO NOT DO THIS EITHER
[a]
b = 1
[a.b]
c = 2
內嵌表格
內嵌表格提供更簡潔的語法來表達表格。它們對於可以快速變得很冗長的群組資料特別有用。內嵌表格用大括號 {
和 }
括起來。在大括號內,可以出現零個或多個以逗號分隔的鍵值對。鍵值對採用與標準表格中的鍵值對相同的形式。允許所有值類型,包括內嵌表格。
內嵌表格旨在出現在單一行上。除非它們在值內有效,否則在大括號之間不允許換行符。即便如此,強烈建議不要將內嵌表格拆分為多行。如果您發現自己被這種慾望所困擾,這表示您應該使用標準表格。
name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" }
上面的內嵌表格與以下標準表格定義相同
[name]
first = "Tom"
last = "Preston-Werner"
[point]
x = 1
y = 2
[animal]
type.name = "pug"
表格陣列
尚未表達的最後一個類型是表格陣列。這些可以使用雙括號中的表格名稱來表達。具有相同雙括號名稱的每個表格將是陣列中的元素。表格按遇到的順序插入。沒有任何鍵值對的雙括號表格將被視為空表格。
[[products]]
name = "Hammer"
sku = 738594937
[[products]]
[[products]]
name = "Nail"
sku = 284758393
color = "gray"
在 JSON 領域中,這將為您提供以下結構。
{
"products": [
{ "name": "Hammer", "sku": 738594937 },
{ },
{ "name": "Nail", "sku": 284758393, "color": "gray" }
]
}
您也可以建立表格的巢狀陣列。只要在子表格上使用相同的雙括弧語法即可。每個雙括弧子表格都將屬於其上方最近定義的表格元素。
[[fruit]]
name = "apple"
[fruit.physical]
color = "red"
shape = "round"
[[fruit.variety]]
name = "red delicious"
[[fruit.variety]]
name = "granny smith"
[[fruit]]
name = "banana"
[[fruit.variety]]
name = "plantain"
上述 TOML 會對應到下列 JSON。
{
"fruit": [
{
"name": "apple",
"physical": {
"color": "red",
"shape": "round"
},
"variety": [
{ "name": "red delicious" },
{ "name": "granny smith" }
]
},
{
"name": "banana",
"variety": [
{ "name": "plantain" }
]
}
]
}
嘗試附加到靜態定義的陣列,即使該陣列是空的或具有相容類型,也必須在解析時產生錯誤。
# INVALID TOML DOC
fruit = []
[[fruit]] # Not allowed
嘗試使用與已建立陣列相同的名稱定義一般表格,也必須在解析時產生錯誤。
# INVALID TOML DOC
[[fruit]]
name = "apple"
[[fruit.variety]]
name = "red delicious"
# This table conflicts with the previous table
[fruit.variety]
name = "granny smith"
您也可以在適當的地方使用內嵌表格
points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ]
檔案名稱副檔名
TOML 檔案應使用副檔名 .toml
。
MIME 類型
在網際網路上傳輸 TOML 檔案時,適當的 MIME 類型為 application/toml
。
與其他格式比較
在某些方面,TOML 與 JSON 非常相似:簡單、有明確的規範,而且可以輕鬆對應到普遍的資料類型。JSON 非常適合序列化主要由電腦程式讀寫的資料。TOML 與 JSON 的不同之處在於它強調易於人類讀寫。註解是一個很好的範例:當資料從一個程式傳送至另一個程式時,註解沒有任何用途,但對於可能手動編輯的組態檔而言,註解非常有幫助。
YAML 格式與 TOML 一樣,都是以組態檔為導向。然而,在許多用途上,YAML 是一個過於複雜的解決方案。TOML 旨在追求簡潔,而這項目標在 YAML 規範中並不明顯:http://www.yaml.org/spec/1.2/spec.html
INI 格式也經常使用於組態檔。然而,該格式並未標準化,而且通常無法處理超過一或兩層的巢狀。
參與貢獻
歡迎提供文件、錯誤回報、提交請求,以及所有其他貢獻!
Wiki
我們有一個官方 TOML Wiki,其中彙整了以下事項
- 使用 TOML 的專案
- 實作
- 驗證程式
- TOML 解碼器和編碼器的與語言無關的測試套件
- 編輯器支援
- 編碼器
- 轉換器
如果您想檢視或新增到該清單,請務必瀏覽。感謝您成為 TOML 社群的一份子!