簡體   English   中英

如何按鍵查找特定的 JSON 值?

[英]How to find a particular JSON value by key?

有一個像這樣的 JSON:

{
  "P1": "ss",
  "Id": 1234,
  "P2": {
      "P1": "cccc"
  },
  "P3": [
      {
          "P1": "aaa"
      }
  ]
}

如何在不迭代所有 JSON 的情況下找到所有P1的值?

PS: P1可以在 JSON 中的任何位置

如果沒有方法可以做到這一點,你能告訴我如何遍歷 JSON 嗎?

正如我在其他答案中所說,我認為沒有辦法在不遍歷整個結構的情況下找到與"P1"鍵關聯的所有值。 不過我已經想出更好的方法來做到這一點它來找我一邊看着@Mike布倫南的回答另一個JSON相關的問題, 如何獲得字符串從JSON對象,而不是Unicode的?

基本思想是使用json.loads()接受的object_hook參數來觀察正在解碼的內容並檢查尋找的值。

注意:這僅在表示是 JSON object (即括在花括號{} )時才有效,如您的示例中所示。

from __future__ import print_function
import json

def find_values(id, json_repr):
    results = []

    def _decode_dict(a_dict):
        try:
            results.append(a_dict[id])
        except KeyError:
            pass
        return a_dict

    json.loads(json_repr, object_hook=_decode_dict) # Return value ignored.
    return results

json_repr = '{"P1": "ss", "Id": 1234, "P2": {"P1": "cccc"}, "P3": [{"P1": "aaa"}]}'
print(find_values('P1', json_repr))

(Python 3)輸出:

['cccc', 'aaa', 'ss']

前幾天我遇到了同樣的問題。 我最終只是搜索了整個對象並考慮了列表和字典。 以下片段允許您搜索多個鍵的第一次出現。

import json

def deep_search(needles, haystack):
    found = {}
    if type(needles) != type([]):
        needles = [needles]

    if type(haystack) == type(dict()):
        for needle in needles:
            if needle in haystack.keys():
                found[needle] = haystack[needle]
            elif len(haystack.keys()) > 0:
                for key in haystack.keys():
                    result = deep_search(needle, haystack[key])
                    if result:
                        for k, v in result.items():
                            found[k] = v
    elif type(haystack) == type([]):
        for node in haystack:
            result = deep_search(needles, node)
            if result:
                for k, v in result.items():
                    found[k] = v
    return found

deep_search(["P1", "P3"], json.loads(json_string))

它返回一個字典,其中的鍵是搜索的鍵。 Haystack 應該已經是一個 Python 對象,所以你必須在將它傳遞給 deep_search 之前執行 json.loads。

歡迎任何優化意見!

我對這個問題的處理方法會有所不同。

由於 JSON 不允許深度優先搜索,因此將 json 轉換為 Python 對象,將其提供給 XML 解碼器,然后提取您要搜索的節點

from xml.dom.minidom import parseString
import json        
def bar(somejson, key):
    def val(node):
        # Searches for the next Element Node containing Value
        e = node.nextSibling
        while e and e.nodeType != e.ELEMENT_NODE:
            e = e.nextSibling
        return (e.getElementsByTagName('string')[0].firstChild.nodeValue if e 
                else None)
    # parse the JSON as XML
    foo_dom = parseString(xmlrpclib.dumps((json.loads(somejson),)))
    # and then search all the name tags which are P1's
    # and use the val user function to get the value
    return [val(node) for node in foo_dom.getElementsByTagName('name') 
            if node.firstChild.nodeValue in key]

bar(foo, 'P1')
[u'cccc', u'aaa', u'ss']
bar(foo, ('P1','P2'))
[u'cccc', u'cccc', u'aaa', u'ss']

使用jsonjson轉換為 Python 對象,然后遞歸執行效果最佳。 這個例子確實包括遍歷列表。

import json
def get_all(myjson, key):
    if type(myjson) == str:
        myjson = json.loads(myjson)
    if type(myjson) is dict:
        for jsonkey in myjson:
            if type(myjson[jsonkey]) in (list, dict):
                get_all(myjson[jsonkey], key)
            elif jsonkey == key:
                print myjson[jsonkey]
    elif type(myjson) is list:
        for item in myjson:
            if type(item) in (list, dict):
                get_all(item, key)

將 JSON 轉換為 Python 並遞歸搜索是迄今為止最簡單的:

def findall(v, k):
  if type(v) == type({}):
     for k1 in v:
         if k1 == k:
            print v[k1]
         findall(v[k1], k)

findall(json.loads(a), 'P1')

(其中 a 是字符串)

示例代碼忽略數組。 添加它作為練習。

記住 json 只是一個字符串,使用帶有前瞻和后視的正則表達式可以非常快速地完成這項任務。

通常,json 是從對外部 api 的請求中提取的,因此包含但已注釋掉顯示其工作方式的代碼。

import re
#import requests
#import json

#r1 = requests.get( ... url to some api ...)
#JSON = str(json.loads(r1.text))
JSON = """
 {
  "P1": "ss",
  "Id": 1234,
  "P2": {
      "P1": "cccc"
  },
  "P3": [
     {
          "P1": "aaa"
     }
  ]
 }
"""
rex1  = re.compile('(?<=\"P1\": \")[a-zA-Z_\- ]+(?=\")')
rex2 = rex1.findall(JSON)  
print(rex2)

#['ss', 'cccc', 'aaa']

我認為沒有任何方法可以在不迭代整個結構的情況下找到與 P1 相關的所有值。 這是一種遞歸方法,首先將 JSON 對象反序列化為等效的 Python 對象。 為了簡化事情,大部分工作是通過遞歸私有嵌套函數完成的。

import json

try:
    STRING_TYPE = basestring
except NameError:
    STRING_TYPE = str  # Python 3

def find_values(id, obj):
    results = []

    def _find_values(id, obj):
        try:
            for key, value in obj.items():  # dict?
                if key == id:
                    results.append(value)
                elif not isinstance(value, STRING_TYPE):
                    _find_values(id, value)
        except AttributeError:
            pass

        try:
            for item in obj:  # iterable?
                if not isinstance(item, STRING_TYPE):
                    _find_values(id, item)
        except TypeError:
            pass

    if not isinstance(obj, STRING_TYPE):
        _find_values(id, obj)
    return results

json_repr = '{"P1": "ss", "Id": 1234, "P2": {"P1": "cccc"}, "P3": [{"P1": "aaa"}]}'

obj = json.loads(json_repr)
print(find_values('P1', obj))

您還可以使用生成器在 json.load() 之后搜索對象。

我在此處回答的代碼示例: https : //stackoverflow.com/a/39016088/5250939

def item_generator(json_input, lookup_key):
    if isinstance(json_input, dict):
        for k, v in json_input.iteritems():
            if k == lookup_key:
                yield v
            else:
                for child_val in item_generator(v, lookup_key):
                    yield child_val
    elif isinstance(json_input, list):
        for item in json_input:
            for item_val in item_generator(item, lookup_key):
                yield item_val

這個問題很老,但沒有100%的答案,所以這是我的解決方案:

它能做什么:

  • 遞歸算法;
  • 列表搜索;
  • object 搜索;
  • 返回它在樹中找到的所有結果;
  • 返回鍵中父級的 id

建議:

  • 學習深度優先搜索和廣度優先搜索;
  • 如果你的 json 太大,遞歸可能是個問題,研究堆棧算法
   @staticmethod
    def search_into_json_myversion(jsondata, searchkey, parentkeyname: str = None) -> list:
        found = []

        if type(jsondata) is list:
            for element in jsondata:
                val = Tools.search_into_json_myversion(element, searchkey, parentkeyname=parentkeyname)
                if len(val) != 0:
                    found = found + val
        elif type(jsondata) is dict:
            if searchkey in jsondata.keys():
                pathkey = parentkeyname + '->' + searchkey if parentkeyname != None else searchkey
                found.append({pathkey: jsondata[searchkey]})
            else:
                for key, value in jsondata.items():
                    val = Tools.search_into_json_myversion(value, searchkey, parentkeyname=key)
                    if len(val) != 0:
                        found = found + val

        return found

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM