json版sedことjqのPythonバインディングをcythonで作った

jqはjsonデータを加工するコマンド、「json界のsed」と呼ばれています。

手軽さで知られるjqですが、実はjqのスクリプトにはmap・filterなどの強力なビルドイン関数があり、 変数・関数を定義できるなど、強力なデータ操作能力を持っています。しかもコンパクト。

文字列に対する正規表現のようなパワフルさです。

こんな強力な能力を、JSONだけに閉じ込めておくのは勿体無い!そこで!

東北の中山間地にある実家で強制ネット断食だった三ガ日に、Pythonバインディングをcythonで作ってみた!

pyjq: Binding for jq JSON Processor

https://github.com/doloopwhile/pyjq

インストール

事前にjqをとってきてコンパイルしておきます。

# 依存ライブラリ
# debian系の場合
sudo apt-get install flex bison gcc make autoconf

git clone https://github.com/stedolan/jq
cd jq
git checkout jq-1.3

autoreconf -i
./configure
make
sudo make install

# ダイナミックリンクライブラリのキャッシュを更新
# Linuxの場合
ldconfig

あとはpipでインストールできます。pyjq自体のコンパイルはすぐなのですが、cythonのコンパイルに少し時間がかかります。

pip install pyjq

サンプル

数値・文字列・真偽値・リスト・辞書でできたデータ構造を、jqスクリプトで直接処理できます。

戻り値はjson(文字列)ではなく、データ構造が帰ってきます。

>>> data = dict(
...     parameters= [
...         dict(name="PKG_TAG_NAME", value="trunk"),
...         dict(name="GIT_COMMIT", value="master"),
...         dict(name="TRIGGERED_JOB", value="trunk-buildall")
...     ],
...     id="2013-12-27_00-09-37",
...     changeSet=dict(items=[], kind="git"),
... )
>>> import pyjq
>>> pyjq.first('.parameters[] | {"param_name": .name, "param_type":.type}', data)
{'param_type': None, 'param_name': 'PKG_TAG_NAME'}

関数は3種類あります。

apply(script, value, **kw)
jqの出力した値をリストで返す
first(script, value, default=None, **kw)
jqの出力した値の最初のものを返す
one(script, value, **kw)
jqが値を1つだけ返した時、その値を返す。 値を出力しなかったり2つ以上の値を返したときは、例外を投げる。

また、スクリプトを固めて使いまわすためのpyjq.compileもあります(正規表現re.compileのように)。

制限

jqはjson用のコマンドなので、pyjqもjsonに変換可能なデータ構造(数値・文字列・真偽値・リスト・辞書だけを含むデータ構造)しか処理できません。

まあ、これで十分な気もしますが、どうなんでしょう?