JSONにはなんで「コメント」を書けないの?

このサイトはアフィリエイト広告(Amazonアソシエイト含む)を掲載しています。
JSONのコメント行に×印を付け、Node.jsとPythonで読み込みエラーになる様子を描いたイメージ

標準JSONの文法にはそもそもコメントという要素が定義されていないから!

JSONの文法にはそもそも「コメント」という項目が存在しない

tsconfig.jsonやVS Codeのsettings.jsonでは//を使って気軽にメモを残せますよね。それに慣れていると自分のプロジェクトの設定ファイルにも同じ感覚でコメントを書いてエラーになった経験がある方もいるんじゃないでしょうか。

JSONという仕様にはコメントという概念が用意されていません。JSONの現行の仕様書であるRFC 8259の文法定義を見ると、JSONを構成する要素は次の3種類しかないと分かります。

  • 6種類の構造文字({ } [ ] : ,)
  • 文字列・数値
  • true・false・nullという3つのリテラル

この文法にコメントを表す記号は定義されていません。要素の間には空白・タブ・改行などを置けますが//の1行コメントも/* */の複数行コメントも使えません。そのため、コメントを含むテキストを標準JSONとして読み込むと文法エラーになります。

JSONとJavaScriptは似ているようで別物

JSONはJavaScript Object Notationという名前で、「JavaScript」が入っている通りJSONはJavaScriptのオブジェクトリテラルの記法をベースに作られています。RFC 8259でもJSONは最小限で移植しやすくテキストベースなJavaScriptのサブセットとして設計されたと説明されています。

JavaScriptのオブジェクトリテラルでは値に変数や計算式を使ったり、メソッドを定義したりできます。コードの途中にコメントを書くこともできます。

一方、JSONはデータを受け渡すための形式です。値として書けるのはオブジェクト・配列・文字列・数値・真偽値・nullに限られます。変数を参照したり関数を実行したりする書き方はできません。

JavaScriptでJSONを読み込むときは文字列をコードとして実行するeval()ではなくJSON用のJSON.parse()を使います。コメントが仕様から外された経緯は後の節で紹介します。

実際にコメント入りJSONをパースしてエラーを確認してみた

説明だけだとピンとこない部分もあると思うので実際に試してみました。次のようなコメント付きJSONを用意します。

test.json
{
  // これはコメントです
  "name": "chunlog"
}

このファイルをNode.jsのJSON.parse()で読み込んでみました。

コマンド(Node.js)
node -e "
try {
  JSON.parse(require('fs').readFileSync('test.json', 'utf8'));
} catch (e) {
  console.log(e.message);
}
"
実行結果
Expected property name or '}' in JSON at position 4 (line 2 column 3)

Pythonのjson.load()でも実行してみました。

コマンド(Python)
python3 -c "
import json
try:
    with open('test.json', encoding='utf-8') as f:
        json.load(f)
except Exception as e:
    print(type(e).__name__ + ': ' + str(e))
"
実行結果
JSONDecodeError: Expecting property name enclosed in double quotes: line 2 column 3 (char 4)

言語もエラーメッセージの文言も違いますが、どちらも「2行目、コメントを書いた場所」でつまずいているのが分かります。今回使ったJSON.parse()とPython標準のjson.load()はこのコメント記法を受け付けません。

コメントが外された経緯にもちゃんと理由がある

「コメントぐらい対応してくれてもいいのに」と思う方もいるかもしれません。実はこれ、うっかり仕様に入れ忘れたわけではなくJSONの考案者であるDouglas Crockford氏が意図的に外したものです。

2012年、Crockford氏は当時利用していたGoogle+(現在はサービス終了)への投稿でこの経緯を明かしています。それによると当時一部の開発者がJSONのコメント欄に「このパーサーはこう解釈して」といったパース時の挙動を制御するための指示を書き込む使い方をしていたそうです。パーサーの実装によってコメントの扱いがバラバラになってしまうと、せっかくのJSONの強みである「どの言語でも同じように読み書きできる」という相互運用性が崩れてしまいます。それを防ぐためにコメントという機能そのものを仕様から外した、という判断だったようです。

ちなみに同氏は「どうしても設定ファイルにメモを残したいなら好きなだけコメントを書いてから、JSONパーサーに渡す前にコメントを取り除くツールを一枚かませればいい」とも述べていて、当時公開していたJSMinというツールを例に挙げていました。この発想は後述する「コメント付きで書いて渡す前に取り除く」という代用テクニックにもそのままつながっています。

VS Codeの設定ファイルにある「JSONC」はJSONとは別物

とはいえ実際にはVS Codeのsettings.jsonやtasks.json、launch.jsonでは普通に//コメントが書けます。これらはJSONにコメントを追加できる拡張形式「JSONC(JSON with Comments)」として扱われているためです。

VS Codeには通常のJSONモードとは別に「JSON with Comments」というモードがあり、//と/* */のコメントを使えます。JSONCの末尾カンマへの対応は読み込み側の実装や設定によって異なります。VS Codeでは受け付けますがファイルの種類や適用されるスキーマによって警告の有無が変わります。

JSONCは標準JSONを拡張した形式で、RFC 8259やECMA-404が定めるJSONの文法には含まれません。VS Codeの言語モードを「JSON with Comments」に変更してもファイルを読み込むアプリまでJSONC対応になるわけではありません。コメント付きの内容をJSON.parse()やPython標準のjson.load()に渡すとエラーになります。

たとえばVS Codeのsettings.jsonにはコメントを書けますが、npmが読み込むpackage.jsonには書けません。同じ.jsonという拡張子でもコメントを使えるかは読み込み側の仕様で決まります。

似た立ち位置の仕様にコメントに加えてクォートなしキーやシングルクォート文字列まで許容する「JSON5」もあります。それぞれの違いを整理すると次の通りです。

項目JSONJSONCJSON5
標準化RFC 8259/ECMA-404JSONの拡張形式非標準(コミュニティ仕様)
コメント不可//・/* */が可能//・/* */が可能
末尾カンマ不可実装・設定による可能
キーのクォート省略不可不可可能
主な用途データ交換・Web APIVS Code関連の設定ファイル設定ファイル全般

どうしてもコメントを書きたいときの代用テクニックと注意点

設定を一時的に無効にする「コメントアウト」も標準JSONではできません。_commentに説明を追加しても元の設定はそのまま有効です。設定を止めたい場合は読み込み側が用意している無効化の方法を使います。項目の削除は必須項目かどうかと、省略したときの動作を確認してから行ってください。

標準JSONの範囲内でコメントっぽいことをしたい場合の代用テクニックも紹介します。よく使われるのは"_comment"や"//"のようなキーに説明文を持たせる方法です。

test2.json
{
  "_comment": "APIキーの設定です",
  "apiKey": "sample-key-123",
  "timeout": 30
}

これは標準JSONの文法に沿っているので当然エラーなくパースできます。実際に読み込んで中身を確認するとこんな結果になります。

Bash
node -e "
const data = JSON.parse(require('fs').readFileSync('test2.json', 'utf8'));
console.log(Object.keys(data));
"
実行結果
[ '_comment', 'apiKey', 'timeout' ]

当然といえば当然ですが、_commentが普通のデータとして紛れ込んでいるのが分かりますよね。見た目はコメントっぽくてもパーサーからすれば単なる1つのキーでしかありません。ですが、この代用テクニックには次のような副作用があります。

  • 全キーをループ処理するコードでコメント用のキーまで処理対象に含まれてしまう。
  • JSON Schemaで追加のキーが禁止されていてコメント用のキーも定義されていない場合は検証でエラーになる。
  • 同じオブジェクト内に_commentや//というキーを重複して書くと後の値だけが残るなど、読み込み側によって結果が変わる。

用途に応じて使い分けるならこんな整理になりそうです。

  • VS Codeの設定ファイルなど読み込み側がJSONCに対応していると分かっている場合は素直にJSONCとして書く。
  • 標準JSONとして配布する場合はコメント対応のツールで標準JSONへ変換し、変換後のファイルを確認してから渡す。末尾カンマも含む場合はコメントを削除するだけでは標準JSONにならない点に注意する。
  • _comment のようなキーを使う場合は、読み込み側やJSON Schemaがそのキーを許容することを確認する。名前を付けるだけで自動的に無視されるわけではない。

JSONがここまで普及した理由の一つは、この「余計な解釈の余地を残さない、徹底したシンプルさ」にあるのかもしれません。


ITに残る昔の名残や身近なルールの理由をほかにも知りたい方はIT雑学まとめから関連記事を探せます。

  • URLをコピーしました!