JSONの比較ツール - オンラインで無料のJSON比較 | JSON差分
2つのJSONオブジェクトを比較し、追加、削除、変更されたすべての値を、変更箇所への正確なパス付きで一覧表示する無料のオンラインツール。結果は色分けされて見やすく表示され、比較処理はブラウザ内で完結し外部サーバーには送信されない。API開発やコードのデバッグ作業に使われる。
JSONの差分ツール
ドキュメンテーション
JSON比較ツール(JSON差分ツールとも呼ばれる)は、2つのJSON(JavaScript Object Notation)値を比較し、その間で何が変わったかを報告します。追加、削除、変更されたすべてのプロパティまたは配列項目を、データ内の正確な位置とともに一覧表示します。このページでは、実際の比較ロジックに基づく例を使って、whiz.toolsのJSON比較ツールの仕組みを説明します。
JSON比較とは?
JSON比較とは、2つのJSON文書を照合して差分を見つける処理です。JSON文書は、オブジェクト(波括弧内のキーと値の組)、配列(角括弧内の順序付きリスト)、および文字列、数値、真偽値、nullなどのプリミティブ値から構成されるテキストです。数行を超えると、2つの文書を目視で比較するのは時間がかかり、誤りも生じやすくなります。そのため、比較ツールが照合を自動的に行い、各変更箇所を強調表示します。
開発者はこのような比較を使って、APIレスポンスの確認、設定ファイルの変更の追跡、データ移行で情報が失われていないことの検証、バージョン管理下のJSONファイルの変更のレビューを行います。
ツールが2つのJSON値を比較する方法
ツールはまず、標準のJSONパーサーで両方の入力を解析し、次に、解析後の2つの値を同じ階層で、一度に1レベルずつたどります。各段階で、次の3つの質問をこの順番で確認します。
- 2つの値の型が異なる(例えば、一方がオブジェクトでもう一方が数値である)か、一方が
nullでもう一方がそうでないか。そうであれば、その位置で変更を記録し、さらに深い比較は行いません。 - 両方の値がプリミティブ(文字列、数値、真偽値、またはnull)か。そうであれば、値を直接比較します。数値
123から文字列"123"への変更を含め、差異はすべて変更として扱われます。 - 両方の値がオブジェクトまたは両方が配列か。そうであれば、以下の規則で内容を比較し、入れ子になったオブジェクトや配列も再帰的に比較します。
すべての差異は、user.address.cityやtags[1]のようなパスとともに記録されるため、元の文書内で簡単に見つけられます。オブジェクトのメンバーはドットでつなぎ、配列項目は角括弧内のインデックスで示します。配列がオブジェクトに置き換えられた場合のように、文書の最上位で発生した差異にはデータ内のパスがないため、$と表示されます。これはRFC9535で定義されたJSONPath標準のルート識別子で、文書全体を表します。
オブジェクトの比較
2つのJSONオブジェクトについて、ツールはどちらか一方に現れるすべてのキーを集めます。各キーについて、次のように処理します。
- キーが2番目のオブジェクトにのみ存在する場合、それは追加されたプロパティです。
- キーが1番目のオブジェクトにのみ存在する場合、それは削除されたプロパティです。
- キーが両方に存在する場合、ツールは2つの値を再帰的に比較します。
キーの順序は関係ありません。JSON標準はオブジェクトのメンバーの順序を定義していないため、{"a":1,"b":2}と{"b":2,"a":1}は同一として扱われます。
配列の比較
配列は内容ではなく位置で比較されます。ツールは両方の配列をインデックスごとにたどり、長い方の配列の長さまで各位置にある値を比較します。一方の配列が短い場合、長い方の配列の末尾にある余分な項目は追加または削除として報告されます。
つまり、ツールは配列項目の内容による照合を一切行いません。オブジェクトがインデックス1からインデックス2へ「移動」したことは認識せず、各インデックスの値が変わったとだけ判断します。配列の途中で項目を削除または挿入すると、その後のすべての項目が1つずつずれるため、通常は1回の明確な追加または削除ではなく、複数の個別の変更として表示されます。
計算例
例1:2つのオブジェクトの比較
1番目のJSON:
1{ "user": { "address": { "city": "New York", "zip": "10001" } } }
22番目のJSON:
1{ "user": { "address": { "city": "Boston", "zip": "02108" } } }
2結果:
- 変更
user.address.city:"New York"→"Boston" - 変更
user.address.zip:"10001"→"02108"
例2:末尾での配列変更
1番目のJSON:
1{ "tags": ["important", "urgent", "review"] }
22番目のJSON:
1{ "tags": ["important", "critical", "review", "documentation"] }
2インデックス0は変更されず、インデックス1は変更され、インデックス2は変更されず、インデックス3は2番目の配列にのみ存在します。結果:
- 変更
tags[1]:"urgent"→"critical" - 追加
tags[3]:"documentation"
例3:配列の途中から項目を削除する場合
この例では、混乱のよくある原因である、配列の途中から項目を削除したときに何が起こるかを示します。
1番目のJSON:
1{
2 "products": [
3 { "id": 1, "name": "Laptop", "price": 999.99 },
4 { "id": 2, "name": "Mouse", "price": 24.99 },
5 { "id": 3, "name": "Keyboard", "price": 59.99 }
6 ]
7}
8「Mouse」の項目を削除し、末尾に「Monitor」の項目を追加した2番目のJSON:
1{
2 "products": [
3 { "id": 1, "name": "Laptop", "price": 899.99 },
4 { "id": 3, "name": "Keyboard", "price": 59.99 },
5 { "id": 4, "name": "Monitor", "price": 349.99 }
6 ]
7}
8これを見た人は、「Mouseが削除され、Monitorが追加された」と言うでしょう。しかし、ツールはインデックスだけで厳密に比較するため、そのようには認識しません。インデックス0と0、インデックス1と1、インデックス2と2をそれぞれ比較するため、削除された項目より後のすべてのフィールドが誤ったオブジェクトと対応します。実際の結果は7件の変更です。
- 変更
products[0].price:999.99→899.99 - 変更
products[1].id:2→3 - 変更
products[1].name:"Mouse"→"Keyboard" - 変更
products[1].price:24.99→59.99 - 変更
products[2].id:3→4 - 変更
products[2].name:"Keyboard"→"Monitor" - 変更
products[2].price:59.99→349.99
このようなリストを比較する際に、より明確な結果を得るには、貼り付ける前に両方の配列を同じ方法で並べ替えるかキー付けします。例えば、各リストを同じ順序で記述するか、比較前にIDフィールドでオブジェクトを対応付けます。
ツールが行わないこと
- 配列項目を内容で照合しません。 上記のとおり、インデックス位置だけで比較するため、項目が変更されたのではなく移動したことを認識できません。
- 循環参照を検出しません。 これは実用上の制限ではありません。両方の入力は
JSON.parseから取得され、常に単純なツリーを構築するため、自身を参照する値を生成できないからです。そもそも、有効なJSONテキストに循環参照を含めることはできません。 - 比較前に配列を並べ替える設定はありません。 上記のインデックスのずれを避ける唯一の方法は、貼り付ける前に入力内の項目を並べ替えることです。
ツールの使用方法
- 左側のボックスに1番目のJSON文書を貼り付け、右側のボックスに2番目の文書を貼り付けます。
- 両方のボックスにテキストが入るとツールは自動的に比較します。または、「Compare」をクリックして手動で実行します。
- 結果一覧を確認します。各行には
user.ageのようなパスと、それが追加、削除、変更のいずれであるかが表示され、変更の場合は古い値と新しい値が並べて示されます。 - 「Copy」をクリックすると、結果をプレーンテキストとしてコピーできます。
ボックスに有効なJSONではないテキストが含まれている場合、ツールは比較結果の代わりに、そのボックスの下にエラーを表示します。両方のボックスが無効な場合は、両方のエラーが同時に表示されます。
よくある質問
2つのJSON値の差異とは何ですか?
プロパティまたは配列項目が、2つの文書の一方にしか存在しない場合、または両方に存在しても異なる値や型を持つ場合、そのプロパティまたは配列項目は異なるとみなされます。数値5から文字列"5"への変更は、見た目が似ていても変更として扱われます。
項目の順序は重要ですか? コンテナによって異なります。JSONオブジェクトにはメンバーの定義済みの順序がないため、キーと値が同じで順序だけが異なる2つのオブジェクトは同一として扱われます。配列には順序があり、ツールはインデックス位置で比較するため、項目を別の位置に移動すると、移動ではなく一連の変更として報告されます。
結果のパス$は何を意味しますか?
文書の一部ではなく、文書全体が変更されたことを意味します。これは、最上位にある2つの入力の値の種類が異なる場合に発生します。例えば、一方が配列で、もう一方がオブジェクトの場合や、単純な数値1と2の場合です。$は、JSONPath標準であるRFC9535のルート識別子です。
JSONデータはサーバーに送信されますか? いいえ。比較はJavaScriptを使ってブラウザー内で実行されます。何もアップロードされません。
インデントや圧縮などの書式設定は結果に影響しますか? いいえ。両方の入力は比較前にJSON値へ解析されるため、空白、インデント、改行は結果に影響しません。比較されるのは実際のデータだけです。
コメントや末尾のカンマを含むJSONを比較できますか? いいえ。RFC8259で定義されている標準JSONでは、コメントや末尾のカンマは使用できません。それらを含む入力は無効として拒否されます。
参考文献
- IETF。「JavaScript Object Notation(JSON)データ交換形式」RFC8259、十二月2017年。
- IETF。「JavaScript Object Notation(JSON)Patch」RFC6902、四月2013年。
- IETF。「JSONPath:JSONのクエリ式」RFC9535、二月2024年。(セクション2.2ではルート識別子
$を定義しています。) - Mozilla Developer Network。「JSON.parse()」。