【Python】jmespathでandやor条件を使いたい


はじめに

<バージョン>
Python: 3.6.8
jmespath: 0.10.0

 以下のようなymlから、一部だけを取り出す場合にはjmespathが便利です。

test_data.yml
---
sample:
  - id: 1
    name: "test1"
  - id: 2
    name: "test2"
  - id: 3
    name: "test3"

1. インストール方法

 jmespathはデフォルトでは入っていないのでインストールしましょう。

pip install jmespath

2. 今回紹介するパターン

  • パターン1
    • idが1 かつ nameがtest1のデータを抽出(and条件)
  • パターン2
    • idが1 または idが2のデータを抽出(or条件)
  • パターン2
    • idが1 または idが2のデータから、nameの項目だけをリストで抽出

3. 変数抽出時の構文

 変数を抽出する場合は以下のように記載します。検索文字列は複雑になりがちなので、
別途変数として記載した方が良いです。

jmespath.search(検索文字列, 検索する元となるデータ)

4. コードの内容

 以下が実際に作成したコードです。わかりやすさ重視で書いているので、
重複した変数宣言や行があることについてはご了承ください。
jmespathで抽出する前に、変数(jmespath_str)に検索文字列を定義することで
コードが読みやすくなります。検索条件の書き方は、

  • and条件の場合
    • 条件1 && 条件2
  • or条件の場合
    • 条件1 || 条件2

なので覚えておきましょう。

test_jmespath.py
import jmespath
import yaml


def main():

    # load yaml
    with open("test_data.yml", "r") as yml:
        test_data = yaml.load(yml, Loader=yaml.SafeLoader)

    # pattern1
    jmespath_str = "sample[?(id == `{}` && name == `{}`)]".format(1, "test1")
    print("pattern1:", jmespath_str)
    print(jmespath.search(jmespath_str, test_data))

    # pattern2
    jmespath_str = "sample[?(id == `{}` || id == `{}`)]".format(1, 2)
    print("pattern2:", jmespath_str)
    print(jmespath.search(jmespath_str, test_data))

    # pattern3
    jmespath_str = "sample[?(id == `{}` || id == `{}`)].name".format(1, 2)
    print("pattern3:", jmespath_str)
    print(jmespath.search(jmespath_str, test_data))


if __name__ == "__main__":
    main()

5. 実行結果

 想定通りの結果を得ることが出来ました。

pattern1: sample[?(id == `1` && name == `test1`)]
[{'id': 1, 'name': 'test1'}]
pattern2: sample[?(id == `1` || id == `2`)]
[{'id': 1, 'name': 'test1'}, {'id': 2, 'name': 'test2'}]
pattern3: sample[?(id == `1` || id == `2`)].name
['test1', 'test2']

参考記事

Improved Filters — JMESPath