Python json解析器允许重复键

时间:2015-03-28 19:38:08

标签: python json duplicates key

我需要解析一个json文件,不幸的是,我不遵循原型。我有两个数据问题,但我已经找到了解决方法,所以我最后会提到它,也许有人可以帮助那里。

所以我需要解析这样的条目:

    "Test":{
        "entry":{
            "Type":"Something"
                },
        "entry":{
            "Type":"Something_Else"
                }
           }, ...

json默认解析器更新字典,因此只使用最后一个条目。我还要以某种方式存储另一个,我不知道如何做到这一点。我还必须按照它们在文件中出现的顺序将密钥存储在几个字典中,这就是我使用OrderedDict这样做的原因。它工作正常,所以如果有任何方法可以用重复的条目扩展它,我将不胜感激。

我的第二个问题是,这个相同的json文件包含这样的条目:

         "Test":{
                   {
                       "Type":"Something"
                   }
                }

Json.load()函数在json文件中到达该行时引发异常。我解决这个问题的唯一方法是自己手动移除内部支架。

提前致谢

3 个答案:

答案 0 :(得分:13)

您可以使用JSONDecoder.object_pairs_hook自定义JSONDecoder解码对象的方式。此钩子函数将传递一组(key, value)对,您通常会对其进行一些处理,然后变为dict

但是,由于Python词典不允许重复键(并且您根本无法更改),您可以在钩子中返回未更改的对,并在解码时获得(key, value)对的嵌套列表你的JSON:

from json import JSONDecoder

def parse_object_pairs(pairs):
    return pairs


data = """
{"foo": {"baz": 42}, "foo": 7}
"""

decoder = JSONDecoder(object_pairs_hook=parse_object_pairs)
obj = decoder.decode(data)
print obj

输出:

[(u'foo', [(u'baz', 42)]), (u'foo', 7)]

您如何使用此数据结构取决于您。如上所述,Python词典不允许重复键,并且没有办法解决这个问题。你怎么会基于一个键进行查找? dct[key]会含糊不清。

因此,您可以实现自己的逻辑来按照预期的方式处理查找,或者实现某种类型的冲突避免,以便在密钥不可用时使密钥唯一,然后然后创建嵌套列表中的字典。


修改:既然您说要修改重复密钥以使其唯一,那么您就是这样做的:

from collections import OrderedDict
from json import JSONDecoder


def make_unique(key, dct):
    counter = 0
    unique_key = key

    while unique_key in dct:
        counter += 1
        unique_key = '{}_{}'.format(key, counter)
    return unique_key


def parse_object_pairs(pairs):
    dct = OrderedDict()
    for key, value in pairs:
        if key in dct:
            key = make_unique(key, dct)
        dct[key] = value

    return dct


data = """
{"foo": {"baz": 42, "baz": 77}, "foo": 7, "foo": 23}
"""

decoder = JSONDecoder(object_pairs_hook=parse_object_pairs)
obj = decoder.decode(data)
print obj

输出:

OrderedDict([(u'foo', OrderedDict([(u'baz', 42), ('baz_1', 77)])), ('foo_1', 7), ('foo_2', 23)])

make_unique函数负责返回无冲突密钥。在此示例中,它仅使用_n后缀键,其中n是增量计数器 - 只需根据您的需要进行调整。

因为object_pairs_hook完全按照它们在JSON文档中出现的顺序接收对,所以也可以使用OrderedDict来保留该顺序,我也包括它。

答案 1 :(得分:0)

非常感谢@Lukas Graf,我通过实现我自己的钩子函数版本来实现它

def dict_raise_on_duplicates(ordered_pairs):
  count=0
  d=collections.OrderedDict()
  for k,v in ordered_pairs:
      if k in d:
          d[k+'_dupl_'+str(count)]=v
          count+=1
      else:
          d[k]=v
  return d

只剩下剩下的就是自动摆脱双括号而且我已经完成了:D再次感谢

答案 2 :(得分:0)

如果您希望将这些重复的键转换为数组,而不是使用单独的副本,则可以完成以下工作:

def dict_raise_on_duplicates(ordered_pairs):
    """Convert duplicate keys to JSON array."""
    d = {}
    for k, v in ordered_pairs:
        if k in d:
            if type(d[k]) is list:
                d[k].append(v)
            else:
                d[k] = [d[k],v]
        else:
           d[k] = v
    return d

然后您只需使用:

dict = json.loads(yourString, object_pairs_hook=dict_raise_on_duplicates)