v1.0.0
7/10/2018 日掲載 – テキスト版

TOML

トムの明瞭で最小の言語。 (By Tom Preston Werner)

最新版: v0.5.0.

注: このリポジトリのmasterブランチは最新の開発版を指しており、 リリース版とは異なる仕様や変更が盛り込まれている可能性があります。 特定のバージョンに関する仕様についてはversionsディレクトリ以下を参照してください。

バージョン0.5.0になり、TOMLの仕様は非常に安定しています。 将来出るバージョン1.0.0の目標として可能な限りの0.5.0との後方互換性を目指しています。1.0.0への移行をシンプルにするため、全てのTOMLの実装は0.5.0に準拠するよう推奨されます。

目的

TOMLは明瞭なセマンティクスを持ち、可読性の高い、ミニマルな設定ファイルフォーマットとなることを目的として作られています。TOMLは曖昧さなしに連想配列に変換できるよう設計されていて、 様々な言語上でそれらのデータ構造に展開することが出来ます。

# TOMLドキュメントの例です。

title = "TOML Example"

[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # 日付はファーストクラスのデータ型です。

[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true

[servers]

  # タブもしくはスペースで自由にインデントできます。
  [servers.alpha]
  ip = "10.0.0.1"
  dc = "eqdc10"

  [servers.beta]
  ip = "10.0.0.2"
  dc = "eqdc10"

[clients]
data = [ ["gamma", "delta"], [1, 2] ]

# 配列内の改行ももちろんOK!
hosts = [
  "alpha",
  "omega"
]

仕様

  • TOMLはケース・センシティブです
  • TOMLファイルはユニコード(UTF-8)でエンコードされている必要があります
  • 空白はタブ(0x09)もしくはスペース(0x20)のことです
  • 改行はLF(0x0A)もしくはCRLF(0x0D0A)です。

コメント

ハッシュ記号(#)に続けて改行までをコメントとします。

# 好きなようにコメントできます。
key = "value" # 行末までコメントです。

キーと値の組

TOML文書の最も基本的な構造はキーと値の組からなります。

キーは等号(=)の左に、値は右に記述します。 キーと値の周りにある空白は無視されます。 キー、等号、値は同じ行に入れる必要があります(いくつかのタイプの値は複数行で記述される場合があります)。

key = "value"

値は、文字列、整数、浮動少数、ブーリアン、日時、配列もしくはインライン・テーブルのいずれかのデータ型でなければなりません。未定義の値は不正となります。

key = # 不正

キー

キーはベア・キー、クォーテッド・キー、ドッテッド・キーのいずれかになります。

ベア・キーは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"  # 不正です
"" = "blank"     # 可能ですがお奨めしません
'' = 'blank'     # 可能ですがお奨めしません

ドッテッドキーはドット(.)で接続されたベア・キーもしくはクォーテッド・キーの連なりです。近い属性同士をまとめるために用いることが出来ます。

name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true

JSONで記述すると、上記のデータは以下のような構造になります。

{
  "name": "Orange",
  "physical": {
    "color": "orange",
    "shape": "round"
  },
  "site": {
    "google.com": true
  }
}

ドットで分けられたそれぞれの部分の周りに空白を入れても無視されます。しかしながら、ベスト・プラクティスは空白で囲んだりはしないことです。

キーを複数回定義することは不正です。

# やらないでくださいね
name = "Tom"
name = "Pradyun"

(クォーテッド・キーの部分となる)キーは、値との組が直に定義されていない限り、そのキーを再度記述したり、キーの下で更にキーを生やしたりすることが出来ます。

a.b.c = 1
a.d = 2
# 以下は不正となります。
a.b = 1
a.b.c = 2

訳注:ドッテッド・キーは階層構造をとるため、末端のキーより上の階層のキーに新たに別のキーを子として生やしても構いません。末端のキーはすでに値をアサインしてしまっているため、再度記述することは不正になります。

文字列

文字列を記述するには、4種類の方法があります。基本文字列、複数行基本文字列、リテラル文字列、複数行リテラル文字列です。

基本文字列はクォーテーションマーク(")で囲まれた文字列です。 クォーテーションマーク、バックスラッシュ、制御文字(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)

全てのユニコード文字は\uXXXXもしくは\UXXXXXXXXの形式にエスケープできます。エスケープコードは正しいユニコード・スカラ値である必要があります.

上記以外のエスケープシーケンスは将来のために予約されていて、もし使ってしまった場合はTOMLはエラーを出すでしょう。

ときにはあなたは文書の一節を書いたり(例: 翻訳文書)、とても長い文を改行したくなることがあるでしょう。TOMLはそのようなときの手間を省くことが出来ます。

複数行文字列はクォーテーションマーク3つずつで囲むことで表現できます。文字列の頭にすぐ改行が来た場合はその改行は取り除かれます。その他の空白と改行はそのまま保持されます。

str1 = """
Roses are red
Violets are blue"""

TOMLのパーサは改行をそのプラットフォームに応じて自由に正規化出来ます。

# Unixでは上記のTOMLファイルは以下と同じパース結果になります:
str2 = "Roses are red\nViolets are blue"

# Windowsでは上記のTOMLファイルは以下と同じパース結果になります:
str3 = "Roses are red\r\nViolets are blue"

長い文字列を不要な行頭の空白なしに書きたい場合は、\を行末に書きます。\は全ての空白(もしくは改行)を、空白でない文字が現れるまで取り除きます。もし文字列の最初の文字が\だった場合は、全ての空白文字列と改行を、次の空白でない文字が現れるか、文字列の終わりまで、取り除きます。全てのエスケープシーケンスは基本文字列と同様に複数行文字列でも使えます。

# 以下のそれぞれの文字列は同じとなります:
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.\
       """

使える文字は、バックスラッシュと制御文字(U+0000 〜 U+001F、U+007F)以外の全てのユニコード文字です。バックスラッシュと制御文字はエスケープする必要があります。クォーテーションマークは複数行文字列の終了を避けるため以外の目的でエスケープする必要はありません。

あなたがWindowsパスや正規表現を書くことが多い場合、バックスラッシュをエスケープすることは、面倒になったり、間違いやすくなったりします。そのような場合、TOMLはエスケープなしのリテラル形式の文字列をサポートしています。

リテラル文字列はシングル・クォート(')で囲む必要があります。基本文字列のように一行に書きます:

# そのままの文字列を得ることが出来ます.
winpath  = 'C:\Users\nodejs\templates'
winpath2 = '\\ServerX\admin$\system32\'
quoted   = 'Tom "Dubs" Preston-Werner'
regex    = '<\i\c*\s*>'

エスケープが無いため、シングル・クォートはリテラル文字列中では書けません。そのような場合、TOMLはリテラル文字列の複数行版をサポートしています。

複数行リテラル文字列はシングル・クォート3つずつで囲まれていて、改行も許します。リテラル文字列と同様エスケープはありません。文字列の頭の改行は取り除かれます。他の文字列の中身は全て変更なしに読み込まれます。

regex2 = '''I [dw]on't need \d{2} apples'''
lines  = '''
最初の一行は取り除かれて
文字列に展開されます。
その他の空白、改行文字は
保持されます。
'''

タブを除く制御文字をリテラル文字列に使うことは出来ません。 よって、バイナリデータを扱う際には、Base64か、他の適切なASCIIもしくはUTF-8のエンコーディング形式でエンコードすることを推奨します。そして、それらのエンコーディングは(TOMLを読み込む)アプリケーション側で取り扱う必要があります。

整数

整数は全ての数のことです(訳注:整数全体のことだと思われる)。正の数を表すときはプラス符号+を前につけても、つけなくても構いません。負の数の場合はマイナス符号-を前につけます。

int1 = +99
int2 = 42
int3 = 0
int4 = -17

大きな数字を表記するために、あなたはアンダースコアを使うことも出来ます。それぞれのアンダースコアは最低1つの数字で囲む必要があります。

int5 = 1_000
int6 = 5_349_221
int7 = 1_2_3_4_5     # 可能ですがお奨めしません

(10進数のゼロ以外の)整数の表記をゼロから始めることは出来ません。-0+0については許容され、プレフィックスなしのゼロと同じ値となります。

正の整数は2進数、8進数、16進数の形式で表すことも出来ます。 これらの表記では(プレフィックスの後に)ゼロを頭にして続けることが出来ます。16進数を表す場合大文字小文字は問いません。アンダースコアは数字の間に用いることは出来ますが、プレフィックスとの間に入れることは出来ません。

# 16進数表記はプレフィックス`0x`をつけます
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef

# 8進数表記はプレフィックス`0o`をつけます
oct1 = 0o01234567
oct2 = 0o755 # Unixのファイルパーミッションを表すのに便利です

# 2進数表記はプレフィックス`0b`をつけます
bin1 = 0b11010110

許容される範囲としては、64bit(signed long)となります(−9,223,372,036,854,775,808 〜 9,223,372,036,854,775,807)。

浮動小数点数

浮動小数点数はIEEE754 64ビット倍精度で実装されます。

小数は整数部(整数型と同じルールで記述)と、それに続く小数部もしくは指数部から成ります。小数部と指数部の両方で表すことも出来ますが、その場合は小数部を指数部より前に置く必要があります。

# 小数表記
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01

# 指数表記
flt4 = 5e+22
flt5 = 1e6
flt6 = -2E-2

# 複合
flt7 = 6.626e-34

小数部は小数点の後に数字をならべて表記します。

指数部はE(大文字小文字は問わない)の後に整数(整数型と同じルールで記述)で表記します。

整数と同様、あなたは可読性のためにアンダースコアを使うことも出来ます。それぞれのアンダースコアは最低1つの数字で囲む必要があります。

flt8 = 9_224_617.445_991_228_313

-0.0+0.0は許容され、IEEE754に従って実値に展開されます。

以下の特別な浮動小数点数も記述することが出来ます。 これらを記述する場合は小文字でなければいけません。

# 無限大
sf1 = inf  # 正の無限大
sf2 = +inf # 正の無限大
sf3 = -inf # 負の無限大

# 非数
sf4 = nan  # sNaNかqNaNかは実装依存です
sf5 = +nan # `nan`と同じ
sf6 = -nan # 許容されますが、展開は実装依存です

ブーリアン

ブーリアン値はただのトークンです(皆がいつも使っているやつです)。小文字のみとします。

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 section 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 ] # 不正

配列は複数行に書くことも出来ます。最後の要素の後ろにカンマを置くことも出来ます。改行やコメントは値や閉じ括弧の前に好きなだけ置くことが出来ます。

arr7 = [
  1, 2, 3
]

arr8 = [
  1,
  2, # OK
]

テーブル

テーブル(ハッシュテーブルや連想配列のことです)はキーと値の組からなる集まりです。それは角括弧で囲まれたテーブル名が書かれた行から始まります。配列は必ず(キーと組になった)値として表記されるので、テーブルの角括弧と配列は簡単に区別することが出来ます。

[table]

ここに続いて、次のテーブルの開始か、ファイルの終わりまで、キーと値はこのテーブルに属します。 テーブル内のキーと値の各ペアの順番は保証されません。

[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]            # ベスト・プラクティスです
[ d.e.f ]          # [d.e.f]と同じ
[ g .  h  . i ]    # [g.h.i]と同じ
[ j . "ʞ" . 'l' ]  # [j."ʞ".'l']と同じ

もし、上位のテーブルそのものを記述する必要がないのであれば、省略することも出来ます。

# [x] 省略可
# [x.y] これも可
# [x.y.z] これも省略可
[x.y.z.w] # ここから始めて構いません

空のテーブルは単純にキーと値のペアを書かかないことで作れます。

キーと同様にテーブルも同じ名前で複数回定義することは出来ません。 もしそうした場合不正となります。

# やらないでくださいね

[a]
b = 1

[a]
c = 2
# やっちゃダメですってば

[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" }
      ]
    }
  ]
}

すでに値として定義された配列に対して、テーブルの配列を追加しようとする行為はパース時にエラーとなります。 仮にそのデータ型が同じであってもです。

# 不正です
fruit = []

[[fruit]] # エラーになります

既にテーブルの配列として定義されたテーブルの後に、同じ名前を持つ通常のテーブルを定義しようとした場合、パース時にエラーとなります。

# 不正なTOMLドキュメント
[[fruit]]
  name = "apple"

  [[fruit.variety]]
    name = "red delicious"

  # このテーブルは上記のテーブルの配列と競合します
  [fruit.variety]
    name = "granny smith"

ファイル名(拡張子)

TOMLのファイルは.tomlという拡張子を付ける必要があります。

MIME Type

インターネット経由でTOMLファイルを転送する場合、ふさわしいMIMEタイプはapplication/tomlです。

他のフォーマットとの比較

いくつかの側面ではTOMLはJSONにとても似通っています。 シンプルで、仕様がよく定義されており、どこにでもあるデータ型に変換するのが簡単です。 JSONはコンピューター・プログラムが読み書きするデータをシリアライズするにはぴったりのフォーマットです。TOMLがJSONと異なるのは、人間が読み書きするのにやさしいフォーマットというところに重点を置いているところです。コメントが良い例です。それらはプログラムがデータをやり取りする上では何の意味も持ちません。ですが設定ファイルを人が手で編集するときにはとても助けになるのです。

YAMLフォーマットはTOMLのように設定ファイルを記述するのに向いています。しかし、多くの場合、YAMLは複雑すぎる選択肢となってしまっています。TOMLは、YAMLの仕様とは真逆のシンプルさを目標としています。

INIフォーマットもまた設定ファイルを記述するのによく使われています。しかし、このフォーマットは標準化されていませんし、1つか2つのネストを超える複雑さを扱うには向いていません。

貢献について

ドキュメント化、バグレポート、プルリクエスト、その他のコントリビューションは常に歓迎しています!

Wiki

私達にはOfficial TOML Wikiがあります。 そこには以下の情報が集まっています。

  • TOMLを使っているプロジェクトの一覧
  • TOMLの実装の一覧
  • TOMLのバリデータの一覧
  • TOMLのエンコーダーとデコーダの言語非依存のテストスイートの一覧
  • エディタ・サポートの一覧
  • エンコーダの一覧
  • コンバーターの一覧

これらのリストを参照したり、内容を追加したい場合はぜひWikiを御覧ください。

TOMLコミュニティの一員でいてくれてありがとうございます!