目的と前提
JSON を整形した後に「読みやすくなった」だけで処理を終えると、文字列の先頭ゼロや null と欠落値の違いを見落とします。この記事では、ファイルを読む・文字列として包む・空白を減らす操作を、小さな Node.js の検証コードで分けます。
開示:QoTool の運営側からの投稿で、自社ツールへのリンクを含みます。文章とコードは AI を利用して作成し、掲載する検証項目は Node.js で実行して確認しました。サンプルは架空のデータです。ツールを使わなくても、以下のコードだけで確認できます。
1. ファイル名ではなくルートの型を確認する
英語の質問なら how do you open a json file に当たる作業です。まず元ファイルを残し、コピーをテキストとして開きます。QoTool の画面では Open file から読み込めます。表示上の入力上限は 5 MB、大きいデータはプレビュー範囲が制限されるため、画面に見える件数だけで全件数を判断しません。
JSON のルートはオブジェクトとは限りません。配列、文字列、数値、真偽値、null も有効です。また、拡張子が .json でも、実体が一行一件の JSONL のことがあります。複数行に独立したオブジェクトが並ぶ入力は、単一の JSON.parse では処理できません。
2. 変換後の値を比較するテスト
次を check-json.cjs として保存し、node check-json.cjs で実行します。追加パッケージは不要です。成功時は最後に PASS が表示されます。
const assert = require('node:assert/strict');
const value = {
id: '0007',
message: 'two words',
empty: '',
absent: null,
flags: [true, false]
};
const pretty = JSON.stringify(value, null, 2);
const compact = JSON.stringify(JSON.parse(pretty));
assert.deepEqual(JSON.parse(compact), value);
assert.equal(JSON.parse(compact).id, '0007');
assert.equal(JSON.parse(compact).message, 'two words');
assert.equal(Object.hasOwn(JSON.parse(compact), 'absent'), true);
assert.equal(Object.hasOwn(JSON.parse(compact), 'missing'), false);
const quotedText = JSON.stringify(pretty);
assert.equal(typeof JSON.parse(quotedText), 'string');
assert.equal(JSON.parse(quotedText), pretty);
assert.throws(() => JSON.parse('{"a":1,}'));
assert.throws(() => JSON.parse('{"a":1}' + String.fromCharCode(10) + '{"a":2}'));
console.log('PASS');
重要なのは、整形後の文字列そのものを比較する場合と、パース後の値を比較する場合を区別することです。インデントは変わってよい一方、id の先頭ゼロや message の内部の空白は変えてはいけません。
3. エスケープは別の操作
ログや設定値に JSON の本文を文字列として格納するなら、escape json に相当する操作を行います。上の quotedText は、pretty の本文を一つの JSON 文字列として包んだ結果です。これを一度パースしても、オブジェクトではなく文字列が得られます。
二重に包まれた入力を扱う場合は、一度戻した時点で型を確認します。常に二度 JSON.parse する処理にすると、正当な文字列まで JSON として解釈しようとします。画面上のバックスラッシュだけを一括削除する方法も、引用符や改行を壊す原因になります。
4. 圧縮の意味を限定する
json minify は、JSON の構造上不要な空白を減らす作業です。文字列の中の空白を削除する作業ではありません。上のテストでは two words が同じ値で残ることを確認しています。
この JavaScript の例を任意のデータにそのまま適用する際には、数値精度にも注意します。Number.MAX_SAFE_INTEGER を超える整数は JSON.parse の段階で丸められる場合があります。ID を文字列として扱う仕様なら、最初から文字列として保持します。数値であることが必須の仕様なら、桁を保持するパーサーを使い、出力先まで正確な数字列を確認します。
5. このテストが保証しないこと
このサンプルは JSON で表現できる値だけを対象にしています。Date、Map、undefined、循環参照などの JavaScript オブジェクトを損失なく保存するテストではありません。JSON Schema による業務ルールの検証も別途必要です。
実際の連携では、空配列、空文字、null、欠落フィールド、引用符と改行を含む文字列、大きな整数のサンプルを追加すると、見た目では気づきにくい変化を検出できます。修復、整形、エスケープを別々の工程として記録しておくと、どこで値が変わったかを調べやすくなります。