2016-03-24 3 views
2

Ich rufe viele Webdienste in Python auf, die JSON-formatierten Text zurückgeben, der die gleichen Daten beschreibt, aber alle sind unterschiedlich strukturiert. Anstatt ein Dutzend Möglichkeiten zum Durchlaufen der Daten zu schreiben, versuche ich, einen gemeinsamen Basispfad und einen gemeinsamen Feldnamen zu erstellen, verstehe aber jetzt nicht, um einen dynamischen Namen für das gewünschte Feld zu erstellen.Erstellen eines dynamischen Pfades zum Ergreifen von Variablen aus JSON in Python

service1 die Adresse nennt, "addr1", während service2 es nennt, "address1".

service1 JSON Pfad zu den Addresse: [ "Ergebnisse"] [0] [ "Orte"] [0] [ "addr1"].

service2 JSON-Pfad zur Adresse: ["query"] [0] ["address1"].

service1 Antwort:

{ 
    "results":[ 
     { 
      "providedLocation":{ 
       "location":"123 Main St. Whoville" 
      }, 
      "locations":[ 
       { 
       "addr1":"123 Main St.", 
       "city":"Whoville" 
       } 
      ] 
     } 
    ] 
} 

Aus meiner häufigsten verwendeten Begriffe translation.ini

[service1] 
base_path = '["results"][0]["locations"]' 
field  = "addr1" 
[service2] 
base_path = '["query"]' 
field  = 'address1' 

Ich Looping durch die Adressenstellen zurückgegeben, wie diese Datei:

j   = json.loads(response.text) 
try: 
    for i in range(0,count_the_results()): 
     street_number = j[base_path][i][field] # multiple locations returned 

except KeyError: 
    print("street_number error again") 

Ich habe versucht mit eval(), aber es lässt die Klammern ([0]), die bricht den Pfad

j[eval(base_path)] 

Ich versuchte, die base_path in Stücke brechen, aber eval bringt mich noch

base_path = '["results"][0]' 
locations = '["locations"]' 
j[eval(str(base_path)+str(locations))] 

ich Schlüssel verwenden können, aber immer noch den einzigartigen Weg bauen müssen irgendwie

j.get ("Ergebnisse", {}) [0] .get ("Orte") [i] [field]

Kann jemand bitte darauf hinweisen, was ich bei der Erstellung des Pfades vermisse?

+0

Gibt es einen Grund, warum Sie immer das erste Ergebnis jeder Liste verwenden? Beide Servicemodelle in Ihren Beispielen unterstützen mehrere Adressen. sollten Sie nicht so codieren, dass Sie alle damit umgehen können? – Joe

+0

gute Frage, Joe. Der "base_path" ist der Teil, den ich als statischen Teil der Antwort identifiziert habe - immer 1 Punkt, und zufällig wird er "Ergebnisse" (Plural) genannt. Diesem folgt eine unbekannte Liste von Adressen, die in meinem Beispiel um [i] vor dem gewünschten Feld erhöht wird. Danke für Ihre Antwort. – jim

+0

Sie können immer eine Schritt-für-Schritt-Methode ausführen, bei der Sie die Schlüssel betrachten, wenn es sich um eine bestimmte Zeichenfolge handelt. Auf diese Weise brauchen Sie nur den Namen der Variablen. –

Antwort

1

Man könnte es so machen:

def get_item(response, path): 
    for item in path: 
     response = response[item] 
    return response 

# Assume we need the string 'qwerty' 
spam = {'spam': ['eggs', {'13': 'qwerty'}], 'eggs': 123} 
# Then that will be our path: 
path = ['spam', 1, '13'] 

print get_item(spam, path) 

Er druckt 'qwerty'.


Der kurzgeschlossene und effizienter (aber wahrscheinlich weniger verständlich) Weg, dies zu tun, ist builtin reduce Funktion wie das verwenden:

def get_item(response, path): 
    return reduce(lambda x, y: x[y], path, response) 

Das andere Problem ist, wie man den Pfad zu speichern, in der Datei .ini. Mein Vorschlag wäre, es im JSON-Format zu schreiben und dann an json.loads() zu übergeben, wodurch Sie den Pfad wie in meinem Beispiel erhalten.

base_path = '["results", 0, "locations"]' 

Sie erhalten die Zeichenfolge '["results", 0, "locations"]' aus Ihrer config (es könnte ein Problem sein, oder?), Gibt sie an json.loads

path = json.loads(path_string) 

und Sie es in get_item Funktion nutzen zu können.

+0

Ich werde deine Vorschläge testen, Ilya. Ich dachte nicht daran, Werte aus meiner eigenen Datei mit JSON zu laden, also habe ich es nach Stunden der Frustration für ConfigParser umgeschrieben. – jim

+0

@jim Es tut mir leid, dass es dich frustriert hat, ich schlug es vor, weil ich dachte, du könntest einfach eine JSON-Zeichenfolge (und jede andere Zeichenfolge) in deine Konfiguration einfügen. Hat mein Vorschlag funktioniert, nachdem du dein Programm so umgeschrieben hast, dass du 'configparser' verwendest? –

+0

Entschuldigung für das Missverständnis, ich wollte nicht, dass du mich überhaupt frustriert hast - es war alles selbstverschuldet :). Ihre Antwort ist großartig und ich verwende es Testergebnisse von jedem Web-Service-Provider. Du hast meinen Tag wirklich mit deinem Vorschlag gemacht und ich schätze es. Ich werde dies als die Antwort markieren. – jim

Verwandte Themen