How to find a particular json value by key?

前端 未结 8 1755
再見小時候
再見小時候 2020-11-29 04:23

There is a json like this:

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


        
相关标签:
8条回答
  • 2020-11-29 04:28

    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 @Mike Brennan's answer to another JSON-related question How to get string objects instead of Unicode from JSON?

    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.

    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 2) output:

    [u'cccc', u'aaa', u'ss']
    
    0 讨论(0)
  • 2020-11-29 04:35

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

    Code example from my answer here: 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
    
    0 讨论(0)
  • 2020-11-29 04:36

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

    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)

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

    0 讨论(0)
  • 2020-11-29 04:37

    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

    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']
    
    0 讨论(0)
  • 2020-11-29 04:38

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

    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.

    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']
    
    0 讨论(0)
  • 2020-11-29 04:40

    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.

    Any comments for optimization are welcomed!

    0 讨论(0)
提交回复
热议问题