L'importation depuis JSON
peut obtenir des structures très complexes et imbriquées. Par exemple:
{u'body': [{u'declarations': [{u'id': {u'name': u'i',
u'type': u'Identifier'},
u'init': {u'type': u'Literal', u'value': 2},
u'type': u'VariableDeclarator'}],
u'kind': u'var',
u'type': u'VariableDeclaration'},
{u'declarations': [{u'id': {u'name': u'j',
u'type': u'Identifier'},
u'init': {u'type': u'Literal', u'value': 4},
u'type': u'VariableDeclarator'}],
u'kind': u'var',
u'type': u'VariableDeclaration'},
{u'declarations': [{u'id': {u'name': u'answer',
u'type': u'Identifier'},
u'init': {u'left': {u'name': u'i',
u'type': u'Identifier'},
u'operator': u'*',
u'right': {u'name': u'j',
u'type': u'Identifier'},
u'type': u'BinaryExpression'},
u'type': u'VariableDeclarator'}],
u'kind': u'var',
u'type': u'VariableDeclaration'}],
u'type': u'Program'}
Quelle est la façon recommandée de marcher sur des structures complexes comme ci-dessus?
En dehors de quelques listes, il existe principalement des dictionnaires, la structure peut devenir encore plus imbriquée, j'ai donc besoin d'une solution générale.
Si vous avez seulement besoin de parcourir le dictionnaire, je vous suggère d'utiliser une fonction récursive walk
qui prend un dictionnaire puis parcourt récursivement ses éléments. Quelque chose comme ça:
def walk(node):
for key, item in node.items():
if item is a collection:
walk(item)
else:
It is a leaf, do your thing
Si vous souhaitez également rechercher des éléments ou interroger plusieurs éléments répondant à certains critères, jetez un œil au module jsonpath .
Au lieu d'écrire votre propre analyseur, selon la tâche, vous pouvez étendre les encodeurs et décodeurs à partir du module de bibliothèque standard json
.
Je le recommande surtout si vous devez encoder des objets appartenant à des classes personnalisées dans le json. Si vous devez effectuer une opération qui pourrait être effectuée également sur une représentation sous forme de chaîne du json, pensez également à itérer JSONEncoder ().
Pour les deux, la référence est http://docs.python.org/2/library/json.html#encoders-and-decoders
Si vous connaissez la signification des données, vous souhaiterez peut-être créer une fonction parse
pour transformer les conteneurs imbriqués en une arborescence d'objets de types personnalisés. Vous utiliseriez ensuite les méthodes de ces objets personnalisés pour faire tout ce que vous devez faire avec les données.
Pour votre exemple de structure de données, vous pouvez créer Program
, VariableDeclaration
, VariableDeclarator
, Identifier
, Literal
et BinaryExpression
classes, puis utilisez quelque chose comme ça pour votre analyseur:
def parse(d):
t = d[u"type"]
if t == u"Program":
body = [parse(block) for block in d[u"body"]]
return Program(body)
else if t == u"VariableDeclaration":
kind = d[u"kind"]
declarations = [parse(declaration) for declaration in d[u"declarations"]]
return VariableDeclaration(kind, declarations)
else if t == u"VariableDeclarator":
id = parse(d[u"id"])
init = parse(d[u"init"])
return VariableDeclarator(id, init)
else if t == u"Identifier":
return Identifier(d[u"name"])
else if t == u"Literal":
return Literal(d[u"value"])
else if t == u"BinaryExpression":
operator = d[u"operator"]
left = parse(d[u"left"])
right = parse(d[u"right"])
return BinaryExpression(operator, left, right)
else:
raise ValueError("Invalid data structure.")
Peut-être peut aider:
def walk(d):
global path
for k,v in d.items():
if isinstance(v, str) or isinstance(v, int) or isinstance(v, float):
path.append(k)
print "{}={}".format(".".join(path), v)
path.pop()
Elif v is None:
path.append(k)
## do something special
path.pop()
Elif isinstance(v, dict):
path.append(k)
walk(v)
path.pop()
else:
print "###Type {} not recognized: {}.{}={}".format(type(v), ".".join(path),k, v)
mydict = {'Other': {'Stuff': {'Here': {'Key': 'Value'}}}, 'root1': {'address': {'country': 'Brazil', 'city': 'Sao', 'x': 'Pinheiros'}, 'surname': 'Fabiano', 'name': 'Silos', 'height': 1.9}, 'root2': {'address': {'country': 'Brazil', 'detail': {'neighbourhood': 'Central'}, 'city': 'Recife'}, 'surname': 'My', 'name': 'Friend', 'height': 1.78}}
path = []
walk(mydict)
Produira une sortie comme celle-ci:
Other.Stuff.Here.Key=Value
root1.height=1.9
root1.surname=Fabiano
root1.name=Silos
root1.address.country=Brazil
root1.address.x=Pinheiros
root1.address.city=Sao
root2.height=1.78
root2.surname=My
root2.name=Friend
root2.address.country=Brazil
root2.address.detail.neighbourhood=Central
root2.address.city=Recife
Quelques ajouts à la solution ci-dessus (pour gérer json, y compris les listes)
#!/usr/bin/env python
import json
def walk(d):
global path
for k,v in d.items():
if isinstance(v, str) or isinstance(v, int) or isinstance(v, float):
path.append(k)
print("{}={}".format(".".join(path), v))
path.pop()
Elif v is None:
path.append(k)
# do something special
path.pop()
Elif isinstance(v, list):
path.append(k)
for v_int in v:
walk(v_int)
path.pop()
Elif isinstance(v, dict):
path.append(k)
walk(v)
path.pop()
else:
print("###Type {} not recognized: {}.{}={}".format(type(v), ".".join(path),k, v))
with open('abc.json') as f:
myjson = json.load(f)
path = []
walk(myjson)