JSONPath in Python: come analizzare i file JSON con Python
Attualmente JSON è uno dei formati più importanti per lo scambio di dati fra applicazioni, specialmente sul web. JSONPath è un linguaggio di query che consente di estrarre dati specifici da oggetti JSON. In questo contesto ti spieghiamo come implementare JSONPath in Python e ti proponiamo alcuni esempi facili da capire.
Cos’è JSONPath di Python?
JSON è un formato di file intersistema, utilizzato per agevolare e migliorare lo scambio di dati strutturati tra applicazioni. I file JSON sono costituiti da coppie chiave-valore elencate (dall’inglese: “key-value pairs”). I valori in JSON possono essere espressi con diversi tipi di dati, compresi valori primitivi e oggetti. Gli oggetti, a loro volta, possono contenere le proprie coppie chiave-valore. Grazie alla sua ampia adozione nei sistemi moderni, JSON è adatto per il trasferimento di dati tra applicazioni, sia a livello locale che su internet.
Tuttavia, non tutte le applicazioni hanno bisogno di tutti i dati presenti in un file JSON. In questi casi si può usare JSONPath. JSONPath è un linguaggio di query che consente di estrarre in modo mirato informazioni specifiche da oggetti JSON. Nella maggior parte dei linguaggi di programmazione, JSONPath deve essere importato da una libreria esterna. Poiché tali librerie devono essere implementate separatamente per ogni lingua, le diverse librerie possono differire leggermente fra loro.
Il modulo jsonpath-ng in Python
jsonpath-ng
è l’implementazione più comune di JSONPath. Esistono anche altre implementazioni di JSONPath per Python, come ad esempio jsonpath
e jsonpath-rw
. Tuttavia, queste sono meno note e complete, per cui in questo articolo ci concentreremo solo su jsonpath-ng
.
Installazione
Puoi facilmente installare jsonpath-ng
dalla shell. Per farlo basta digitare il comando pip install jsonpath-ng
.
L’installazione si effettua utilizzando il gestore di pacchetti pip, predefinito per Python. Prima di iniziare è importante assicurarsi che pip sia installato nel sistema e nel caso in cui non sia presente, è necessario procedere con l’installazione. Per ulteriori informazioni visita il sito web di pip.
Sintassi
Puoi usare JSONPath per eseguire query complesse su oggetti JSON. A tal fine, nel modulo sono presenti diversi metodi, operatori ed espressioni atomiche che possono essere utilizzati per selezionare e interrogare dati specifici. I due metodi principali di JSONPath sono parse()
e find()
. parse()
consente di definire le query che possono poi essere referenziate varie volte. Con find()
è possibile eseguire queste query su dati JSON per estrarre valori concreti. Per chiarire meglio il concetto guardiamo l’esempio qui sotto.
import json
import jsonpath_ng as jp
raw_data = '''
{
"nome": "Johannes",
"età": 30,
"città di residenza": "Como"
}
'''
json_object = json.loads(raw_data)
nome_query = jp.parse("$.nome")
result = nome_query.find(json_object)
print(result[0].value) # Output: Johannes
PythonNell’esempio abbiamo trasformato i dati JSON, espressi sotto forma di stringa, in un oggetto dizionario utilizzando la funzione json.loads
. Questo è il formato più adatto per lavorare con Python. Nel momento in cui abbiamo creato l’oggetto nome_query
, abbiamo definito la query "$.nome"
per ottenere il valore corrispondente a “nome”. Successivamente, questa operazione è stata applicata all’oggetto JSON utilizzando il metodo find()
. Il risultato della query è stato assegnato alla variabile result
e successivamente recuperato tramite result[0].value
.
Per consentire a Python di interpretare dati JSON da una stringa o da un file JSON, è necessario includere il modulo Python json
come evidenziato nell’esempio precedente. Successivamente è possibile convertire le stringhe e i file in un formato che può essere letto da Python utilizzando le funzioni loads()
o load()
.
Il metodo find non fornisce solo il valore desiderato, ma include anche informazioni contestuali aggiuntive, ad esempio il percorso del valore cercato. Tali informazioni sono restituite sotto forma di lista, in cui il valore cercato presenta l’indice 0. Pertanto, per ottenere il valore desiderato, è possibile utilizzare result[0].value
.
Nell’esempio precedente, abbiamo utilizzato il simbolo del dollaro per definire la query. Questa è un’espressione atomica con la quale si fa riferimento all’oggetto root di JSON. Tutti gli operatori e le proposizioni logiche sono elencati nella seguente tabella.
Proposizione/Operatore | Significato | Esempio | Spiegazione |
---|---|---|---|
$
|
Oggetto root | $.marcus.età
|
Accede al valore della chiave “età” nell’oggetto “marcus”. |
.
|
Campo di un oggetto | $.marcus
|
Accede a “marcus”, dove “marcus” è un campo dell’oggetto root. |
..
|
Ricerca ricorsiva di un campo. Vengono esaminati anche i campi degli oggetti figli. | $.people..età
|
Ritorna tutte le occorrenze del campo “età” in “people” e nei suoi oggetti figli. |
[x]
|
Elemento di un array | $.people[5]
|
Accede al sesto elemento (indice 5) dell’array “people”. |
\*
|
Segnaposto per numero, usato soprattutto in combinazione con cicli for | $.people[\*]
|
Accede a un campo in “people”. In combinazione con un ciclo for, ogni campo viene ritornato in sequenza. |
Oltre alle espressioni e agli operatori, ci sono alcuni filtri da usare per rendere la ricerca ancora più specifica. Nell’implementazione Python di JSONPath è possibile collegare tali filtri anche con gli operatori Python. Tutti i simboli utilizzabili in relazione ai filtri sono riportati nella tabella sottostante con degli esempi.
Simboli | Significato | Esempio | Spiegazione |
---|---|---|---|
.[?(filter) ]
|
Sintassi generale per i filtri. Le parentesi tonde possono essere omesse. | $.people[?(@.nome == "Anna")]
|
Trova persone il cui nome è “Anna”. |
@
|
Oggetto attualmente analizzato, usato spesso in concomitanza con cicli for. | $.people[?(@.età < 50)]
|
Trova i campi “people” il cui valore relativo a “età” è inferiore a 50. |
< , > , <= , >= , == e !=
|
Operatori di comparazione grazie ai quali è possibile filtrare alcuni risultati di ricerca. | $.people[@.età < 50 & @.età > 20]
|
Trova persone la cui età è compresa fra i 20 e i 50 anni. |
&
|
E logico | $.people[?(@.luogo di residenza == 'Roma' & @.età > 40)]
|
Trova persone più vecchie di 40 anni e che vivono a Roma. |
Se desideri usare un filtro devi includere il modulo jsonpath_ng.ext
e farvi riferimento quando chiami parse()
.
Esempio di utilizzo per JSONPath in Python
import json
import jsonpath_ng as jp
import json
import jsonpath_ng as jp
# Dati JSON come stringa
data = """
{
"città": [
{
"nome": "Roma",
"provincia": "Lazio",
"abitanti": 2873000
"èCapitale": true,
"quartiere testaccio": {
"abitanti": 7671
}
},
{
"nome": "Milano",
"provincia": "Lombardia",
"abitanti": 1361908,
"èCapitale": false
},
{
"nome": "Firenze",
"provincia": "Toscana",
"abitanti": 382258,
"èCapitale": false
},
{
"nome": "Venezia",
"provincia": "Veneto",
"abitanti": 261905
}
]
}
"""
# Converti dati da stringa a dizionario
json_data = json.loads(data)
# Query: nomi di tutte le città
query1 = jp.parse("città[*].nome")
for match in query1.find(json_data):
print(match.value) # Output: Roma, Milano, Firenze, Venezia
importare # jsonpath_ng.ext per utilizzare il filtro
import jsonpath_ng.ext as jpx
# Query: nome di tutte le città che hanno meno di 1 milione di abitanti
query2 = jpx.parse("$.città[?@.abitanti < 1000000].nome")
for match in query2.find(json_data):
print(match.value) # Output: Firenze, Venezia
# Tutti i campi riportanti il titolo "abitanti"
query3 = jp.parse("$.città..abitanti")
match = query3.find(json_data)
for i in match:
print(i.value) # Output: 2873000, 7671, 1361908, 382258, 261905
# Nome di tutte le città che non si chiamano "Roma"
query4 = jpx.parse('$.città[?(@.nome != "Roma")].nome')
for match in query4.find(json_data):
print(match.value) # Output: Milano, Firenze, Venezia
PythonIn questo esempio, i dati JSON sono specificati come stringa e poi convertiti nell’oggetto dizionario utilizzando loads()
. Nell’oggetto root è compreso un solo array, che a sua volta contiene 4 città. Ciascuna città ha 4 campi, che a loro volta comprendono i seguenti dati:
- Nome della città
- Provincia della città
- Numero di abitanti
- Se la città è la capitale italiana o no
Come campo accessorio, Roma ha un oggetto intitolato “Quartiere Testaccio”, che a sua volta contiene un valore relativo al numero di abitanti.
Dopo aver convertito i dati in un formato adeguato, vengono eseguite 4 diverse query, le cui funzioni e risultati vengono inseriti nell’esempio sotto forma di commenti. Come potrai notare, la terza query restituisce cinque valori. Questo avviene perché l’operatore ..
esegue una ricerca ricorsiva dei campi adatti. Ciò significa che vengono analizzati tutti gli oggetti e tutti i loro figli. Per questo motivo il numero di abitanti del quartiere Testaccio compare nella lista degli abitanti delle città.
La combinazione di JSON e Python è uno strumento versatile per la programmazione internet. Se stai lavorando a un’applicazione web e desideri pubblicarla in modo rapido, facile e diretto via Git, Deploy Now di IONOS è la soluzione perfetta per te.