基於python實現json數據的jsonPath(精簡版)定位及增刪改操作
by:授客 QQ:1033553122
實踐環境
win7 64
Python 3.4.0
代碼
#-*- encoding:utf-8 -*-
# author:授客
import re
def parse_sub_expr(sub_expr):
'''
解析字表達式-元素路徑的組成部分
:param sub_expr:
:return:
'''
RIGHT_INDEX_DEFAULT = '200000000' # 右側索引的默認值 未指定右側索引時使用,形如 key[2:]、key[:]
result = re.findall('\[.+\]', sub_expr)
if result: # 如果子表達式為數組,形如 [1]、key[1]、 key[1:2]、 key[2:]、 key[:3]、key[:]
array_part = result[0]
array_part = array_part.lstrip('[').rstrip(']')
key_part = sub_expr[:sub_expr.index('[')]
if key_part == '$': # 如果key為 $ ,為根,替換為數據變量 json_data
key_part = JSON_DATA_VARNAME
elif key_part == '*':
key_part == '\[.+\]' # 如果key為 * ,替換為 \[\.+\] 以便匹配 ["key1"]、["key2"]、……
else:
key_part = '\["%s"\]' % key_part
if array_part == '*': # 如果數組索引為 * ,替換為 \[\d+\] 以便匹配 [0]、[1]、……
array_part = '\[\d+\]'
else:
array_part_list = array_part.replace(' ', '').split(':')
left_index = array_part_list[0:1]
right_index = array_part_list[1:]
if left_index:
left_index = left_index[0]
if not (left_index or left_index.isdigit()): # 為空字符串、非數字
left_index = '0'
else:
left_index = '0'
if right_index:
right_index = right_index[0]
if not (right_index or right_index.isdigit()):
right_index = RIGHT_INDEX_DEFAULT # 一個比較大的值,
array_part = left_index + '-' + right_index
else:
array_part = left_index
array_part = '\[[%s]\]' % array_part # 數組索引設置為 \[[n-m]\],以便匹配[n],[n+1], ……,[m-1]
return key_part + array_part
elif sub_expr == '*':
sub_expr = '\[.+\]'
elif sub_expr == '$':
sub_expr = JSON_DATA_VARNAME
else:
sub_expr = '\["%s"\]' % sub_expr
return sub_expr
def parse_json(json_data, data_struct_link):
'''
遞歸解析json數據結構,存儲元素的路徑
:param json_data:
:param data_struct_link:
:return:
'''
if type(json_data) == type({}): # 字典類型
keys_list = json_data.keys()
for key in keys_list:
temp_data_struct_link = data_struct_link + '["%s"]' % key
if type(json_data[key]) not in [type({}), type([])]: # key對應的value值既不是數組,也不是字典
data_struct_list.append(temp_data_struct_link)
else:
parse_json(json_data[key], temp_data_struct_link)
elif type(json_data) == type([]): # 數組類型
array_length = len(json_data)
for index in range(0, array_length):
temp_json_data = json_data[index]
keys_list = temp_json_data.keys()
for key in keys_list:
temp_data_struct_link = data_struct_link + '[%s]["%s"]' % (str(index), key)
if type(temp_json_data[key]) not in [type({}), type([])]: # key對應的value值既不是數組,也不是字典
data_struct_list.append(temp_data_struct_link)
else:
parse_json(temp_json_data[key], temp_data_struct_link)
if __name__ == '__main__':
json_data = [{"data": [{
"admin": "string|集群負責人|||",
"components": [
{
"clusterId": "integer|組件所屬的集群 id|||",
"createTime": "string|組件創建時間|||",
"description": "string|組件描述|||",
"enabled": "boolean|組件是否開啟||false|",
},
{
"clusterId": "integer|組件所屬的集群 id|||",
"createTime": "string|組件創建時間|||",
"description": "string|組件描述|||",
"enabled": "boolean|組件是否開啟||false|",
}
],
"createTime": "string|集群創建時間|||",
"description": "string|集群描述|||",
"enabled": "boolean|集群是否開啟||false|",
"id": "integer|集群 id|||",
"modifyTime": "string|集群修改時間|||",
"name": "string|集群名|||"
}],
"errMsg": "string||||",
"ok": "boolean||||",
"status": "integer||||"
}]
JSON_DATA_VARNAME = 'json_data' # 存在json數據的變量名稱
data_struct_list = [] # 用於存放所有 json 元素路徑,形如 json_data[0]["data"][0]["components"][0]["enabled"]
data_struct_link = 'json_data' # 用於臨時存放單條json 元素路徑(的一部分)
parse_json(json_data, data_struct_link)
print('獲取的json元素路徑,元素值如下:')
for item in data_struct_list:
print(item, '\t', eval(item))
# 測試用表達式
# expr = '$.data[*].components[0]' # json數據為字典 形如 {……}
# expr = '$[*].data[0:1].components[*]' # json數據為數組 形如 [{……}]
expr = 'data[0:1].components[*]'
# expr = 'data[0:1].components'
# 解析表達式為正則表達式
re_pattern = ''
for sub_expr in expr.split('.'):
re_pattern += parse_sub_expr(sub_expr)
print('\n元素路徑jsonpath表達式為:%s' % expr)
print('元素路徑正則表達式re pattern為:%s' % re_pattern)
print('\njsonpath 匹配結果如下:')
re_pattern = re.compile(re_pattern)
target_set = set() # 匹配結果會有重復值,所以采用集合
for item in data_struct_list:
results = re.findall(re_pattern, item)
for result in results:
print('匹配的元素路徑jsonpath為:%s' % item)
print('正則匹配結果為:%s' % result)
target = item[0:item.index(result) + len(result)]
print('供提取數據使用的jsonpath為:%s' % target)
print('提取的結果值為:%s \n' % eval(target))
target_set.add(target)
# 通過匹配提取的目標結果,操作json串
for item in target_set:
target = eval(item)
if type(target) == type({}): # 如果為字典
# 更改鍵的值
target['clusterId'] = 10
# 新增鍵值對
target['new_key'] = 'key_value'
# 更改鍵的名稱,可以考慮先復制舊的鍵值,賦值給新的鍵,然后刪除舊的鍵
target['description_new'] = target['description']
# 刪除鍵值對
del target['description']
elif type(target) == type([]):
# 暫不實現
pass
print(json_data)
運行結果截圖: