JSONデータの比較
2021/10/13 追記
WinMerge 日本語版の2021/06/29 2.16.12-jp-3でPrettifyJSON展開プラグインが追加されたので、デフォルトでJSON整形比較が可能になりましたね!
BeatSaberで遊ぶようになってからJSONファイルに触れる機会が増えたのですが、吐き出すツールによって未整形のJSONデータである場合があります。代表的なのは、譜面データの.datファイルですね。
Gitで作譜中の譜面データを管理しようと思ったけど、MMA2で保存されるJSONデータが未整形なためWinMergeで差分比較するのが困難になってます。
WimMergeのプラグインで比較前整形
WinMergeにはプラグイン機能があって、標準でEXCEL等の比較には対応していますので、それを真似てJSONデータを整形してから比較できないか調べたら、既に行っている人がいたのですが、下記エラーが出て上手く動作しませんでした。
エラーコードを調べるとSyntax errorっぽいのですが、WinMergeからのエラーメッセージが不親切でコードのどこがおかしいのか分からないです。VBScriptとJScriptに分けてCScriptで実行してみたりしましたが特にエラーも出ず、デバッグが難しそうでした。また、64bit環境ではVBScriptからJScriptの関数呼び出しが出来ない様な情報もあるため、あきらめました。
別の方法を調査するとコマンドラインで動く、JSON整形・集計ツールであるjqを見つけたので、これをVBScriptから外部コマンドで呼び出せば行けそうです。
<scriptlet>
<implements type="Automation" id="dispatcher">
<property name="PluginEvent">
<get/>
</property>
<property name="PluginDescription">
<get/>
</property>
<property name="PluginFileFilters">
<get/>
</property>
<property name="PluginIsAutomatic">
<get/>
</property>
<method name="UnpackFile"/>
<method name="PackFile"/>
</implements>
<script language="VBS">
Option Explicit
Function get_PluginEvent()
get_PluginEvent = "FILE_PACK_UNPACK"
End Function
Function get_PluginDescription()
get_PluginDescription = "Json形式のファイルを整形し比較をする"
End Function
Function get_PluginFileFilters()
get_PluginFileFilters = "\.json$;\.dat$"
End Function
Function get_PluginIsAutomatic()
get_PluginIsAutomatic = True
End Function
Function UnpackFile(fileSrc, fileDst, pbChanged, pSubcode)
Dim shell
Dim command
Dim jqPath
jqPath = "C:\Program Files\WinMerge\MergePlugins\jq-win64.exe"
Set shell = CreateObject("WScript.Shell")
command = "cmd /c type """ & fileSrc & """ | """ & jqPath & """ > """ & fileDst & """"
shell.Run command, 0, true
pbChanged = True
pSubcode = 0
UnpackFile = True
End Function
Function PackFile(fileSrc, fileDst, pbChanged, pSubcode)
PackFile = False
End Function
</script>
</scriptlet>
ダウンロードしたjqの実行ファイルはWinMergeのプラグインフォルダに置くことにしました。PATHが通ったところに置けばフルパス指定で実行しなくても大丈夫ですが、PC移行時とか忘れちゃうのでプラグインフォルダにCompareJsonFiles.sctと一緒に入れておくことにします。
ハマったところは、shell.Runの部分で shell.Run(command,0,true)
だと 0x800a0414 コンパイルエラーになります。これもまたエラーコードしか出ないので非常にデバッグしづらいです。
拡張子フィルタがありますので"\.json$;\.dat$"
の部分でJSONファイルに使われる拡張子を列挙すると良いです。BeatSaberで使うことを想定しているので、.datを追加しておきました。
プラグインの使用方法
- jqの公式サイトからWindows(64bit)用のexeファイルをダウンロードして、WinMergeのプラグインフォルダに配置します。
- 上記プラグインのスクリプトレットを
CompareJsonFiles.sct
で、同じくプラグインフォルダに配置します。その際にスクリプトのjqPath = "C:\Program Files\WinMerge\MergePlugins\jq-win64.exe"
を環境に合わせて修正して下さい。なお、文字コードはSJISにして下さい。 - WimMerge起動時のダイアログにあるファイル展開プラグインか、TortoiseGitで差分表示した場合などは起動後にメニューのプラグインから
展開プラグインで開く
を選択して、CompareJsonFiles.sct
を選んで下さい。
4.上手く行けば、下記の様にJSONデータが整形されて表示されます。
5.WinMergeの設定で、指定get_PluginFileFilters
拡張子の場合は自動で展開プラグインを適用させることもできますが、必要な場合のみ使用したいので私は手動で整形実行しています。
WinMergeで整形後データを編集した場合
WinMergeで展開プラグインを使用したファイルを編集して保存しようとすると、以下の様なメッセージが表示されます。
しかし、JSONファイルを整形しているだけなので、そのままOKで同名ファイルに上書き保存すれば問題ありません。
その他
jqコマンドはJSONの整形だけでなくソートなどもできます。
例えばキー基準でソートを行い、構造的な比較をしたい場合は以下の様にスクリプトのjqコマンドを実行している部分を修正すれば可能です。
command = "cmd /c type """ & fileSrc & """ | """ & jqPath & """ --sort-keys > """ & fileDst & """"
参考:jqでsortする https://qiita.com/yoza/items/c4c732779a5a10fd3b4c