JSON構文チートシート
RFC 8259で定義されるJSONの構文は、6つの構造文字、4つの合法的なホワイトスペース文字、2つのコンテナ、6つの値の型、そして文字列と数値の厳格な文法に要約されます。このチートシートは、すべてのルールを1ページにまとめました。末尾カンマから16進リテラルまで、パーサーが拒否するミスの正確な姿も含めています。
JSON構文チートシートとは
JSONの文法全体はABNFなら数十行に収まり、現実のパースエラーはほぼすべて、十数個の具体的なミスのどれかです。このページはその知識のリファレンス版です。各セクションでは、文法の一片をRFC 8259が定義する通りに述べたうえで、そのルールをコピー可能なJSONとして示します。フォーマッターやバリデーターに貼り付けて、合格するか落ちるかを見られます。
一次資料が欲しいなら、3つの文書が重要です。RFC 8259は現行のインターネット標準。ECMA-404はEcma Internationalが発行する、同一内容の双子の標準です。そしてRFC 8259内部の数値文法は、ECMAScript仕様の数値文法から、8進と16進の拡張を取り除いたものを意図的に再利用しています。以下のすべてのルールは、この3つの源のどれかに遡れます——ここにあるのは慣習や伝承ではありません。
ルールは短いのに容赦がありません。寛容なJSONというものは存在しないのです。仕様に適合するパーサーは、文書を丸ごと受け入れるか、構文エラーで拒否します。そして拒否は、開発者が最も忘れがちな少数のルール——クォートのスタイル、末尾カンマ、コメント、先頭ゼロ——の周りに集中しています。以下で一度覚えれば、検証の失敗はほとんど謎ではなくなります。
ルールは、わざと破ってみるのが一番早く身につきます。このページを読みながらJSONフォーマッターを2つ目のタブで開いたままにして、このページの各サンプルをその場で再インデントしてみてください。
整形ではなく判定が欲しいときはJSONバリデーターが、ドキュメントが最初に破っているルールの正確な行と列を報告してくれます。
6つの構造文字
JSONの構造をすべて担うのは、6つの約物文字です。オブジェクトを包む波括弧{ }、配列を包む角括弧[ ]、キーと値を隔てるコロン:、そしてオブジェクト内のペアや配列内の値を隔てるカンマ,です。文法のほかの部分は構造的な役割を果たしません。ドキュメント内のその他の文字は、文字列の中にあるか、4つのホワイトスペース文字のどれかです。カンマは厳密に区切りです。2つの項目の間にのみ現れ、閉じ波括弧や閉じ角括弧の前に現れることはありません。
| 文字 | 名前 | 文法での役割 |
|---|---|---|
| { } | 波括弧 | オブジェクトを開いて閉じる——キーと値のペアの集合 |
| [ ] | 角括弧 | 配列を開いて閉じる——値の順序付きリスト |
| : | コロン | オブジェクト内でキーと値を隔てる |
| , | カンマ | ペアや配列の項目を隔てる——閉じ括弧の直前に置かれることは決してない |
有効——カンマは項目間にのみ
{"name":"Ada","tags":["math","pioneer"]}無効——閉じ括弧の前の末尾カンマ
{"name":"Ada","tags":["math","pioneer"],}ホワイトスペース:ちょうど4文字
文字列の外では、JSONが許すホワイトスペース文字はちょうど4つです。スペース(U+0020)、水平タブ(U+0009)、ラインフィード(U+000A)、キャリッジリターン(U+000D)。それ以外——垂直タブ、フォームフィード、ノーブレークスペース、バイトオーダーマーク——は、多くのエディタがそれらの文字を見えない形で表示するにもかかわらず、構文エラーです。だからこそ、ワープロから貼り付けたJSONはしばしば検証に失敗します。画面上はきれいに見えても、文法が知らない文字を含んでいるのです。
ホワイトスペースは、整形を可能にする存在でもあります。文法はトークン間のこの4文字を無視するため、同じドキュメントを、回線上では1つの長い行に、エディタではインデントされた木構造にでき、2つの形式は意味的に同一です——読み込んだあとは、どのパーサーにも区別がつきません。
最小化——任意のホワイトスペースなし
{"a":1,"b":[2,3]}整形済み——ホワイトスペースを追加、データは同じ
{
"a": 1,
"b": [
2,
3
]
}文字列:ダブルクォートと9つのエスケープ
JSONの文字列はダブルクォートで包まれます。シングルクォートは決して使いません。内側では、バックスラッシュ\がエスケープを導入し、RFC 8259は2文字のエスケープをちょうど9個定義しています。うち2つは必須です。リテラルのダブルクォートのための\\"と、リテラルのバックスラッシュのための\\\\。この2文字は、エスケープしなければ文字列を終わらせたり壊したりするためです。さらに6つは任意の短縮形——フォワードスラッシュのための\/と、テキストに最もよく現れる5つの制御文字のための\b \f \n \r \tです。9番目の形式が\uXXXXで、任意のUnicodeコードポイントを4桁の16進数で書きます。
エスケープの対象でない文字は、すべてUTF-8としてリテラルで書けます。そして2つの形式は等価です。パーサーはどちらでも同一の文字列を渡します。エスケープは表記であってデータではない——この点を、エスケープのガイドが詳しく掘り下げています。
| エスケープ | 生成される文字 | RFC 8259上の位置づけ |
|---|---|---|
| \" | ダブルクォート | 必須——文字列内でクォートを書く唯一の方法 |
| \\ | バックスラッシュ | 必須——リテラルのバックスラッシュを書く唯一の方法 |
| \/ | フォワードスラッシュ | 任意の短縮形。合法だがほとんど不要 |
| \b \f \n \r \t | バックスペース、フォームフィード、改行、復帰、タブ | よく使う5つの制御文字の名前付きエスケープ |
| \uXXXX | 任意のコードポイント。例:éは\u00e9 | 万能の形式——ちょうど4桁の16進数 |
ファイル内でのエスケープ形式
"quote": "she said \"hi\"" "path": "C:\\Users\\ada" "e-acute": "\u00e9"
パーサーが返すもの
quote: she said "hi" path: C:\Users\ada e-acute: é
数値:ECMAScriptから拡張を引いたもの
数値は、平易な記法の整数または小数で、指数を付けても構いません。RFC 8259はECMAScriptの数値文法を採用し、その拡張を取り除いています。16進なし、8進なし、先頭ゼロなし、先頭のプラスなし、後ろに点だけという形もなし。指数はeまたはEを使い、符号は付けても構いません。数値が始めてよい符号は、無地のハイフンマイナスだけです。NaN、Infinity、-InfinityはJSONではありません——そのような定数を持つ言語は、慣習として代わりにnullを書きます。
精度は意図的に実装に任されています。文法は、パーサーが何桁まで尊重しなければならないかを定めていないため、非常に長い数値は黙って変わって届くことがあります。相互運用可能な生成者は、整数を対象プラットフォームが正確に表現できる範囲に収めます。JavaScriptの背後にあるIEEE 754倍精度では、2^53 − 1までです。
| 記述 | 判定 | 理由 |
|---|---|---|
| 42, -17, 3.14 | 有効 | 素直な整数と小数の形式 |
| 2.1e10, 5E-3 | 有効 | 指数。eまたはE、その後の符号は任意 |
| 01, -01 | 無効 | 先頭ゼロは禁止——1と書く |
| 1., .5, +6 | 無効 | 点の両側には数字が必要。先頭のプラスも不可 |
| 0x1F, 1_000 | 無効 | 16進と桁区切りはJavaScriptの拡張 |
| NaN, Infinity | 無効 | 文法の一部ではない。JSONにそのような定数はない |
| 9007199254740993 | 要注意 | パースはできるが、IEEE 754倍精度の正確な整数範囲を超える |
3つのリテラルと5つの定番の拒否
値の種類を完成させるのは、素の3つのトークンです。true、false、そしてnull。すべて小文字で、クォートは付けません。True、FALSE、Noneは構文エラーであり、個性的な大文字小文字の使い方ではありません。この周囲に、現実に拒否される文書のほぼすべてを説明する5つの線が、文法には引かれています:
- コメントは禁止。RFC 8259にコメント構文はありません。//も/* */も、どこに現れても構文エラーです。フォーマットを自分で管理できる場所なら、"_comment"のような兄弟キーで注記してください。
- 末尾カンマは禁止。[1, 2, 3,]も{"a":1,}も無効です。どんなに親切そうに見えても——カンマは区切りであり、項目を無と隔てることはできません。
- シングルクォートと、クォートなきキーも禁止。{name:'ada'}は無効なJSONです。{"name":"ada"}が文法の唯一の書き方です。
- 重複キーは——公式には——禁止。文法は同じ名前が2回現れることを許しますが、どちらの値が勝つかはRFC 8259 §4が実装に委ねているため、重複に依存する文書には定義された意味がありません。
- トップレベルの値は任意。RFC 8259以降、文書全体が素の文字列、数値、ブーリアン、nullでも構いません。RFC 4627の「オブジェクトと配列のみ」ルールは廃止済みで、"hello"も42も完全なJSON文書です。
エンコーディング:UTF-8とバイトレベルのルール
RFC 8259 §8.1はバイトエンコーディングを確定しています。閉じたエコシステムの一部でないシステム間でやり取りされるJSONテキストは、UTF-8でエンコードしなければなりません。開かれた回線上にUTF-16やUTF-32のJSONは存在せず、生成者はバイトオーダーマークを先頭に付けてはいけません。パーサーは先頭のBOMをエラーにせず無視してもよいものの、仕様に適合するものはBOMを出力しません。層の分かれ方に注目してください。\uXXXXのエスケープは個々の文字列内での表記の選択であり、UTF-8は文書全体の性質です。2つは異なる問題を解決します。
これで文法は終わりです。ルールを体に染み込ませる最速の方法は、自分の文書を実際にぶつけてみることです。本物のペイロードを整形し、一度に1つずつルールを破り、バリデーターのエラーを1つずつ読む。10分のわざとらしい失敗は、このページの二回目の通読より多くを教えてくれます。
よくある質問
このページからリンクされたツールに、本物のAPIデータを貼り付けても大丈夫ですか?
はい。このサイトのフォーマッターとバリデーターは、完全にブラウザ内で動作します。文書はタブ内のJavaScriptでパースされ、監査すべきアップロード工程は存在しません。自分でも確認できます。ツールが動作している間、ブラウザのNetworkパネルは沈黙したままであり、さらにサイトのContent-Security-Policyが外向きの接続を遮断するため、改変されたページのコピーですらデータを送信できません。
JSONの文字列にシングルクォートは使えますか?
いいえ。RFC 8259は文字列をダブルクォートと定義しており、キーも値も同様です。シングルクォートにはまったく意味がありません。'hello'に遭遇したパーサーは即座に失敗し、"hello"だけが唯一の有効な書き方です。シングルクォートを快く読み取るツールは、JSONではなくJSON5や別のスーパーセットをパースしています。だからこそ、その出力はより厳格な受け手に拒否されうるのです。
末尾カンマとは正確には何で、なぜエラーになるのですか?
問題は文字ではなく位置です。2つの項目の間のカンマは区切りですが、}や]の直前のカンマは、項目を無と隔てることになり、文法はそれを禁じています。手で編集したファイルが検証に落ちる、単独で最多の理由です。だからこそ、生成器、ミニファイアー、整形ツールは、書き出す前に末尾カンマを皆取り除いてくれます。
JSONの数値に、007のような先頭ゼロを付けられないのはなぜですか?
先頭ゼロは、古いJavaScriptで8進(基数8)リテラルを書く方法だったからです。RFC 8259の数値文法はECMAScriptから取り、そこから8進と16進の拡張を取り除いています。そのため、1つの書き方が1つの値を意味し続けるよう、007は拒否されます。7と書いてください。先頭ゼロが値の一部である郵便番号のような識別子は、文字列として保存してください。
JSONオブジェクト内の重複キーは合法ですか?
文法は、同じ名前が2回現れることを許します。しかし規格は、結果の定義を意図的に拒んでいます。RFC 8259は、実装が最後の値、最初の値、またはエラーを報告しうると述べています。したがって、意味が重複に依存する文書は、相互運用可能なJSONではありません。たまたまお使いのパーサーが黙って受け入れるとしても、重複はバグとして扱ってください。
JSONの数値は、どのくらい大きくなると精度が壊れますか?
文法は桁数の上限を定めていません。しかし、ほとんどのパーサーはIEEE 754倍精度浮動小数点にデコードし、それは整数を2^53 − 1までしか正確に表現できません。9007199254740993のような17桁の識別子は、黙って別の数になって届くことがあります。64ビットのidを持つAPIのSDKが、数値ではなく文字列として扱うよう指示する、定番の理由です。