如何通过键找到特定的json值?

时间:2022-10-26 13:35:09

There is a json like this:

有一个像这样的json:

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

How can I find all P1's value without it iterating all json?

如果没有迭代所有json,我怎样才能找到所有P1的值?

PS:P1 can be anywhere in json.

PS:P1可以在json的任何地方。

If no method can do this, can you tell me how to iterate through the json?

如果没有方法可以做到这一点,你能告诉我如何迭代json吗?

8 个解决方案

#1


6  

My approach to this problem would be different.

我对这个问题的处理方法会有所不同。

As JSON doesn't allow depth first search, so convert the json to a Python Object, feed it to an XML decoder and then extract the Node you are intending to search

由于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']

#2


15  

As I said in my other answer, I don't think there is a way of finding all values associated with the "P1" key without iterating over the whole structure. However I've come up with even better way to do that which came to me while looking at the accepted answer to a different question How to get string objects instead of Unicode from JSON?

正如我在其他答案中所说,我认为没有办法找到与“P1”键相关的所有值而不迭代整个结构。然而,我已经想出了更好的方法来做到这一点,在我看到一个不同的问题的接受答案时如何从JSON获取字符串对象而不是Unicode?

The basic idea is to use the object_hook parameter that json.loads() accepts just to watch what is being decoded and check for the sought-after value. Note: This will only work if the representation is of a JSON Object (i.e. something enclosed in curly braces {}), as in your sample json.

基本思想是使用json.loads()接受的object_hook参数来观察正在解码的内容并检查所追求的值。注意:这仅在表示是JSON对象(即大括号{}中包含的内容)时才有效,如示例json中所示。

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)

Output:

输出:

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

#3


11  

I had the same issue just the other day. I wound up just searching through the entire object and accounted for both lists and dicts. The following snippets allows you to search for the first occurrence of a multiple keys.

前几天我遇到了同样的问题。我只是搜索整个对象,并考虑了列表和序列。以下代码段允许您搜索多个键的第一个匹配项。

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))

It returns a dict with the keys being the keys searched for. Haystack is expected to be a Python object already, so you have to do json.loads before passing it to deep_search.

它返回一个dict,键是搜索的键。 Haystack预计已经是一个Python对象了,所以在将它传递给deep_search之前你必须先做json.loads。

Any comments for optimization are welcomed!

欢迎任何评论优化!

#4


6  

Using json to convert the json to Python objects and then going through recursively works best. This example does include going through lists.

使用json将json转换为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)

#5


5  

Converting the JSON to Python and recursively searching is by far the easiest:

将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')

(where a is the string)

(其中a是字符串)

The example code ignores arrays. Adding that is left as an exercise.

示例代码忽略数组。添加它作为练习留下。

#6


2  

I don't think there's any way of finding all values associated with P1 without iterating over the whole structure. Here's a recursive way to do it that first deserializes the json object in a file into an equivalent Python object. To simplify things most of the work is done via a private nested function.

我认为没有任何方法可以找到与P1相关的所有值而不迭代整个结构。这是一种递归方式,首先将文件中的json对象反序列化为等效的Python对象。为了简化操作,大多数工作都是通过私有嵌套函数完成的。

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

    def _find_values(id, obj):
        try:
            for key, value in obj.iteritems():
                if key == id:
                    results.append(value)
                elif not isinstance(value, basestring):
                    _find_values(id, value)
        except AttributeError:
            pass

        try:
            for item in obj:
                if not isinstance(item, basestring):
                    _find_values(id, item)
        except TypeError:
            pass

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

import json

with open('data.json') as json_file:
    obj = json.load(json_file)

print find_values('P1', obj)

#7


2  

Bearing in mind that json is simply a string, using regular expressions with look-ahead and look-behind can accomplish this task very quickly.

请记住,json只是一个字符串,使用具有前瞻和后视的正则表达式可以非常快速地完成此任务。

Typically, the json would have been extracted from a request to external api, so code to show how that would work has been included but commented out.

通常,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']

#8


1  

You could also use a generator to search the object after json.load().

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

Code example from my answer here: https://*.com/a/39016088/5250939

我在这里回答的代码示例:https://*.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

#1


6  

My approach to this problem would be different.

我对这个问题的处理方法会有所不同。

As JSON doesn't allow depth first search, so convert the json to a Python Object, feed it to an XML decoder and then extract the Node you are intending to search

由于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']

#2


15  

As I said in my other answer, I don't think there is a way of finding all values associated with the "P1" key without iterating over the whole structure. However I've come up with even better way to do that which came to me while looking at the accepted answer to a different question How to get string objects instead of Unicode from JSON?

正如我在其他答案中所说,我认为没有办法找到与“P1”键相关的所有值而不迭代整个结构。然而,我已经想出了更好的方法来做到这一点,在我看到一个不同的问题的接受答案时如何从JSON获取字符串对象而不是Unicode?

The basic idea is to use the object_hook parameter that json.loads() accepts just to watch what is being decoded and check for the sought-after value. Note: This will only work if the representation is of a JSON Object (i.e. something enclosed in curly braces {}), as in your sample json.

基本思想是使用json.loads()接受的object_hook参数来观察正在解码的内容并检查所追求的值。注意:这仅在表示是JSON对象(即大括号{}中包含的内容)时才有效,如示例json中所示。

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)

Output:

输出:

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

#3


11  

I had the same issue just the other day. I wound up just searching through the entire object and accounted for both lists and dicts. The following snippets allows you to search for the first occurrence of a multiple keys.

前几天我遇到了同样的问题。我只是搜索整个对象,并考虑了列表和序列。以下代码段允许您搜索多个键的第一个匹配项。

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))

It returns a dict with the keys being the keys searched for. Haystack is expected to be a Python object already, so you have to do json.loads before passing it to deep_search.

它返回一个dict,键是搜索的键。 Haystack预计已经是一个Python对象了,所以在将它传递给deep_search之前你必须先做json.loads。

Any comments for optimization are welcomed!

欢迎任何评论优化!

#4


6  

Using json to convert the json to Python objects and then going through recursively works best. This example does include going through lists.

使用json将json转换为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)

#5


5  

Converting the JSON to Python and recursively searching is by far the easiest:

将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')

(where a is the string)

(其中a是字符串)

The example code ignores arrays. Adding that is left as an exercise.

示例代码忽略数组。添加它作为练习留下。

#6


2  

I don't think there's any way of finding all values associated with P1 without iterating over the whole structure. Here's a recursive way to do it that first deserializes the json object in a file into an equivalent Python object. To simplify things most of the work is done via a private nested function.

我认为没有任何方法可以找到与P1相关的所有值而不迭代整个结构。这是一种递归方式,首先将文件中的json对象反序列化为等效的Python对象。为了简化操作,大多数工作都是通过私有嵌套函数完成的。

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

    def _find_values(id, obj):
        try:
            for key, value in obj.iteritems():
                if key == id:
                    results.append(value)
                elif not isinstance(value, basestring):
                    _find_values(id, value)
        except AttributeError:
            pass

        try:
            for item in obj:
                if not isinstance(item, basestring):
                    _find_values(id, item)
        except TypeError:
            pass

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

import json

with open('data.json') as json_file:
    obj = json.load(json_file)

print find_values('P1', obj)

#7


2  

Bearing in mind that json is simply a string, using regular expressions with look-ahead and look-behind can accomplish this task very quickly.

请记住,json只是一个字符串,使用具有前瞻和后视的正则表达式可以非常快速地完成此任务。

Typically, the json would have been extracted from a request to external api, so code to show how that would work has been included but commented out.

通常,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']

#8


1  

You could also use a generator to search the object after json.load().

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

Code example from my answer here: https://*.com/a/39016088/5250939

我在这里回答的代码示例:https://*.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