Vai al contenuto principale
CuteJSON
↑↓ Naviga Enter Seleziona Esc Chiudi

Scheda di riferimento JSONPath, con esempi elaborati

Pubblicato 4 min di lettura Di Akash Kinkar Pandey

JSONPath e un linguaggio di query per JSON, allo stesso modo che XPath lo e per XML. E stato delineato da Stefan Goessner nel 2007, implementato in modo diverso da tutti coloro che ne avevano bisogno, e infine standardizzato come RFC 9535 nel 2024. Quella historia e perche due implementazioni JSONPath spesso discordano, e perche una scheda di riferimento e piu utile con risultati allegati che come una lista di simboli.

Ogni query qui sotto viene eseguita su questo documento. Puoi incollarla nel tester JSONPath, che carica esattamente questo come esempio.

{
  "store": {
    "book": [
      { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 },
      { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 },
      { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }
    ],
    "bicycle": { "color": "red", "price": 19.95 }
  },
  "expensive": 10
}

I selettori

Radice. $ e l'intero documento. Ogni query inizia lì.

Figlio per nome. $.store.bicycle.color restituisce "red". Un punto seguito da un nome, quante volte serve.

Nome tra virgolette. $['store']['bicycle'] e la stessa cosa scritta in un altro modo. Hai bisogno delle parentesi quando una chiave ha uno spazio, un punto o un trattino, o quando inizia con una cifra: $['first name'].

Wildcard. $.store.bicycle.* restituisce "red" e 19.95, ogni figlio di quell'oggetto. $.store.book[*] restituisce tutti e tre i libri.

Indice. $.store.book[0] e il primo libro. $.store.book[-1] e l'ultimo, contando dalla fine.

Fettina. $.store.book[0:2] restituisce i primi due libri. La fine e esclusiva, esattamente come in Python. $.store.book[::2] prende ogni secondo libro, e un passo negativo inverte: $.store.book[::-1].

Unione. $.store.book[0, 2] restituisce il primo e il terzo libro. $.store.bicycle['color', 'price'] seleziona due figli nominati contemporaneamente.

Discendente. $..price restituisce ogni prezzo a qualsiasi profondita, che qui e 8.95, 12.99, 8.99 e 19.95. Questo e il selettore verso cui le persone si rivolgono di piu e quello che costa di piu su un grande documento, perché visita ogni valore.

Filtro. $.store.book[?@.price < 10] restituisce i due libri meno cari. Il @ si riferisce al valore testato. La RFC 9535 ha eliminato le parentesi che i vecchi tutorial usano, quindi sia [?@.price < 10] che [?(@.price < 10)] appaiono nel mondo. Il tester qui accetta entrambi.

Esistenza. $.store.book[?@.isbn] restituisce solo il libro che ha un campo isbn, senza confrontarlo con nulla.

Combinare test. &&, || e ! funzionano come ci si aspetterebbe: $..book[?@.category == 'fiction' && @.price < 10].title restituisce "Moby Dick".

Perche un filtro che sembra corretto non restituisce nulla

Quasi sempre, e una incompatibilita di tipo. La specifica dice che valori di tipo diversi non sono mai uguali e non sono mai ordinati, quindi un prezzo memorizzato come "8.95" con virgolette non corrisponde a @.price < 10, e non corrisponde nemmeno a @.price == 8.95. Se un filtro non restituisce nulla, controlla i tipi nel documento prima di controllare la query.

La seconda causa e collegare il filtro al livello sbagliato. Un filtro sceglie tra i figli del valore a cui e collegato, quindi va dopo il vettore: book[?@.price < 10], non book.price[?...]. Collegato a un oggetto, testa ogni valore di proprieta di quell'oggetto invece.

Terzo, un valore mancante non e null. @.isbn == null corrisponde a un libro il cui isbn e letteralmente null, non a un libro che non ha isbn affatto. Per testare l'assenza, scrivi !@.isbn.

Dove le implementazioni discordano

L'articolo del 2007 era una proposta, non una specifica, quindi le librerie divergesero per diciassette anni. Se stai spostando una query tra strumenti, questi sono i luoghi da controllare:

  • Indici negativi e passi negativi sono ampiamente supportati ora e mancano in alcune librerie piu vecchie.
  • La forma di filtro con parentesi e l'ortografia vecchia. La RFC 9535 usa [?] nudo, e molti strumenti accettano solo una delle due.
  • La RFC definisce le funzioni length(), count(), match() e search(). Molte implementazioni le mancano o forniscono un insieme diverso con nomi diversi.
  • La RFC attribuisce ai risultati un ordine di documento. Alcune implementazioni non garantiscono questo, in particolare per i segmenti discendenti.

Il tester su questo sito implementa i selettori elencati sopra e lo dice chiaramente nella pagina, inclusa una tabella di cosa supporta. Estensioni di funzioni, percorsi assoluti dentro un filtro, e confrontare due percorsi tra loro non sono implementati, e usarne uno produce un messaggio che nomina la funzionalita invece di un errore di sintassi. Questa e una scelta deliberata: uno strumento che pretende conformita totale e poi fallisce silenziosamente su un caso limite e peggiore di uno che ti dice dove si trova il suo limite.

JSONPath o Puntatore JSON

Rispondono a domande diverse.

Un Puntatore JSON nomina esattamente un valore e risolve o non risolve. Non ha wildcard ne filtri, ed e proprio per questo che JSON Schema, JSON Patch e la maggior parte dei messaggi di errore di validazione lo usano: un indirizzo senza ambiguita e ciò che servono. /store/book/0/title significa un solo luogo.

Una query JSONPath e una ricerca. Puo restituire molti valori o nessuno, e puo filtrare. Usala quando non sai gia dove si trova quello che vuoi.

Se conosci l'indirizzo, usa un puntatore. Se stai cercando qualcosa, usa una query. Entrambi gli strumenti su questo sito riportano la riga dove si trova ogni risultato, quindi in ogni caso finisci di ritorno nel documento invece che in una lista astratta di risultati.

Torna a tutti i post