JSONが読み込めないときに見る場所
APIから受け取ったデータを少し直しただけなのに、JSONのエラーになってしまう。見た目がJavaScriptに似ているため、つい同じ書き方をしてしまう場面があります。まず短いデータで記号と値の型を確かめ、そのあとで「読み込めたけれど値が変わった」問題まで見ていきましょう。
エラーの位置より少し前を見る
閉じ忘れた引用符や余分なカンマは、次の文字を読んだ時点でエラーになることがあります。表示された行だけでなく、ひとつ前の値の終わりも手がかりです。次の表は、設定ファイルのつもりで書くと混ざりやすい形です。
JSONとして読める書き方
| 読めない例 | 修正例 | 違い |
|---|---|---|
{name: "Mika"} |
{"name": "Mika"} |
キーも二重引用符で囲む |
{'count': 2} |
{"count": 2} |
一重引用符は使わない |
{"count": 2,} |
{"count": 2} |
最後の項目の後ろにカンマを置かない |
{"enabled": True} |
{"enabled": true} |
true・false・nullは小文字 |
{"count": 01} |
{"count": 1} |
整数部に余分な先頭ゼロを付けない |
コメントを残したいとき
JSONの文法にはコメントがありません。説明を別ファイルに置くか、受け手が許すなら説明用の項目を設けます。JSONCなどのコメント対応形式を読めるエディターでも、そのまま通常のJSON APIへ送れるわけではありません。
文字列と数値は見た目が似ていても別の値
商品コードの「0012」を数値にすると、桁をそろえるためのゼロを残せません。一方、個数の2を文字列にすると、受け手が数値を期待している場合に型のエラーになります。構文が正しいかと、項目の意味が合っているかは別の確認です。
小さな入力で型を確かめる
codeは文字列、countは数値、enabledは真偽値、noteはnull、tagsは配列です。nullは空文字列でも「項目が存在しない」状態でもありません。たとえば更新APIでは、noteを省くと変更なし、nullを送ると削除、という独自の約束もありえます。
{"code":"0012","count":2,"enabled":false,"note":null,"tags":[]}
文字列の中の改行は \n と書く
画面に見せたい改行を、そのまま二重引用符の中に打ち込むと構文エラーになります。JSONの文字列では改行を \n と表します。ファイルパスで使うバックスラッシュも、ひとつの文字として残すには二重に書きます。
入力と、読み込んだ後の内容
messageを読み込むとfirstとsecondの間に改行が入り、pathはC:\temp\sample.txtになります。JSONそのものを別のJSONの文字列に埋め込む場合は、外側の層でもエスケープが必要です。バックスラッシュの数を勘で減らすより、どの層の文字列を編集しているかを見る方が迷いません。
{"message":"first\nsecond","path":"C:\\temp\\sample.txt"}
同じキーが二つあっても、必ずエラーになるとは限らない
{"mode":"test","mode":"live"}は、人が見ればどちらを使うのか迷うデータです。RFC 8259 §4はキー名の一意性をSHOULDとして求めていますが、重複時の読み取り結果は実装間でそろいません。JavaScriptのJSON.parseでは後ろの値が残ります。
整形前に元データを残す
Online ToolsのJSON整形もJSON.parseを使うため、この例を整形するとmodeはliveだけになります。重複が消えた整形結果から、元の二つの値を復元することはできません。重複の有無を調べたいときは、重複キーを拒否するJSON差分比較へ元データを左右に入れる方法があります。
長いIDが変わるなら、構文ではなく数値精度を疑う
JSONの数値の書式と、読み込むプログラムが保持できる精度は同じではありません。JavaScriptの通常の数値で整数を確実に表せる範囲は±9,007,199,254,740,991までです。これはJSON文法の桁数上限ではありません。大きな識別番号は、送り手と受け手で文字列として扱う約束にすると桁を保ちやすくなります。
JavaScriptで再現できる例
Online ToolsのJSON整形・JSONからCSVへの変換も通常のJSON.parseを使います。長いIDを扱う元データは手元に残し、変換後の桁を照合するのが安心です。数値を勝手に文字列へ変えるとAPIの約束を破ることがあるので、型の変更は受け手と合わせます。
JSON.stringify(JSON.parse('{"id":9007199254740993}'))
// {"id":9007199254740992}
JSON.stringify(JSON.parse('{"id":"9007199254740993"}'))
// {"id":"9007199254740993"}
短い例を整形してから、元データへ戻る
JSON整形ツールで上の小さな例を入力し、「整形」と「検証」の結果を見比べられます。「検証」の成功はJSONとして読めたという意味で、業務ルールやJSON Schemaへの適合まで保証するものではありません。
続けて読む
項目の追加・削除を探すならJSONのキー順と配列順を踏まえた差分比較へ。CSVとの使い分けはデータ形式の選び方、文字化けは文字コードの基礎が手がかりになります。
仕様の根拠
文法と値の型はRFC 8259 §§2–3、重複キーは§4、数値精度は§6、文字列は§7に記載されています。JSON.parseの動作はECMAScript仕様を参照できます。