JSON ist eine Schreibweise für Daten, die fast jede Sprache lesen und schreiben kann: Objekte, Listen, Texte, Zahlen. Programme schicken sich JSON über HTTP und WebSockets, und viele Dateien von Werkzeugen sind JSON. Hier stehen die Regeln, die häufigen Fehler, wie Ruby, JavaScript und Python JSON lesen und schreiben, und wie jq es im Terminal zeigt.
So könnte ein Film aus der Filmdatenbank aussehen:
{ "title": "Nosferatu", "year": 1922, "runtime": 94, "genres": ["Horror", "Fantasy"], "director": { "name": "F. W. Murnau", "born": 1888 }, "watched": true, "rating": null }
| Schreibweise | Bedeutung |
|---|---|
{ "name": wert, … } |
Objekt: Namen und Werte, durch Kommas getrennt. Die Namen stehen immer in doppelten Anführungszeichen. |
[ wert, wert, … ] |
Liste (Array): Werte in einer Reihenfolge, auch gemischt |
"Nosferatu" |
Text (String), nur in doppelten Anführungszeichen; \" ist ein Anführungszeichen darin, \n ein Zeilenumbruch |
1922 · -3.5 · 6.02e23
|
Zahlen, mit Punkt statt Komma |
true · false
|
wahr, falsch |
null |
kein Wert |
Objekte und Listen lassen sich beliebig ineinander setzen: eine Liste von Filmen, jeder mit einer Liste von Genres. Leerzeichen und Zeilenumbrüche zwischen den Teilen sind egal; sie machen JSON nur lesbar.
JSON sieht aus wie ein Objekt in JavaScript, ist aber strenger. Diese Fehler kommen am häufigsten vor:
| Falsch | Richtig |
|---|---|
{ title: "Nosferatu" } |
{ "title": "Nosferatu" }: Namen brauchen Anführungszeichen. |
{ "title": 'Nosferatu' } |
{ "title": "Nosferatu" }: nur doppelte Anführungszeichen |
[1, 2, 3,] |
[1, 2, 3]: kein Komma nach dem letzten Eintrag |
// ein Kommentar |
JSON kennt keine Kommentare. Wer welche braucht, nimmt YAML. |
{ "year": 01922 } |
1922: keine führenden Nullen |
{ "rating": NaN } |
null: NaN und Infinity gibt es nicht |
Ist JSON kaputt, nennt die Fehlermeldung die Stelle, an der das Lesen scheiterte. Für ein Komma nach dem letzten Eintrag eines Objekts:
Expected double-quoted property name in JSON at position 42 (line 4 column 1) ← JavaScript
parse error: Expected another key-value pair at line 4, column 1 ← jq
unexpected token at '{ …' (JSON::ParserError) ← Ruby
Der Fehler liegt meist kurz vor der genannten Stelle, hier in der Zeile davor. jq . datei.json prüft eine Datei und nennt Zeile und Spalte.
require 'json' film = JSON.parse('{"title": "Nosferatu", "year": 1922}') puts film['title'] # Nosferatu film['watched'] = true puts JSON.generate(film) # {"title":"Nosferatu","year":1922,"watched":true} puts JSON.pretty_generate(film) # eingerückt, zum Lesen File.write('film.json', film.to_json) films = JSON.parse(File.read('films.json'))
JSON.parse macht aus Objekten Hashes mit Strings als Schlüsseln (film['title']), aus Listen Arrays. Mit JSON.parse(text, symbolize_names: true) sind die Schlüssel Symbole (film[:title]). Ist der Text kein gültiges JSON, wirft JSON.parse einen JSON::ParserError; ein Server fängt ihn ab (rescue), statt abzustürzen.
const film = JSON.parse('{"title": "Nosferatu", "year": 1922}'); console.log(film.title); // Nosferatu const text = JSON.stringify(film); // {"title":"Nosferatu","year":1922} const pretty = JSON.stringify(film, null, 2); // eingerückt mit 2 Leerzeichen const response = await fetch('/api/films'); const films = await response.json(); // die Antwort als JSON lesen
Über einen WebSocket kommen Nachrichten als Text an; JSON.parse(event.data) macht daraus wieder ein Objekt.
import json film = json.loads('{"title": "Nosferatu", "year": 1922}') print(film["title"]) # Nosferatu text = json.dumps(film, indent=2, ensure_ascii=False) # eingerückt, Umlaute bleiben with open("films.json") as f: films = json.load(f) with open("film.json", "w") as f: json.dump(film, f, indent=2)
Ohne ensure_ascii=False schreibt Python Umlaute als ü; das ist gültiges JSON, aber schlecht zu lesen.
jq liest JSON aus einer Datei oder aus einer Pipe und zeigt es eingerückt und farbig. Mit einem Filter holt es heraus, was du brauchst:
jq . film.json # alles, lesbar jq .title film.json # ein Feld: "Nosferatu" jq -r .title film.json # ohne Anführungszeichen: Nosferatu jq '.director.name' film.json # verschachtelt jq '.[] | .title' films.json # aus jedem Eintrag einer Liste jq '.[] | select(.year < 1930) | .title' films.json # nur einige jq 'length' films.json # wie viele Einträge curl -s https://api.github.com/users/octocat | jq .name
jq meldet kaputtes JSON mit Zeile und Spalte, zum Beispiel parse error: Expected another key-value pair at line 4, column 1 für ein Komma zu viel.