First.No bullshit.Just show the code.And the result.
# coding:utf8
import json
# source code URL: https://blog.csdn.net/weixin_42744102/article/details/99722187
class FindKey(object):
def __init__(self, obj):
self.json_object = None
if isinstance(obj, str):
self.json_object = json.loads(obj)
elif obj != None:
self.json_object = obj
else:
raise TypeError("Unexpected object type.Can not read from NoneType")
def get_obj_contain_key(self, key):
result_list = []
self.__search_obj_contain_key(
json_object=self.json_object,
old_path="",
key=key,
result_list=result_list)
return result_list
def __search_obj_contain_key(self, json_object, old_path:str, key, result_list):
if isinstance(json_object, dict):
for k,v in json_object.items():
if k == key:
result_list.append(
{
"path": old_path,
"obj": json_object
}
)
if isinstance(v, dict) or isinstance(v, list):
self.__search_obj_contain_key(
json_object=v,
old_path= old_path + "[\"{}\"]".format(k),
key=key,
result_list=result_list
)
elif isinstance(json_object, list):
tmp_index = 0
for item in json_object:
if item == key:
result_list.append(
{
"path": old_path,
"obj": json_object
}
)
if isinstance(item, dict) or isinstance(item, list):
self.__search_obj_contain_key(
json_object=item,
old_path= old_path + "[{}]".format(tmp_index),
key=key,
result_list=result_list
)
tmp_index += 1
return None
测试代码:
json_str = "{\"a_dict\":{\"a_list\":[\"item1\", \"ip\", \"item2\"]}, "+\
"\"ip\":\"8.8.8.8\", \"b_dict\":{\"ip\":\"192.168.1.1\", "+\
"\"c_dict\":{\"ips\":[{\"ip\":\"192.168.1.2\"},"+\
"{\"ip\":\"192.168.1.3\"},{\"ip\":\"192.168.1.4\"}]} } }"
print(json_str)
json_obj = json.loads(json_str)
print(json_obj)
tool = FindKey(json_obj)
res = tool.get_obj_contain_key("ip")
for item in res:
print("path=",item["path"])
print("obj=",item["obj"])
运行结果如下:
{"a_dict":{"a_list":["item1", "ip", "item2"]}, "ip":"8.8.8.8", "b_dict":{"ip":"192.168.1.1", "c_dict":{"ips":[{"ip":"192.168.1.2"},{"ip":"192.168.1.3"},{"ip":"192.168.1.4"}]} } }
{'a_dict': {'a_list': ['item1', 'ip', 'item2']}, 'ip': '8.8.8.8', 'b_dict': {'ip': '192.168.1.1', 'c_dict': {'ips': [{'ip': '192.168.1.2'}, {'ip': '192.168.1.3'}, {'ip': '192.168.1.4'}]}}}
path= ["a_dict"]["a_list"]
obj= ['item1', 'ip', 'item2']
path=
obj= {'a_dict': {'a_list': ['item1', 'ip', 'item2']}, 'ip': '8.8.8.8', 'b_dict': {'ip': '192.168.1.1', 'c_dict': {'ips': [{'ip': '192.168.1.2'}, {'ip': '192.168.1.3'}, {'ip': '192.168.1.4'}]}}}
path= ["b_dict"]
obj= {'ip': '192.168.1.1', 'c_dict': {'ips': [{'ip': '192.168.1.2'}, {'ip': '192.168.1.3'}, {'ip': '192.168.1.4'}]}}
path= ["b_dict"]["c_dict"]["ips"][0]
obj= {'ip': '192.168.1.2'}
path= ["b_dict"]["c_dict"]["ips"][1]
obj= {'ip': '192.168.1.3'}
path= ["b_dict"]["c_dict"]["ips"][2]
obj= {'ip': '192.168.1.4'}
测试代码运行结果解读:
测试代码里的最后一个for循环里的两句print
,第一个print
是输出的是 访问包含关键字key
的那个对象在json_obj
里的路径,表示 key
在 json_obj["a_dict"]["a_list"]
这个对象里找到了。第二个print
直接输出这个对象的内容。
当然我知道,还有的人只想搜索json对象里面所有的键值对,只搜键,不搜值,只想获取键自身的值是key
的父元素。不过我觉得我的这个demonstration已经足够了,稍微改动一下就能实现这个需求,所以就没搞。真的想实现也很简单,就是把第44
~50
行代码注释掉或删掉就行了。
好啦。不好的代码,我当然要吐槽一下。原作者写的代码是真的不敢恭维。
结果生成了,应当立即返回。编程提倡尽量减少全局变量,而且结果暂存在class里面并没有意义,所以搞了个什么 self.result_list
除了实现偷懒式的全局变量应付递归需要修改同一个变量的需求,愣是没有看明白有什么用。要知道Python里面,变量都是引用对象的id,无论递归多少次,栈里的所有函数引用的result_list
依然是同一个变量,没有翻倍的内存开销。
另外吐槽一下,我搜了度娘好一会儿,居然找不到满足我这个需求的小demonstration,看了那博主的文章,以为是我需要的,结果不是我需要的,拿来用甚至重写了整个代码……找到轮子又重新造轮子,有苦说不出。