JSONPath-Tester
Einen JSONPath-Ausdruck schreiben und die Treffer live sehen. RFC-9535-Syntax.
Nichts, was Sie einfügen, verlässt Ihren Browser. Die connect-src Erlaubnisliste macht daraus eine Garantie des Browsers statt eines Versprechens. Selbst überprüfen
Schreiben Sie einen JSONPath-Ausdruck und sehen Sie jeden Treffer in Ihrem eigenen Dokument, samt normalisiertem Pfad. Bearbeiten und erneut ausführen, bis er auswählt, was Sie gemeint haben.
Die Syntax hier folgt RFC 9535, dem im Februar 2024 veröffentlichten Proposed Standard der IETF. Das zählt mehr, als es klingt, denn in den siebzehn Jahren davor gab es überhaupt keine Spezifikation.
Warum der Dialekt genannt werden muss
JSONPath begann 2007 als Blogbeitrag von Stefan Goessner. Es wurde breit implementiert und nie spezifiziert, und die Implementierungen wichen in fast allem Interessanten voneinander ab: ob $.. die Wurzel einschließt, was ein negativer Index bedeutet, ob $[0,1] eine Vereinigung bildet, wie sich ein Filter bei fehlendem Schlüssel verhält und was bei einer Slice-Schrittweite von null passiert. Ein Vergleichsprojekt hat Hunderte solcher Unstimmigkeiten katalogisiert.
RFC 9535 hat das geklärt. Ein Tester, der nicht sagt, welchen Dialekt er implementiert, gibt Ihnen die Antwort, ohne die Frage zu nennen - dieser sagt es also: RFC 9535, mit den unten aufgeführten Ausnahmen.
Hier unterstützte Syntax
- $
- Die Wurzel des Dokuments. Jeder Ausdruck beginnt hier.
- .name und ['name']
- Ein benanntes Mitglied. Für Namen mit Leerzeichen oder Satzzeichen die Klammerform verwenden.
- .* und [*]
- Jedes Mitglied eines Objekts oder jedes Element eines Arrays.
- ..
- Ein Nachfahren-Segment: sucht auf dieser Ebene und auf allen darunter.
- [0] und [-1]
- Ein Array-Index. Negativ zählt vom Ende her.
- [1:5], [::2], [::-1]
- Ein Slice mit der Semantik von RFC 9535. Eine negative Schrittweite läuft rückwärts.
- [0, 2, 'name']
- Mehrere Selektoren in einem Segment, die die Vereinigung ihrer Ergebnisse liefern.
- [?<Ausdruck>]
- Ein Filter. Darin ist @ das aktuelle Element und $ die Wurzel des Dokuments. Vergleich mit == != < <= > >=, kombinierbar mit && || und !.
- length() count() match() search() value()
- Die von RFC 9535 definierten Funktionserweiterungen. match() verankert die ganze Zeichenkette, search() nicht.
Bewusst nicht unterstützt
Skriptausdrücke der Form [(...)] wurden nie spezifiziert und RFC 9535 hat sie entfernt. Der Eltern-Operator ^ ist eine Erweiterung, die manche Implementierungen hinzugefügt haben und die die RFC nicht enthält. Und @.length als Pseudo-Eigenschaft ist die Vor-RFC-Schreibweise dessen, was heute length(@) heißt; wenn Sie so etwas einfügen, sagt der Tester das, statt stillschweigend nichts zurückzugeben.
JSONPath, JMESPath, jq und JSON Pointer
Vier Wege, Teile eines JSON-Dokuments zu adressieren, für vier verschiedene Aufgaben.
- JSONPath
- Wählt eine Menge von Knoten aus. Am besten, wenn Sie alles wollen, was einem Muster entspricht, in beliebiger Tiefe. Jetzt als RFC 9535 standardisiert.
- JMESPath
- Transformiert, statt nur auszuwählen: Projektionen, Multiselect-Hashes und Pipe-Ausdrücke lassen Sie die Ausgabe umformen. Wird von der AWS CLI benutzt. Von Anfang an mit einer echten Spezifikation.
- jq
- Eine vollwertige Sprache mit angehängter Abfragesyntax. Dann sinnvoll, wenn die Operation eher nach Programmieren als nach Auswählen aussieht.
- JSON Pointer, RFC 6901
- Adressiert genau eine Stelle, ohne Platzhalter und ohne Filter. Bewusst trivial, weshalb sowohl JSON Patch als auch JSON Schema darauf setzen. Zwei Escapes: ~0 für eine Tilde und ~1 für einen Schrägstrich.
How to do this in code
Dieselbe Abfrage im Code ausführen.
py Python
# jsonpath-ng is the most complete Python implementation
from jsonpath_ng.ext import parse
expr = parse('$.store.book[?(@.price < 10)].title')
titles = [m.value for m in expr.find(data)]
# JMESPath, if you prefer a specified language with projections
import jmespath
titles = jmespath.search('store.book[?price < `10`].title', data) js JavaScript
import { JSONPath } from 'jsonpath-plus';
const titles = JSONPath({
path: '$.store.book[?(@.price < 10)].title',
json: data,
});
// Get the normalised paths rather than the values
const paths = JSONPath({ path: '$..author', json: data, resultType: 'path' }); sh jq
jq hat keinen Nachfahren-mit-Filter-Operator, deshalb werden die beiden Hälften getrennt geschrieben.
# The jq equivalent of a filtered descendant search
jq '.store.book[] | select(.price < 10) | .title' data.json
# Every value at any depth under a key
jq '.. | .author? // empty' data.json java Java
Jayway JsonPath ist älter als RFC 9535 und weicht stellenweise davon ab, besonders bei Filtern auf fehlende Schlüssel.
import com.jayway.jsonpath.JsonPath;
List<String> titles = JsonPath.read(json, "$.store.book[?(@.price < 10)].title"); Häufige Fragen
- Warum liefert mein Ausdruck nichts zurück?
- Meist eines von drei Dingen: ein Name, der wegen eines Leerzeichens oder Bindestrichs in Klammern und Anführungszeichen gehört; ein Filter, der mit einer nicht quotierten Zeichenkette vergleicht (schreiben Sie @.type == 'book', nicht @.type == book); oder ein Pfad, der ein Array annimmt, wo das Dokument ein Objekt hat. Der Tester meldet einen Parse-Fehler mit Position, wenn der Ausdruck selbst fehlerhaft ist, und ein leeres Ergebnis nur, wenn der Ausdruck gültig ist, aber nichts trifft.
- Was ist ein normalisierter Pfad?
- RFC 9535 definiert eine kanonische Schreibweise für die Position eines Treffers: Namen in Klammern und Anführungszeichen sowie numerische Indizes, etwa $['store']['book'][0]['title']. Jeder Treffer zeigt hier einen, was Ergebnisse zwischen Implementierungen vergleichbar macht.
- Ist $..* dasselbe wie $..?
- Nein, und das ist eine der Abweichungen, die die RFC geklärt hat. $..* wählt jeden Nachfahrenknoten außer der Wurzel; ein bloßes $.. ist gar kein vollständiger Ausdruck.