前書き
最近AWSの仕事が多く、aws-cliでdescribe系のコマンドを打ってます。
表示させるだけならシンプルですが、複雑な処理をさせたいので、pythonで個人用のラッパーツールを作りました。
作成中にdescribe系のメソッドで取得したjsonに対して何らかの方法でフィルターしたいと探したところ
jsonpathなるものをKode Kloudで発見したので試してみました。
参考にした記事、サイト
https://github.com/h2non/jsonpath-ng
https://qiita.com/takkii1010/items/0ce1c834d3a73496ccef
https://www.sukerou.com/2018/12/python-jsonxpathjsonpath.html
https://kodekloud.com/topic/lab-json-path-wild-cards/
jsonpathの使い方は上記のサイトかkodekloudの練習問題やればわかると思います。
本記事の内容
この投稿では上記サイトの内容を踏まえたうえで
実際に使った時に私がやりたかった事に対して、正解がすぐ出なかった点をメモしておきます。
サンプルのjson
※AWSのELBの取得結果を参考にサンプルとして記載しています。
samplejson = { "LoadBalancers":
[
{
"LoadBalancerArn": "hogeARN",
"DNSName": "hugaDNSname",
"State": {
"Code": "active"
},
"AvailabilityZones": [
{
"ZoneName": "hoge-region1",
"SubnetId": "hoge-subnet1",
"LoadBalancerAddresses": [100]
},
{
"ZoneName": "hoge-region2",
"SubnetId": "fuga-subnet2",
"LoadBalancerAddresses": [200]
}
]
},
{
"LoadBalancerArn": "hogeARN2",
"DNSName": "hugaDNSname2",
"State": {
"Code": "active2"
},
"AvailabilityZones": [
{
"ZoneName": "hoge-regionc3",
"SubnetId": "hoge-subnet3",
"LoadBalancerAddresses": [300]
},
{
"ZoneName": "hoge-regiona4",
"SubnetId": "fuga-subnet4",
"LoadBalancerAddresses": [400]
}
]
}
]
}
検証した事
最下層の要素でマッチさせて親の要素を取りたい
例えば、StateのCodeがactiveであることを条件にマッチさせたいとき、下記のような形でアクセスすると思います。
result = parse("$.LoadBalancers[?State.[*].Code == 'active']").find(samplejson)
list(result)[0].value
{'LoadBalancerArn': 'hogeARN', 'DNSName': 'hugaDNSname', 'State': {'Code': 'active'}, 'AvailabilityZones': [{...}, {...}]}
※$を条件式の前に書けば行けるかと思いましたが、取得できませんでした。
parse("$[?LoadBalancers.State.[*].Code =~ 'active']").find(samplejson)
[]
ただ、このアクセスの仕方だと取得したデータから最上位のLoadBalancersの要素が抜けてしまいます。
LoadBalancersの要素まで残した状態でデータが欲しければparent
を使うそうです。
result = parse("$.LoadBalancers[?State.[*].Code == 'active'].`parent`.`parent`").find(samplejson)
list(result)[0].value
{'LoadBalancers': [{...}, {...}]}
マッチさせる条件を変数にしたい
これはpythonの変数展開になりますが、記載しておきます。
先ほどのStateがactiveになっている要素を取得する例だと、以下のような記載になります。
variable = "match_word"
result = parse("$.LoadBalancers[?State.[*].Code == '%s'].`parent`.`parent`" % (variable )).find(samplejson)
pythonの変数展開は他にもやり方がありましたが、これで通ったからまぁいいかなと・・