JSONのネストされたオブジェクトの変更を検出する

JSON diffアルゴリズムがネストされたオブジェクトを再帰的に比較する方法を学びます。深い比較、パス追跡、異なるネストレベルでの変更報告について解説します。

Structural Diffs

詳細な説明

実際のJSONドキュメントはフラットであることはほとんどありません。APIレスポンス、設定ファイル、データエクスポートは通常、数レベルの深さにネストされたオブジェクトを含んでいます。堅牢なJSON diffアルゴリズムは、ネストされた構造に再帰的に降りていき、各変更へのフルパスを追跡する必要があります。

再帰比較の仕組み:

アルゴリズムが同じキーで2つのオブジェクトに遭遇した場合、それらを全体として比較する(オブジェクト全体が「変更された」と報告する)のではなく、両方のオブジェクトの子要素に降りて個別に比較します。このプロセスはリーフ値(プリミティブ)に到達するか、追加/削除を検出するまで繰り返されます。

// 変更前
{
  "user": {
    "name": "Alice",
    "settings": {
      "theme": "dark",
      "notifications": {
        "email": true,
        "sms": false
      }
    }
  }
}

// 変更後
{
  "user": {
    "name": "Alice",
    "settings": {
      "theme": "light",
      "notifications": {
        "email": true,
        "sms": true,
        "push": true
      }
    }
  }
}

diffは正確なパスで3つの変更を報告します:

  • user.settings.theme"dark" から "light" に変更
  • user.settings.notifications.smsfalse から true に変更
  • user.settings.notifications.push:値 true で追加

パスの表現:

ほとんどのdiffツールは、各変更の場所を特定するためにドット記法(user.settings.theme)またはRFC 6901のJSON Pointer構文(/user/settings/theme)を使用します。JSON PointerはJSON Patch(RFC 6902)で使用される形式です。

深度制限付きdiff:

一部のdiffツールでは再帰の深度を制限できます。深度0では、ルートオブジェクト全体が一単位として比較されます。深度1では、トップレベルのキーのみが個別に比較されます。これは、大規模なドキュメントの概要を把握してから特定のセクションを詳しく調べる場合に便利です。

パフォーマンスの考慮事項:

深くネストされた多くのレベルを持つドキュメントは、再帰呼び出しの回数を増やします。10以上のネストレベルと数千のキーを持つドキュメントでは、diffのパフォーマンスが低下する可能性があります。しかし、実際のJSONドキュメントは5〜6レベルのネスト以内に収まることが多く、パフォーマンスは問題になりません。

ユースケース

ユーザー設定移行スクリプトのデバッグで、変更前後のJSONスナップショットを比較し、意図したネストされた設定のみが更新され、他の設定への意図しない副作用がないことを確認する。

試してみる — JSON Diff

フルツールを開く