【技术分享】处理JSON 数据的神器: JMESPath (二) 进阶篇

前言:

【技术分享】处理JSON 数据的神器: JMESPath (一) 入门篇 文中介绍了, jmespath的基本使用方法, 如何使用 . [ ] 抽取json文档中的目标数据, 管道符 | 的作用和多字段处理 [ ] { }

本文继续介绍 JMESPath 的高阶用法, 包括数据过滤 和使用内置函数进行数据转换

1. 数据过滤

对于列表数据, jmespath支持基于另一个表达式比较来过滤数据元素的方法. 语法为                       [?expression] , 表达式中支持运算符

  1.  ==   !=   <   <=   >   >=   ,   比较运算符
  2.  ||   &&   ( )  ,  逻辑运算符
  3.  ` `   ' '  ,  转义运算符
In [1]: from jmespath import search

In [2]: data = {
    ...:   "locations": [
    ...:     {"name": "Seattle", "state": "WA", "size": 83.78},
    ...:     {"name": "New York", "state": "NY", "size": 302.6},
    ...:     {"name": "Bellevue", "state": "WA", "size": 37.51},
    ...:     {"name": "Olympia", "state": "WA", "size": 20.09}
    ...:   ]
    ...: }

In [3]: search("locations[?state == 'WA']", data)
Out[3]:
[{'name': 'Seattle', 'state': 'WA', 'size': 83.78},
 {'name': 'Bellevue', 'state': 'WA', 'size': 37.51},
 {'name': 'Olympia', 'state': 'WA', 'size': 20.09}]

In [4]: search("locations[?(state=='WA' && name=='Olympia') || state=='NY'] ", data)
Out[4]:
[{'name': 'New York', 'state': 'NY', 'size': 302.6},
 {'name': 'Olympia', 'state': 'WA', 'size': 20.09}]

在上面的表达式中,?state == 'WA'部分是一个筛选表达式。它将判断locations字段对应的列表中state字段是否等于WA, 只有返回为True的数据, 才会被抓取。

第二次解析, ?(state=='WA' && name=='Olympia') || state=='NY' 表达式组合了判断和逻辑运算, 抓取state==WA且name是Olympia的数据, 或者state是NY的数据, 可以看到返回的数据正是这两条.

为了解释转义运算符,我们需要修改一下data数据, 增加一条{"name": "TEST", "state": "TEST"}的数据

In [1]: from jmespath import search

In [2]: data = {
    ...:   "locations": [
    ...:     {"name": "TEST", "state": "TEST", "size": 20.09},
    ...:     {"name": "New York", "state": "NY", "size": 302.6},
    ...:     {"name": "Bellevue", "state": "WA", "size": 37.51}
    ...:   ]
    ...: }

In [3]: search("locations[?name == state]", data)
Out[3]: [{'name': 'TEST', 'state': 'TEST', 'size': 20.09}]

In [4]: search("locations[?size>`40`]", data)
Out[4]: [{'name': 'New York', 'state': 'NY', 'size': 302.6}]

筛选的表达式中, 没有引号的数据, 标识的是目标数据中对应字段的值, 所以表达式 ?name == state  筛选的的是 locations中 name和state相等的数据. 包括之前想要筛选state == 'WA' 的数据, 需要用 ' ' 对WA进行转义. 如果比较运算需要对数字进行操作, 需要用到另一个转义符  ` ` ,?size>`40`表达式, 筛选的size大于40的数据. 

jmespath 还支持应用内置函数对数据进行筛选,

In [5]: search("locations[?contains(name, 'New')]", data)
Out[5]: [{'name': 'New York', 'state': 'NY', 'size': 302.6}]

如表达式 ?contains(name, 'New'), 筛选name字段中包含'New'字符的数据.

2. 内置函数

jmespath 提供了丰富的内置函数, 支持对数据的简单处理操作. 包括格式转换, 数据断言,  求值等常用的功能. 函数参数中一个特殊字符 @ 将当前结果传递给函数, 类似于Python中的self, 支持的函数如下:

通用typenot_null lengthto_arrayto_stringto_number 
断言containsstarts_withends_with
数字absceilfloor
列表avgminmaxsumsortreversemapjoin
字典min_bymax_bysort_bymegekeysvalues

下面对内置函数进行一个全面的介绍:

2.1 通用函数

2.1.1 type

返回对应数据的数据类型, 示例:

GivenExpressionResult
“foo”type(@)“string”
truetype(@)“boolean”
falsetype(@)“boolean”
nulltype(@)“null”
123type(@)"number"
123.05type(@)"number"
["abc"]type(@)“array”
{"abc": "123"}type(@)“object”

2.1.2 not_null 

返回未解析为非null的第一个参数。

GivenExpressionResult
{"a": null, "b": null, "c": [], "d": "foo"}not_null(no_exist, a, b, c, d)[]
{"a": null, "b": null, "c": [], "d": "foo"}not_null(a, b, `null`, d, c)"foo"
{"a": null, "b": null, "c": [], "d": "foo"}not_null(a, b)null

2.1.3 length

返回数据的长度, 示例:

GivenExpressionResult
n/alength(`abc`)3
“current”length(@)7
“current”length(not_there)<error: invalid-type>
["a", "b", "c"]length(@)3
[]length(@)0
{}length(@)0
{"foo": "bar", "baz": "bam"}length(@)2

2.1.4 to_array

将数据转换成数组类型, 示例:

ExpressionResult
to_array(`[1, 2]`)[1, 2]
to_array(`"string"`)["string"]
to_array(`0`)[0]
to_array(`true`)[true]
to_array(`{"foo": "bar"}`)[{"foo": "bar"}]

2.1.5 to_string

ExpressionResult
to_string(`2`)"2"

2.1.6 to_number 

2.2 断言类函数

2.2.1  contains

判断目标数据是否包含特定字符, 示例:

GivenExpressionResult
n/acontains(`foobar`, `foo`)true
n/acontains(`foobar`, `not`)false
n/acontains(`foobar`, `bar`)true
n/acontains(`false`, `bar`)<error: invalid-type>
n/acontains(`foobar`, 123)false
["a", "b"]contains(@, `a`)true
["a"]contains(@, `a`)true
["a"]contains(@, `b`)false
["foo", "bar"]contains(@, `foo`)true
["foo", "bar"]contains(@, `b`)false

2.2.2 starts_with

判断目标数据是否以特定字符开头, 示例:

GivenExpressionResult
foobarbazstarts_with(@, ``foo)``true
foobarbazstarts_with(@, ``baz)``false
foobarbazstarts_with(@, ``f)``true

 2.2.3 ends_with

判断目标数据是否以特定字符开头, 示例:

GivenExpressionResult
foobarbazends_with(@, ``baz)``true
foobarbazends_with(@, ``foo)``false
foobarbazends_with(@, ``z)``true

2.3 求值类函数

2.3.1 对数字求值 abs, ceil, floor

内置函数, abs求绝对值, ceil向上取整,  floor 向下取整

ExpressionResult
abs(1)1
abs(-1)1
abs(`abc`)<error: invalid-type>
ExpressionResult
ceil(`1.001`)2
ceil(`1.9`)2
ceil(`1`)1
ceil(`abc`)null
ExpressionResult
floor(`1.001`)1
floor(`1.9`)1
floor(`1`)1

 2.3.2 列表求值 avg, min, max, sum

求平均值, 最大值和最小值, 求和, 示例:

GivenExpressionResult
[10, 15, 20]avg(@)15
[10, false, 20]avg(@)<error: invalid-type>
[false]avg(@)<error: invalid-type>
falseavg(@)<error: invalid-type>
GivenExpressionResult
[10, 15]min(@)10
["a", "b"]min(@)“a”
["a", 2, "b"]min(@)<error: invalid-type>
[10, false, 20]min(@)<error: invalid-type>
GivenExpressionResult
[10, 15]max(@)15
["a", "b"]max(@)“b”
["a", 2, "b"]max(@)<error: invalid-type>
[10, false, 20]max(@)<error: invalid-type>
GivenExpressionResult
[10, 15]sum(@)25
[10, false, 20]max(@)<error: invalid-type>
[10, false, 20]sum([].to_number(@))30
[]sum(@)0

2.3.3 列表求值 sort, reverse, map, join

对列表排序, 逆序, 映射, 聚合成字符串, 示例:

GivenExpressionResult
[b, a, c]sort(@)[a, b, c]
[1, a, c]sort(@)[1, a, c]
[false, [], null]sort(@)[[], null, false]
[[], {}, false]sort(@)[{}, [], false]
{"a": 1, "b": 2}sort(@)null
falsesort(@)null
GivenExpressionResult
[0, 1, 2, 3, 4]reverse(@)[4, 3, 2, 1, 0]
[]reverse(@)[]
["a", "b", "c", 1, 2, 3]reverse(@)[3, 2, 1, "c", "b", "a"]
"abcdreverse(@)dcba
GivenExpressionResult
{"array": [{"foo": "a"}, {"foo": "b"}, {}, [], {"foo": "f"}]}map(&foo, array)["a", "b", null, null, "f"]
[[1, 2, 3, [4]], [5, 6, 7, [8, 9]]]map(&[], @)[[1, 2, 3, 4], [5, 6, 7, 8, 9]]
GivenExpressionResult
["a", "b"]join(`, `, @)“a, b”
["a", "b"]join(``, @)``“ab”
["a", false, "b"]join(`, `, @)<error: invalid-type>
[false]join(`, `, @)<error: invalid-type>

2.3.4 字典求值 min_by, max_by, sort_by

根据字典中的key 求最大值,最小值和排序

ExpressionResult
min_by(people, &age){"age": 10, "age_str": "10", "bool": true, "name": 3}
min_by(people, &age).age10
min_by(people, &to_number(age_str)){"age": 10, "age_str": "10", "bool": true, "name": 3}
min_by(people, &age_str)<error: invalid-type>
min_by(people, age)<error: invalid-type>
ExpressionResult
max_by(people, &age){"age": 50, "age_str": "50", "bool": false, "name": "d"}
max_by(people, &age).age50
max_by(people, &to_number(age_str)){"age": 50, "age_str": "50", "bool": false, "name": "d"}
max_by(people, &age_str)<error: invalid-type>
max_by(people, age)<error: invalid-type>
ExpressionResult
sort_by(people, &age)[].age[10, 20, 30, 40, 50]
sort_by(people, &age)[0]{"age": 10, "age_str": "10", "bool": true, "name": 3}
sort_by(people, &to_number(age_str))[0]{"age": 10, "age_str": "10", "bool": true, "name": 3}

 2.3.5 字典求值 mege, keys, values

合并字典, 求字典的键数组, 字典的值数据

ExpressionResult
merge(`{"a": "b"}`, `{"c": "d"}`){"a": "b", "c": "d"}
merge(`{"a": "b"}`, `{"a": "override"}`){"a": "override"}
merge(`{"a": "x", "b": "y"}`, `{"b": "override", "c": "z"}`){"a": "x", "b": "override", "c": "z"}
GivenExpressionResult
{"foo": "baz", "bar": "bam"}keys(@)["foo", "bar"]
{}keys(@)[]
falsekeys(@)<error: invalid-type>
[b, a, c]keys(@)<error: invalid-type>
GivenExpressionResult
{"foo": "baz", "bar": "bam"}values(@)["baz", "bam"]
["a", "b"]values(@)<error: invalid-type>
falsevalues(@)<error: invalid-type>

总结:

本文介绍了jmespath的高阶用法, 包括数据过滤和内置函数的介绍. 可以通过表达式对目标JSON数据进行筛选, 并将抽取出的结果用函数进行转换, 提供了更高级的处理数据的能力. 

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值