【问题标题】:Parsing JSON to find value for key解析 JSON 以查找键的值
【发布时间】:2014-12-01 17:50:50
【问题描述】:

我正在尝试解析 json 以找到所需键的值。我这样做是递归的。如果有其他更快或更有效的方法可以做到这一点,我愿意

示例 json:

{  
   "data_version":"5",
   "application":{  
      "platform":"iPhone",
      "os":"iPhone OS",
      "locale":"en_US",
      "app_version":"unknown",
      "mobile":{  
         "device":"iPhone",
         "carrier":"Verizon",
      }
   },
   "event_header":{  
      "accept_language":"en-us",
      "topic_name":"mobile-clickstream",
      "server_timestamp":1416958459572,
      "version":"1.0"
   },
   "session":{  
      "properties":{  

      }
   },
   "event":{  
      "timestamp":1416958459185,
      "properties":{  
         "event_sequence_number":97
      }
   }
}

这是我目前所拥有的

def json_scan(json_obj, key):
    result = None
    for element in json_obj:
        if str(element) == key:
            result = json_obj[element]
        else:
            if type(json_obj[element]) == DictType:
                json_scan(json_obj[element], key)
            elif type(json_obj[element]) == ListType:
                json_scan(element, key)
    return result

预期输出:

>>> json_scan(json_obj, "timestamp")
1416958459185

当我通过调试器时,我能够找到所需的值,但result = None 行将结果重置为None,在方法结束时,我得到的值是None。我不知道如何解决这个问题。我尝试删除该行但出现错误,因为结果未预设为值。

【问题讨论】:

  • 您需要分配递归调用 - 例如result = json_scan(element, key)
  • @jonrsharpe 我试过了,但该行仍然将结果重置为 None
  • 你是什么意思“这条线”?你根本不需要result = None
  • @jonrsharpe 我删除了result = None 行并添加了您为递归调用建议的调整(result = json_scan(json_obj[element], key)result = json_scan(element, key)),但我得到了在赋值错误之前引用的局部变量“result”
  • 在这种情况下,for element in json_obj: 不会在其中一个调用中发生(无论json_obj 是空的),因此您在分配之前到达return result

标签: python json


【解决方案1】:

使用 json 库来解析 json 文件(应该删除一些逗号)并使用本机 dict 类型:

def json_scan(json_obj, key):
    d = json.loads(json_obj)

    def _(dictobj, lookup):
        if lookup in dictobj.keys():
            return dictobj[lookup]
        else:
            for sub_dictobj in [d for d in dictobj.values() if type(d) == DictType]:
                result = _(sub_dictobj, lookup)
                if result:
                    return result
            return None

    return _(d, key)

更完整的版本:

def json_scan(json_obj, key):
    d = json.loads(json_obj)

    def _(dictobj, lookup):
        if lookup in dictobj.keys():
            return dictobj[lookup]
        else:
            for sub_dictobj in [d for d in dictobj.values() if type(d) == DictType]:
                result = _(sub_dictobj, lookup)
                if result:
                    return result

            # if objects in dictobj.values() are lists, go through them
            for listobject in [l for l in dictobj.values() if type(d) == list]:
                for sub_dictobj in [d for d in listobject if type(d) == DictType]:
                    result = _(sub_dictobj, lookup)
                    if result:
                        return result
            return None

    return _(d, key)

编辑(2015 年 4 月 25 日):

看了@PyCon 2015 的视频后,我遇到了 dict_digger :

http://jtushman.github.io/blog/2013/11/06/dict-digger/ https://github.com/jtushman/dict_digger

它带有测试...

【讨论】:

  • 这是一个很好的解决方案。但是,当key 在列表中的字典中时,它不会考虑。 {"events": [ { "network_type":"unknown", "properties": { "DeviceOsVersion":"iopi-iOS-8.1", "DeviceModel":"iopi-iPhone Simulator", "AppVersion":"iopi-iPhone-7.4b1 (lib 7.4b1)"}, "timestamp":1416848861703 } ], "session": { "properties":{} } }
  • 你是对的!添加列表类型测试以支持更深入的搜索解决了限制。
【解决方案2】:

您应该从 if 语句中返回结果。所以,你的代码是:

def json_scan(json_obj, key):
    for element in json_obj:
        if str(element) == key:
            result = json_obj[element]
            return result
        else:
            if type(json_obj[element]) == DictType:
                json_scan(json_obj[element], key)
            elif type(json_obj[element]) == ListType:
                json_scan(element, key)
    return None

这样,如果您找到结果,它将立即返回,而不是将其重置为 None。如果它没有找到它,它仍然会在最后返回 None。

【讨论】:

  • 它找到了密钥,但该行仍然将结果重置为 None
  • 如果删除 result = None 并且只在 if 语句中分配 result 怎么办?查看我的编辑。
  • @Liondancer 如果将 ekrah 代码中的 json_scan(...) 替换为 return json_scan(...),它是否仍然返回 None
  • @tepples 我得到 UnboundLocalError: local variable 'result' referenced before assignment 这是由于我的 JSON 中的字典为空
  • 你实际上并不需要结果。只需return json_obj[element]
【解决方案3】:

问题是您没有将递归调用分配给结果:

def json_scan(json_obj, key):
    result = None
    for element in json_obj:
        if str(element) == key:
            result = json_obj[element]
        else:
            if type(json_obj[element]) == DictType:
                result = json_scan(json_obj[element], key)
            elif type(json_obj[element]) == ListType:
                result = json_scan(element, key)
    return result

另一个问题是您的扫描不适用于列表 - json_obj[element] 仅适用于 dicts - 但由于您的数据没有列表,它现在可以工作。您应该完全删除列表处理(除非您确实有列表,否则算法需要更改)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-07
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    • 2020-10-06
    • 2019-01-07
    • 1970-01-01
    • 2020-07-27
    相关资源
    最近更新 更多