本文へスキップ
jsonbeautifiers
日本語

JSONバリデーター

すべてのエラーについて、正確な行・列・原因・直し方を表示します。

入力

貼り付けたものがブラウザの外に出ることはありません。 connect-src の許可リストにより、これは約束ではなくブラウザによる保証になっています。 自分で確かめる

検証が答えるのは「これは正しいJSONドキュメントか」という一点だけです。役に立つのは、答えが「いいえ」だったときの中身です。多くのバリデーターは「予期しないトークンです」とだけ告げて、あとは自分で探させます。このツールは、どの文字が、何行目の何列目で、代わりに何を期待していたのか、そしてどう直せばよいのかまで示します。

また、最初の問題で止まりません。4か所間違っているドキュメントは4件として報告されるので、4回ではなく1回の修正で済みます。

何をチェックしているか

RFC 8259の文法を、すべて。意外に思われる部分も含めてです。

空白
トークンの間に置けるのは、スペース・タブ・復帰・改行の4文字だけです。ノーブレークスペース、ゼロ幅スペース、全角スペースはいずれも構文エラーであり、このバリデーターは「予期しないトークン」ではなく、その文字の名前を示します。Webページ、PDF、チャットからJSONをコピーすると絶えず混入します。
数値
先頭のゼロ、先頭のプラス、16進数、末尾の小数点、NaN、Infinityはいずれも不可です。原因も直し方も違うので、違反ごとに個別のメッセージを出します。
文字列
使えるエスケープシーケンスは9種類だけです。U+0020未満の制御文字はエスケープが必要です。対になっていないサロゲートは警告として扱います。パースはできますが、UTF-8に再エンコードすると壊れるためです。
トップレベルの値はひとつ
ドキュメントが持てる値はちょうどひとつです。1行に1つずつ値が並んでいるのはNDJSONであり、このバリデーターはその形を認識して、汎用の「余分な内容」エラーではなくそう伝えます。

エラーではない警告

パースは通るのに午後を台無しにするものがあります。出力を止めないよう、別枠で報告します。

重複キー
RFC 8259はキーが一意であるべき(SHOULD)と述べるにとどまり、重複時の挙動は未定義です。JavaScriptとPythonは最後を採用し、Goやjavaの一部のパーサーはドキュメントごと拒否し、少数は最初を採用します。ここでは両方の位置が分かります。
安全範囲を超える整数
2^53-1を超えると、JavaScriptの数値ではその値を正確に保持できません。警告には、JSON.parseなら代わりに返してくる値が示されます。
バイトオーダーマーク
先頭のU+FEFFはここでは受け入れたうえで報告します。ブラウザやNodeのJSON.parseはこれを無条件に拒否するからです。
非常に深いネスト
このパーサーは反復型で深さ制限がありませんが、受け取る側の多くには制限があります。この環境での実測では、V8はおよそ4,800階層より深い構造のシリアライズを拒否します。読めるドキュメントが、書き戻せないドキュメントであることはあり得ます。

構文だけでなく構造も検証する

構文の検証で分かるのは、ドキュメントが整形式だということだけで、期待した内容が入っているかどうかは分かりません。それにはJSON Schemaが必要です。必須プロパティ、型、制約を記述できます。当サイトのスキーマ生成ツールは、サンプルのペイロードから出発点となるスキーマを作ります。

How to do this in code

コードで妥当性を確認し、そこから使えるエラー情報を取り出す方法です。

js JavaScript

標準ライブラリに例外を投げないバリデーターはないので、try/catchがそのままAPIになります。

function validate(text) {
  try {
    JSON.parse(text);
    return { ok: true };
  } catch (e) {
    // Modern V8 includes a (line L column C) suffix in the message.
    return { ok: false, message: e.message };
  }
}
py Python

JSONDecodeErrorはmsg、lineno、colno、pos、docを持っており、たいていのランタイムより構造化された情報が得られます。

import json

try:
    json.loads(text)
except json.JSONDecodeError as e:
    print(f"{e.msg} at line {e.lineno} column {e.colno} (char {e.pos})")
sh Shell

jq emptyは入力をパースして何も出力しないため、CIスクリプト内の妥当性チェックとしてきれいに使えます。

# jq exits non-zero and prints the position on failure
jq empty input.json

# Python, no extra install
python -m json.tool input.json > /dev/null
go Go

Goは行番号ではなくバイトオフセットを返すので、改行の数は自分で数える必要があります。

if !json.Valid(data) {
    // Valid() gives no position. To get one, decode and
    // inspect the SyntaxError:
    var v any
    if err := json.Unmarshal(data, &v); err != nil {
        var se *json.SyntaxError
        if errors.As(err, &se) {
            line := 1 + bytes.Count(data[:se.Offset], []byte("\n"))
            return fmt.Errorf("%v at line %d", se, line)
        }
    }
}

よくある質問

ほかのバリデーターが1件しか出さないのに、なぜ複数のエラーが出るのですか?
パーサーが停止せず復帰するからです。問題を報告したあとで再同期して処理を続けるため、末尾カンマ・シングルクォートの文字列・クォートのないキーが混在するドキュメントでも、1回で3件すべてを報告します。
文字列や数値が単体でも有効なJSONになりますか?
なります。2014年のRFC 7159以降そうです。当初のRFC 4627はトップレベルをオブジェクトか配列に限っていましたが、現行仕様のRFC 8259は任意の値を許します。したがって"hello"、42、nullはいずれも完結した有効なJSONドキュメントです。
末尾カンマが許される場合はありますか?
JSONでは許されません。JavaScript、JSON5、そしてVS Codeが自身の設定ファイルに使っているJSONCでは許されます。受け取る側がJSONCを解釈するなら残しても構いませんが、そうでなければ修復ツールが取り除きます。
コメントはどうですか?
JSONには設計上ありません。ダグラス・クロックフォードが意図的に取り除きました。パース用のディレクティブを書き込む用途に使われていたためです。JSONCかJSON5を使うか、"_comment"のようなキーに移してください。