本文へスキップ
jsonbeautifiers
日本語

JSONのキー並べ替え

ネストしたオブジェクトも含めてキーをアルファベット順に。差分がきれいに保てます。

JSONPathで絞り込む

RFC 9535の構文です。結果は、このダイアログを開いたパネルを置き換えます。

 

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

オブジェクトのキーをアルファベット順に、ネストしたすべてのオブジェクトを再帰的に並べ替えます。配列の順序には一切手を付けません。配列の順序には意味があり、オブジェクトのキーの順序にはないからです。

そうする理由は差分です。同じ内容でキーの順序が違う2つのファイルは、ノイズだらけの差分を生みます。両方を並べ替えれば、差分には本当に変わった部分だけが残ります。

並べ替えるべき場面

生成されたファイルをコミットする前
ロックファイル、エクスポートされた設定、ツールが書き出すもの全般。生成側が順序を保証していないなら、並べ替えることで実行ごと・マシンごとの揺れがなくなります。
2つのドキュメントを比較する前
先に両方を並べ替えると、テキスト差分が読めるものになります。当サイトの構造差分はもともとキーの順序を無視するので、これは主にそうでないツール向けの手当てです。
正規形を得るため
ドキュメントのハッシュや署名には決定的なシリアライズが必要です。キーの並べ替えはその一部で、残りはRFC 8785(JSON Canonicalization Scheme)が数値の書式や文字列のエスケープまで含めて規定しています。

並べ替えるべきでない場面

順序が読み手にとって意味を持つ、手で管理している設定ファイル。重要な設定が上にあり、関連する項目がまとまっている場合です。それをアルファベット順に並べ替えるのは、技術的には無害で、実務上は迷惑です。

受け取る側がキーの順序に依存している場合も避けるべきです。本来そうであってはいけませんが、自作パーサーの中にはそうしているものがあり、本番でそれに気づくと高くつきます。

比較のしくみ

既定では大文字と小文字を区別し、コードポイント順に従って大文字が小文字より前になります。名前の一覧などで一般に期待される並びにしたい場合は、大文字小文字を区別しない比較を有効にしてください。

これはロケールを考慮した並べ替えではなく、コードポイント順である点に注意してください。どこでも決定的に同じ結果になり、それこそが正規形に必要な性質です。ロケール依存の並べ替えでは、マシンごとに異なるファイルができてしまいます。

How to do this in code

コードでキーを並べ替える方法。

sh jq

-Sは最上位だけでなく、すべての階層に適用されます。

jq -S . input.json          # sort keys, recursively
jq -S -c . input.json       # sorted and compact
py Python
import json

# sort_keys applies recursively
out = json.dumps(json.loads(text), sort_keys=True, indent=2)
js JavaScript

JavaScriptにはソート済みのstringifyが組み込まれていません。このスニペットがあちこちにコピーされている理由がそれです。

// The replacer only receives keys, so sorting needs a walk.
function sortDeep(value) {
  if (Array.isArray(value)) return value.map(sortDeep);
  if (value && typeof value === 'object') {
    return Object.fromEntries(
      Object.keys(value).sort().map((k) => [k, sortDeep(value[k])]),
    );
  }
  return value;
}

const out = JSON.stringify(sortDeep(JSON.parse(text)), null, 2);
go Go

標準ライブラリが頼まれずとも正しいことをしてくれる、数少ない例のひとつです。

// encoding/json sorts map keys automatically when marshalling
// a map. Struct fields keep their declaration order.
var v map[string]any
json.Unmarshal(data, &v)
out, _ := json.MarshalIndent(v, "", "  ")   // keys sorted

よくある質問

並べ替えるとデータが変わりますか?
意味の上では変わりません。仕様上JSONのオブジェクトは順序を持たないため、並べ替えたドキュメントも同じ値を保持します。バイト列は変わりますが、それこそが目的です。
なぜ配列の要素は並べ替えないのですか?
配列の順序はデータの一部だからです。[3,1,2]を[1,2,3]にするのは、書式を整えることではなくドキュメントを変えることです。
これは正規化JSONと同じものですか?
その一部です。RFC 8785(JSON Canonicalization Scheme)は、数値の書式、文字列のエスケープ、Unicode正規化までを規定しており、結果をハッシュしたり署名したりするなら、いずれも重要になります。