kind: reference

JSON

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.

1. Aufbau

Objekte, Listen und Werte

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.

Was JSON nicht erlaubt

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.

2. In Programmen

Ruby

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.

JavaScript

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.

Python

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.

3. Im Terminal

jq

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.