Python json parser permite claves duplicadas

Necesito analizar un archivo json que, desafortunadamente para mí, no sigue el prototipo. Tengo dos problemas con los datos, pero ya he encontrado una solución alternativa, así que solo lo mencionaré al final, tal vez alguien pueda ayudar allí también.

Así que necesito analizar entradas como esta:

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

El analizador predeterminado de json actualiza el diccionario y, por lo tanto, utiliza solo la última entrada. TENGO que guardar de alguna manera el otro también, y no tengo idea de cómo hacer esto. También TENGO que almacenar las claves en los diversos diccionarios en el mismo orden en que aparecen en el archivo, por eso estoy usando un OrderedDict para hacerlo. funciona bien, así que si hubiera alguna forma de expandir esto con las entradas duplicadas, estaría agradecido.

Mi segundo problema es que este mismo archivo json contiene entradas así:

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

La función Json.load () genera una excepción cuando alcanza esa línea en el archivo json. La única forma de solucionar esto fue quitar manualmente los soportes internos.

Gracias por adelantado

Puede usar JSONDecoder.object_pairs_hook para personalizar cómo JSONDecoder decodifica objetos. A esta función de enganche se le pasará una lista de pares (key, value) que normalmente procesa y luego se convierte en un dict .

Sin embargo, dado que los diccionarios de Python no permiten claves duplicadas (y simplemente no puede cambiar eso), puede devolver los pares sin cambios en el gancho y obtener una lista anidada de pares (key, value) cuando decodifique su 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 

Salida:

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

Cómo utilizar esta estructura de datos depende de usted. Como se indicó anteriormente, los diccionarios de Python no permiten claves duplicadas, y no hay forma de evitarlo. ¿Cómo harías una búsqueda basada en una clave? dct[key] sería ambiguo.

Por lo tanto, puede implementar su propia lógica para manejar la búsqueda de la manera que espera que funcione, o implementar algún tipo de prevención de colisiones para hacer que las claves sean únicas si no lo son, y luego crear un diccionario a partir de su lista anidada.


Editar : Como dijiste que te gustaría modificar la clave duplicada para hacerla única, así es como lo harías:

 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 

Salida:

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

La función make_unique es responsable de devolver una clave sin colisiones. En este ejemplo, solo presenta la clave con _n donde n es un contador incremental, simplemente adáptelo a sus necesidades.

Debido a que object_pairs_hook recibe los pares exactamente en el orden en que aparecen en el documento JSON, también es posible preservar ese orden usando un OrderedDict , también lo OrderedDict .

Muchas gracias, @Lukas Graf, también funcionó al implementar mi propia versión de la función de enlace.

 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 

Lo único que queda es deshacerse automáticamente de los dobles corchetes y estoy listo: D Gracias de nuevo