新機能一覧に載ってなかったので気づいてませんでしたが Chrome で JSON ファイルを直接開いたときにヘッダーが表示されるようなっていました
ヘッダーのメニューには 「プリティ プリント」 のチェックボックスがあります
これにチェックを入れると JSON がきれいにフォーマットされて読みやすくなります
以前はこんなのなかった気がすると思って Chrome 116 で開いてみるとありませんでした
Chrome 117 の新機能のようです
これまでは JSON のフォーマットのために VSCode に貼り付けたり devtools のレスポンスで表示したりしていたので この機能があると便利になりますね
ちなみに Edge は 117 でもこの機能はありません
というか Edge ではデフォルトできれいにフォーマットされて色付けもされています
生のレスポンスを見たいときに Ctrl-U でソースコードを表示したり devtools のレスポンスで確認しないといけないです
これはこれで少し不便だったりもします
ちなみに JSON しか確認していませんが他のファイル形式でもフォーマット表示してくれるのかもしれません
このコードを実行したときの出力(プロパティ順)はどうなるでしょうか?
答えはこうなります
bar は最後に来ず obj を展開したときの最初の場所です
と書いた場合と同じです
この仕組み 順番に意味を持たせたいときに良くも悪くもあるんですよね
この場合は bar は常に上書きするもので obj.bar はいらないものです
なのにそれのせいで順番が決まってしまいます
オブジェクトで順番は無いものと考えるべきという主張もありますが 必要になるときもあるものです
上書きするものを除外したオブジェクトを作ればできなくはないものの面倒がありますし 数が多いと書くのが面倒です
関数を用意しておけば書く場所は楽になりますが こんなことしないといけないのかって気持ちになります
ただ 今の動きで助かってる部分もあるのでデフォルト挙動が変わってほしいかというと難しいところです
localStorage などに JSON 文字列を保存して それと現状に差分があるかを確認したいときなんかは今のほうが嬉しいです
JSON 文字列比較だとプロパティ順の違いで不一致になるので順番が変わってほしくないです
イミュータブルオブジェクトとして扱いたいときは上に書いたような方法で obj2 を作るのでこれで毎回順番が変わるとチェックが面倒になります
const obj = { foo: 1, bar: 2, baz: 3 }
const obj2 = { ...obj, bar: 4 }
console.log(JSON.stringify(obj2, null, " "))
答えはこうなります
{
"foo": 1,
"bar": 4,
"baz": 3
}
bar は最後に来ず obj を展開したときの最初の場所です
const obj2 = {}
obj2.foo = 1
obj2.bar = 2
obj2.baz = 3
obj2.bar = 4
と書いた場合と同じです
この仕組み 順番に意味を持たせたいときに良くも悪くもあるんですよね
この場合は bar は常に上書きするもので obj.bar はいらないものです
なのにそれのせいで順番が決まってしまいます
オブジェクトで順番は無いものと考えるべきという主張もありますが 必要になるときもあるものです
上書きするものを除外したオブジェクトを作ればできなくはないものの面倒がありますし 数が多いと書くのが面倒です
const obj = { foo: 1, bar: 2, baz: 3 }
const { bar, ...rest } = obj
const obj2 = { ...rest, bar: 4 }
console.log(JSON.stringify(obj2, null, " "))
{
"foo": 1,
"baz": 3,
"bar": 4
}
関数を用意しておけば書く場所は楽になりますが こんなことしないといけないのかって気持ちになります
const merge = (...objs) => {
const result = {}
for (const obj of objs) {
for (const [k, v] of Object.entries(obj)) {
if (result.hasOwnProperty(k)) {
delete result[k]
}
result[k] = v
}
}
return result
}
const obj = { foo: 1, bar: 2, baz: 3 }
const obj2 = merge(obj, { bar: 4 })
console.log(JSON.stringify(obj2, null, " "))
{
"foo": 1,
"baz": 3,
"bar": 4
}
ただ 今の動きで助かってる部分もあるのでデフォルト挙動が変わってほしいかというと難しいところです
localStorage などに JSON 文字列を保存して それと現状に差分があるかを確認したいときなんかは今のほうが嬉しいです
JSON 文字列比較だとプロパティ順の違いで不一致になるので順番が変わってほしくないです
イミュータブルオブジェクトとして扱いたいときは上に書いたような方法で obj2 を作るのでこれで毎回順番が変わるとチェックが面倒になります
そういえば Python に JSON 扱う機能があった気がする と思って探すと単純にフォーマットしてくれるだけでした
無いならこんな感じで プロパティ取り出しできるツールを作って置くと便利かも
使用例
そう思っていざ作ろうとしたのですが なんかこれでいい気がしてきました
そこまで長くないし jsonprop.js というファイルがなくてもいいし 直接 JavaScript 書いてるので複数のプロパティを結合したり区切り文字を変えたりと好きに拡張できるし
無いならこんな感じで プロパティ取り出しできるツールを作って置くと便利かも
> echo '{"prop1":"a","prop2":{"prop3":"b"},"prop4":["c","d"]}' > data.json
> node jsonprop.js -f data.json prop1 prop2.prop3 prop4[0] prop4[1]
a
b
c
d
使用例
node jsonprop.js -f data.json "user.name" "contents[0].title" | read -L name title
node /path/to/$name/$title/index.js
そう思っていざ作ろうとしたのですが なんかこれでいい気がしてきました
node -p "let d=require('./data.json');[d.user.name,d.contents[0].title].join('\n')"
そこまで長くないし jsonprop.js というファイルがなくてもいいし 直接 JavaScript 書いてるので複数のプロパティを結合したり区切り文字を変えたりと好きに拡張できるし
これの Node.js 版
node コマンドを普通に実行して REPL で require すればいいだけで Node.js インストール済み環境ならそもそも困らないと思う
Python のと違って .foo みたいなプロパティアクセスでほしいとこだけ取れるのが使いやすい
node -p "require('./dump.json')"
node コマンドを普通に実行して REPL で require すればいいだけで Node.js インストール済み環境ならそもそも困らないと思う
Python のと違って .foo みたいなプロパティアクセスでほしいとこだけ取れるのが使いやすい
自動生成された圧縮された JSON をみたいのですが インデントもない状態だと読むのが辛いです
短ければコピペして手元の Windows でフォーマットすればいいのですがちょっと長めです
ローカルまでコピーしてくるのも面倒ですし フォーマットするツールをインストールするのもできれば避けたいです
いい方法ないものかと探してみると Python でできました
これで min.json をフォーマットして表示できます
デフォルトでいろいろな機能が揃ってるのでやっぱり Python は便利ですね
CentOS8 はデフォルトで入ってないのが残念ですが これくらいなら platform-python 使ってしまって良いかも
注意したいのは 複数指定できないところです
とすると 2 つを見れるのではなく b.json へ出力となって もとの b.json は消えてしまいます
使い方
短ければコピペして手元の Windows でフォーマットすればいいのですがちょっと長めです
ローカルまでコピーしてくるのも面倒ですし フォーマットするツールをインストールするのもできれば避けたいです
いい方法ないものかと探してみると Python でできました
python3 -m json.tool min.json
これで min.json をフォーマットして表示できます
デフォルトでいろいろな機能が揃ってるのでやっぱり Python は便利ですね
CentOS8 はデフォルトで入ってないのが残念ですが これくらいなら platform-python 使ってしまって良いかも
注意したいのは 複数指定できないところです
python3 -m json.tool a.json b.json
とすると 2 つを見れるのではなく b.json へ出力となって もとの b.json は消えてしまいます
使い方
user@ubuntu ~> python3 -m json.tool --help
usage: python -m json.tool [-h] [--sort-keys] [infile] [outfile]
A simple command line interface for json module to validate and pretty-print
JSON objects.
positional arguments:
infile a JSON file to be validated or pretty-printed
outfile write the output of infile to outfile
optional arguments:
-h, --help show this help message and exit
--sort-keys sort the output of dictionaries alphabetically by key
JSON を比較したいとき文字列比較だと オブジェクトの順番の違いでも違うもの扱いされる
オブジェクトや配列を再帰的にチェックしていくのは面倒
片方のプロパティ全部をもう片方と全部比較しても もう片方のほうにしか無いプロパティもあったり 考慮することが意外とあってコードも長くなる
短く書きたかったので オブジェクトは Object.entries の形式化してソートするだけ
比較は JSON.stringify した文字列比較に任せる方針なもの作ってみた
JSON を比較するくらい標準機能にあってもいいと思うのに
オブジェクトや配列を再帰的にチェックしていくのは面倒
片方のプロパティ全部をもう片方と全部比較しても もう片方のほうにしか無いプロパティもあったり 考慮することが意外とあってコードも長くなる
短く書きたかったので オブジェクトは Object.entries の形式化してソートするだけ
比較は JSON.stringify した文字列比較に任せる方針なもの作ってみた
const rec = v =>
(v instanceof Object && !Array.isArray(v)) ?
Object.entries(v).map(x => [x[0], rec(x[1])]).sort((a, b) => a[0].localeCompare(b[0]))
:
v
const jsonDiff = (a, b) =>
JSON.stringify(rec(a)) === JSON.stringify(rec(b))
jsonDiff({a: 1, b: 2}, {b: 2, a: 1})
// true
JSON.stringify({a: 1, b: 2}) === JSON.stringify({b: 2, a: 1})
// false
JSON を比較するくらい標準機能にあってもいいと思うのに
.NET って標準じゃ JSON が扱いづらすぎて JSON.NET とか DynamicJSON とか外部のライブラリ使うのが一般的と言ってもいいくらい
ただこれらも万能ってわけじゃなくて .NET は JSON 弱いって印象だったけど 公式パッケージで新しい JSON の機能が出てたみたい
https://www.nuget.org/packages/System.Text.Json
.NET Core 3.0 はだと標準機能みたい
https://docs.microsoft.com/ja-jp/dotnet/api/system.text.json?view=netcore-3.0
今度 C# 使うときに使ってみる
ただこれらも万能ってわけじゃなくて .NET は JSON 弱いって印象だったけど 公式パッケージで新しい JSON の機能が出てたみたい
https://www.nuget.org/packages/System.Text.Json
.NET Core 3.0 はだと標準機能みたい
https://docs.microsoft.com/ja-jp/dotnet/api/system.text.json?view=netcore-3.0
今度 C# 使うときに使ってみる