基礎(chǔ)表達(dá)式
基礎(chǔ)表達(dá)語法寸宵,類似JavaScript的取列表值恤煞、對(duì)象值,互相組合取嵌套值刊苍。
import jmespath
print(jmespath.search('a', {"a": "foo", "b": "bar", "c": "baz"}))
print(jmespath.search('a.b.c.d', {"a": {"b": {"c": {"d": "value"}}}}))
print(jmespath.search('[1]', ["a", "b", "c", "d", "e", "f"]))
print(jmespath.search('a.b.c[0].d[1][0]', {"a": {"b": {"c": [{"d": [0, [1, 2]]}, {"d": [3, 4]}]}}}))
# 輸出
foo
value
b
1
切片
和Python的列表切片語法完全一致。
import jmespath
print(jmespath.search('[0:5]', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
print(jmespath.search('[5:10]', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
print(jmespath.search('[:5]', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
print(jmespath.search('[::2]', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
print(jmespath.search('[::-1]', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
# output
[0, 1, 2, 3, 4]
[5, 6, 7, 8, 9]
[0, 1, 2, 3, 4]
[0, 2, 4, 6, 8]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
列表和切片投影
[*]
第一個(gè)只包含三個(gè)元素濒析,盡管people數(shù)組有四個(gè)元素正什。這是因?yàn)楫?dāng)表達(dá)式第一次應(yīng)用時(shí),最后一個(gè)元素{"missing": "different"}的值為空号杏,空值不會(huì)被添加到收集的結(jié)果數(shù)組中婴氮。如果您嘗試表達(dá)式foo[*].bar
,你會(huì)看到一個(gè)null的結(jié)果盾致,因?yàn)榕cfoo
鍵相關(guān)聯(lián)的值是一個(gè)JSON對(duì)象主经,而不是一個(gè)數(shù)組,并且列表投影僅為JSON數(shù)組定義庭惜。
切片投影和列表投影幾乎是一樣的罩驻,唯一不同的是,左邊的投影是計(jì)算切片的結(jié)果护赊,它可能不包括原始列表中的所有元素鉴腻。
import jmespath
data = {
"people": [
{"first": "James", "last": "d"},
{"first": "Jacob", "last": "e"},
{"first": "Jayden", "last": "f"},
{"missing": "different"}
],
"foo": {"bar": "baz"}
}
print(jmespath.search('people[*].first', data)) # 列表投影
print(jmespath.search('people[0:3].first', data)) # 切片投影
# output
['James', 'Jacob', 'Jayden']
['James', 'Jacob', 'Jayden']
對(duì)象投影
列表投影是為JSON數(shù)組定義的,而對(duì)象投影是為JSON對(duì)象定義的百揭。可以使用*
語法創(chuàng)建對(duì)象投影蜓席。這將創(chuàng)建JSON對(duì)象的值列表器一,并將投影的右側(cè)投影到值列表上。
import jmespath
data = {
"ops": {
"functionA": {"numArgs": 2},
"functionB": {"numArgs": 3},
"functionC": {"variadic": True},
"functionD": 3
}
}
print(jmespath.search('ops.*', data)) # 創(chuàng)建JSON對(duì)象的值列表
print(jmespath.search('ops.*.numArgs', data))
# output
[{'numArgs': 2}, {'numArgs': 3}, {'variadic': True}, 3]
[2, 3]
Flatten Projections(扁平投影)
下面是列表投影和對(duì)象投影組合使用厨内,結(jié)果嵌套了很多層列表祈秕,可讀性差。
我們希望得到一個(gè)結(jié)果["running"雏胃, "stopped"请毛, "terminated", "running"]
瞭亮。在這種情況下方仿,我們不關(guān)心實(shí)例屬于哪個(gè)保留,我們只需要一個(gè)列表统翩。
這就是Flatten投影解決的問題仙蚜。要得到想要的結(jié)果,可以使用[]
而不是[*]
來平鋪列表:嘗試將上面表達(dá)式中的[*]
更改為[]
import jmespath
data = {
"reservations": [
{
"instances": [
{"state": "running"},
{"state": "stopped"}
]
},
{
"instances": [
{"state": "terminated"},
{"state": "running"}
]
}
]
}
print(jmespath.search('reservations[*].instances[*]', data))
print(jmespath.search('reservations[*].instances[*].*', data))
print(jmespath.search('reservations[*].instances[*].state', data))
# output
[[{'state': 'running'}, {'state': 'stopped'}], [{'state': 'terminated'}, {'state': 'running'}]]
[[['running'], ['stopped']], [['terminated'], ['running']]]
[['running', 'stopped'], ['terminated', 'running']]
結(jié)果就很符合期望了厂汗,看起來很順眼委粉。
import jmespath
data = {
"reservations": [
{
"instances": [
{"state": "running"},
{"state": "stopped"}
]
},
{
"instances": [
{"state": "terminated"},
{"state": "running"}
]
}
]
}
print(jmespath.search('reservations[].instances[].state', data))
# output
['running', 'stopped', 'terminated', 'running']
當(dāng)然,也可以直接使用[]
or[][]
進(jìn)行列表扁平投影娶桦。
import jmespath
data = [
[0, 1],
2,
[3],
4,
[5, [6, 7]]
]
print(jmespath.search('[*]', data))
print(jmespath.search('[]', data))
print(jmespath.search('[][]', data))
# output
[[0, 1], 2, [3], 4, [5, [6, 7]]]
[0, 1, 2, 3, 4, 5, [6, 7]]
[0, 1, 2, 3, 4, 5, 6, 7]
過濾投影
如同其名稱贾节,過濾投影的作用就是去除不滿足過濾條件的數(shù)據(jù)汁汗,語法:LHS [? <expression> <comparator> <expression>] RHS
,comparators支持這些 ==, !=, <, <=, >, >=
栗涂。
下面的例子就是獲取狀態(tài)為running
的機(jī)器名稱知牌。
import jmespath
data = {
"machines": [
{"name": "a", "state": "running"},
{"name": "b", "state": "stopped"},
{"name": "c", "state": "running"}
]
}
print(jmespath.search("machines[?state=='running'].name", data))
# output
['a', 'c']
上面那個(gè)例子的過濾條件是字符串status=="running"
,但有時(shí)候會(huì)遇到過濾條件是number整數(shù)類型戴差。
下面這個(gè)例子想獲取exchange_type==13
的數(shù)據(jù)送爸,剛開始是這么寫的[?exchange_type==13]
,也試了[?exchange_type=='13']
暖释,結(jié)果是報(bào)錯(cuò)或者是數(shù)據(jù)為空袭厂。正確的寫法是"data.exchange_config_list[?exchange_type==`13`]"
,注意不是單引號(hào)也不是雙引號(hào)球匕,是反單引號(hào)纹磺。
import jmespath
data = {"code": 200, "data": {"base_rsp": {"ret": 0, "rsp_msg": "", "seq": 0}, "exchange_config_list": [
{"already_exchange_num": 1, "exchange_id": 30217, "exchange_type": 13, "expired_day": 0, "fragments_num": 1,
"fragments_type": 1, "most_exchange_num": 1, "weight": 10000},
{"already_exchange_num": 485, "exchange_id": 90124, "exchange_type": 1, "expired_day": 10, "fragments_num": 3,
"fragments_type": 2, "most_exchange_num": 99999, "weight": 999},
{"already_exchange_num": 0, "exchange_id": 30174, "exchange_type": 13, "expired_day": 0, "fragments_num": 6570,
"fragments_type": 1, "most_exchange_num": 2, "weight": 1}]}, "elapsed_time": 7, "message": "請(qǐng)求成功", "ret": 0}
print(jmespath.search("data.exchange_config_list[?exchange_type==`13`].exchange_id", data))
# output
[30217, 30174]
多條件過濾投影,有||,&&,>,<
等等亮曹。
import jmespath
data = {"code": 200, "data": {"base_rsp": {"ret": 0, "rsp_msg": "", "seq": 0}, "exchange_config_list": [
{"already_exchange_num": 1, "exchange_id": 30217, "exchange_type": 13, "expired_day": 0, "fragments_num": 1,
"fragments_type": 1, "most_exchange_num": 1, "weight": 10000},
{"already_exchange_num": 485, "exchange_id": 90124, "exchange_type": 1, "expired_day": 10, "fragments_num": 3,
"fragments_type": 2, "most_exchange_num": 99999, "weight": 999},
{"already_exchange_num": 0, "exchange_id": 30174, "exchange_type": 13, "expired_day": 0, "fragments_num": 6570,
"fragments_type": 1, "most_exchange_num": 2, "weight": 1}]}, "elapsed_time": 7, "message": "請(qǐng)求成功", "ret": 0}
print(jmespath.search("data.exchange_config_list[?exchange_type==`13`].exchange_id", data))
print(jmespath.search("data.exchange_config_list[?exchange_type==`13` || exchange_type==`1`].exchange_id", data))
print(jmespath.search("data.exchange_config_list[?exchange_type==`13` && weight==`1`].exchange_id", data))
# output
[30217, 30174]
[30217, 90124, 30174]
[30174]
管道符|
語法
投影是JMESPath中的一個(gè)重要概念橄杨。然而,有些時(shí)候投影語義并不是您想要的照卦。一種常見的情況是式矫,您希望操作投影的結(jié)果,而不是將表達(dá)式投影到數(shù)組中的每個(gè)元素上役耕。例如采转,表達(dá)式people[*]
。First將為您提供一個(gè)包含people數(shù)組中每個(gè)人的名字的數(shù)組瞬痘。如果你想要列表中的第一個(gè)元素呢?如果你試過別人[*]故慈。第一個(gè)[0]
,您只是為people數(shù)組中的每個(gè)元素計(jì)算第一個(gè)[0]
框全,并且由于沒有為字符串定義索引察绷,最終結(jié)果將是一個(gè)空數(shù)組。要實(shí)現(xiàn)預(yù)期的結(jié)果津辩,可以使用管道表達(dá)式<表達(dá)式> | <表達(dá)式>
來指示必須停止投影拆撼。
如下面的例子所示,后面新增一個(gè)表達(dá)式對(duì)數(shù)據(jù)進(jìn)行處理喘沿,可以是過濾條件情萤,有可能是索引表達(dá)式,得到期望的數(shù)據(jù)摹恨。
import jmespath
data = {
"people": [
{"first": "James", "last": "d"},
{"first": "Jacob", "last": "e"},
{"first": "Jayden", "last": "f"},
{"missing": "different"}
],
"foo": {"bar": "baz"}
}
print(jmespath.search("people[*]", data))
print(jmespath.search("people[*] | [?last=='e']", data))
print(jmespath.search("people[*].first", data))
print(jmespath.search("people[*].first | [0]", data))
# output
[{'first': 'James', 'last': 'd'}, {'first': 'Jacob', 'last': 'e'}, {'first': 'Jayden', 'last': 'f'}, {'missing': 'different'}]
[{'first': 'Jacob', 'last': 'e'}]
['James', 'Jacob', 'Jayden']
James
MultiSelect多選
多選列表和多選散列允許您創(chuàng)建JSON元素筋岛。這允許您創(chuàng)建JSON對(duì)象中不存在的元素。多選列表創(chuàng)建一個(gè)列表晒哄,多選散列創(chuàng)建一個(gè)JSON對(duì)象睁宰。
說人話肪获,多選散列就是多選哈希,也就是多選字典柒傻。
列表多選
如下面的例子孝赫,列表多選創(chuàng)建JSON對(duì)象中不存在的元素。
import jmespath
data = {
"people": [
{
"name": "a",
"state": {"name": "up"}
},
{
"name": "b",
"state": {"name": "down"}
},
{
"name": "c",
"state": {"name": "up"}
}
]
}
print(jmespath.search("people[].name", data))
print(jmespath.search("people[].[name, state.name]", data))
# output
['a', 'b', 'c']
[['a', 'up'], ['b', 'down'], ['c', 'up']]
對(duì)象多選红符,又稱哈希多選青柄,又稱散列多選。
如下面的例子预侯,key
值是自己定義致开,value
值是表達(dá)式計(jì)算出來的。
import jmespath
data = {
"people": [
{
"name": "a",
"state": {"name": "up"}
},
{
"name": "b",
"state": {"name": "down"}
},
{
"name": "c",
"state": {"name": "up"}
}
]
}
print(jmespath.search("people[].{Name: name, State: state.name}", data))
# output
[{'Name': 'a', 'State': 'up'}, {'Name': 'b', 'State': 'down'}, {'Name': 'c', 'State': 'up'}]
Functions函數(shù)
jmespath有內(nèi)置函數(shù)處理數(shù)據(jù)萎馅,文檔如下內(nèi)置函數(shù)
length()双戳,獲取列表長度,適用于列表對(duì)象糜芳。
import jmespath
data = {
"people": [
{
"name": "b",
"age": 30
},
{
"name": "a",
"age": 50
},
{
"name": "c",
"age": 40
}
]
}
print(jmespath.search("length(people)", data))
# output
3
max_by()飒货,以某個(gè)值為維度丹允,取最大值蝠咆。
如下面例子及舍,取people
列表age
最大的列表元素
import jmespath
data = {
"people": [
{
"name": "b",
"age": 30
},
{
"name": "a",
"age": 50
},
{
"name": "c",
"age": 40
}
]
}
print(jmespath.search('max_by(people, &age)', data))
# output
{'name': 'a', 'age': 50}
contains()寒跳,是否包含某個(gè)元素
下面的例子是獲取myarray列表中包含foo
的元素。
import jmespath
data = {
"myarray": [
"foo",
"foobar",
"barfoo",
"bar",
"baz",
"barbaz",
"barfoobaz"
]
}
print(jmespath.search("myarray[?contains(@, 'foo') == `true`]", data))
# output
['foo', 'foobar', 'barfoo', 'barfoobaz']
@指向數(shù)據(jù)問題
如下面兩個(gè)例子得出屠橄,@指向當(dāng)前操作的列表對(duì)象刃唤,也有可能是字典對(duì)象结啼。
import jmespath
data1 = {
"myarray": [
"foo",
"foobar",
"barfoo",
"bar",
"baz",
"barbaz",
"barfoobaz"
]
}
data2 = [
"foo",
"foobar",
"barfoo",
"bar",
"baz",
"barbaz",
"barfoobaz"
]
print(jmespath.search("myarray[?contains(@, 'foo') == `true`]", data1)) # @指向myarray列表
print(jmespath.search("[?contains(@, 'foo') == `true`]", data2)) # @指向data2列表
# output
['foo', 'foobar', 'barfoo', 'barfoobaz']
['foo', 'foobar', 'barfoo', 'barfoobaz']
import jmespath
data1 = {
"people": [
{
"name": "b",
"age": 30
},
{
"name": "a",
"age": 50
},
{
"name": "c",
"age": 40
}
]
}
data2 = [
{
"name": "b",
"age": 30
},
{
"name": "a",
"age": 50
},
{
"name": "c",
"age": 40
}
]
print(jmespath.search('max_by(people, &age)', data1))
print(jmespath.search('max_by(@, &age)', data2))
# output
{'name': 'a', 'age': 50}
{'name': 'a', 'age': 50}
數(shù)字作為key值毅访,keys和values方法取字典的鍵值
key值是number數(shù)據(jù)類型,取值如下:
import jmespath
my_list = {
"code": 200,
"data": {
"base_rsp": {
"ret": 0,
"rsp_msg": "",
"seq": 0
},
"uid_follow_status_map": {
"17230530": 1
}
},
"elapsed_time": 9,
"message": "\u8bf7\u6c42\u6210\u529f",
"ret": 0
}
print(jmespath.search('data.uid_follow_status_map."17230530"', my_list)) #數(shù)字作為鍵值盘榨,需要用雙引號(hào)喻粹,且單引號(hào)在外邊
print(jmespath.search('values(data.uid_follow_status_map)|[0]', my_list)) #取字典的key或者value值,使用values方法和keys方法
##輸出
1
1
httprunner框架extract提取語法問題
httprunner項(xiàng)目使用jmespath提取字段草巡,但是不完全支持守呜,存在以下問題
表達(dá)式不支持傳遞參數(shù)
表達(dá)式不能格式化傳參:body.data.bbs_id_list[?exchange_type={}].formmat(type)
列表切片索引不支持負(fù)數(shù)
如body.data.bbs_id_list[-1]
,這個(gè)在httprunner執(zhí)行提取不了數(shù)據(jù)山憨,在Python執(zhí)行環(huán)境時(shí)正常的查乒。
可以用reverse
方法進(jìn)行列表反轉(zhuǎn)
print(jmespath.search('data.bbs_id_list[]', data))
print(jmespath.search('reverse(data.bbs_id_list[])', data))
print(jmespath.search('reverse(data.bbs_id_list[])|[0]', data))