JSONのキー名を一括変換したい、あるいはJSON内の値を手軽に暗号化したいと思ったことはありませんか?
この記事では、Hylangの再帰関数を活用して実用的なJSON操作CLIツールを作る方法を紹介します。再帰によるネスト構造の走査パターンと、パイプで繋げるワンライナー活用術が身に付きます。
この記事で作るもの
- JSONキー変換ツール -- 変換規則に従いキー名を一括変換
- JSON暗号化・復号ツール -- パスワードベースで値を暗号化・復号
JSONのキーを一括変換する
再帰によるネスト走査
(defn map_key_deep [translate_func obj]
(if (coll? obj)
(ebranch (isinstance obj it)
(of dict)
(itemmap
(fn [item] #((translate_func (. item [0])) (map_key_deep translate_func (. item [1]))))
obj
)
(of list) (list(map ((curry map_key_deep) translate_func) obj))
)
obj
)
)
JSONは配列・オブジェクト・プリミティブの3種類の構造を持ちます。配列なら全要素に再帰適用、オブジェクトならキーを変換して値に再帰適用しています。
実行例
変換規則の dict.json を作成:
dict.json
[
{"from": "applePrice", "to": "apple_price"},
{"from": "orangePrice", "to": "orange_price"}
]
実行:
echo '{"applePrice":150, "orangePrice": 100}' | uvx --with hyrule --with cytoolz hy ./key_translate.hy -d dict.json
{
"apple_price": 150,
"orange_price": 100
}
JSONの値をパスワードで暗号化・復号する
再帰による値変換
(defn map_value_deep [translate_func obj]
(if (coll? obj)
(ebranch (isinstance obj it)
(of dict)
(valmap ((curry map_value_deep) translate_func) obj)
(of list) (list(map ((curry map_value_deep) translate_func) obj))
)
(translate_func obj)
)
)
キー変換との違いは itemmap→valmap、プリミティブ値に関数を適用する点です。
暗号化・復号の実行例
暗号化:
uvx --with hyrule --with cytoolz --with cryptography hy ./encrypt_json.hy -p <pass> -f <json> -o <json>
復号:
uvx --with hyrule --with cytoolz --with cryptography hy ./decrypt_json.hy -p <pass> -f <json> -o <json>
vipeと組み合わせてワンライナーで編集する
moreutils の vipe と組み合わせると、復号 → Vim編集 → 暗号化保存がワンライナーで実行できます。
uvx --with hyrule --with cytoolz --with cryptography hy ./decrypt_json.hy -f <json> -p <pass> \
| vipe \
| uvx --with hyrule --with cytoolz --with cryptography hy ./encrypt_json.hy -p <pass> -o <json>
まとめ
- Hylangの再帰関数でJSONのネスト構造を自然に走査できる
-
map_key_deep/map_value_deepパターンで、キー変換と値変換を汎用的に実装できる -
vipeとの組み合わせにより、暗号化JSONの編集もワンライナーで完結する