json-csv.de

Ratgeber · Format & Standards

Verschachteltes JSON flachklopfen: von Nested zu Flat-CSV

JSON kennt Tiefe, CSV kennt nur Zeilen und Spalten. Dieser Leitfaden zeigt die vier zentralen Strategien, mit denen Sie jede Verschachtelung sauber in eine flache Tabelle überführen.

8 Min Lesezeit 1.712 Wörter 4 FAQs
Jan-Tristan Rudat
Jan-Tristan Rudat Entwicklung und Konzeption
Geprüft am

JSON und CSV beschreiben Daten auf grundlegend verschiedene Weise. CSV ist ein zweidimensionales Format: Zeilen und Spalten, jede Zelle hält genau einen Wert. JSON dagegen kennt beliebig tiefe Verschachtelung. Ein Objekt kann Objekte enthalten, die wiederum Arrays enthalten, in denen erneut Objekte stehen. Sobald Sie diese Struktur in eine Tabelle pressen wollen, müssen Sie die Tiefe auflösen. Das nennt man Flachklopfen oder Flattening: Aus einem Baum wird eine Reihe von Spalten.

Es gibt dafür kein einziges richtiges Verfahren. Welche Strategie passt, hängt davon ab, was in der Verschachtelung steckt und was Sie danach mit der CSV machen. Dieser Artikel geht vier zentrale Strategien durch und zeigt für jede ein konkretes JSON-Eingangsbeispiel und das resultierende CSV. Drei davon bietet der Konverter auf json-csv.de an, den Explode (Strategie 4) nicht.

Warum CSV flach ist und JSON nicht

Eine CSV-Datei nach RFC 4180 besteht aus Datensätzen, die durch Zeilenumbrüche getrennt sind, und Feldern, die durch ein Trennzeichen getrennt sind. Der erste Datensatz ist üblicherweise die Kopfzeile mit den Spaltennamen. Es gibt keinen Mechanismus, um in einer Zelle eine weitere Tabelle oder ein Objekt zu transportieren. Eine Zelle ist ein Text, eine Zahl, ein Wahrheitswert oder leer.

JSON nach RFC 8259 hat diese Beschränkung nicht. Ein Wert kann selbst wieder ein Objekt oder Array sein, und das beliebig tief. Daraus ergibt sich das Kernproblem: Sie müssen entscheiden, wie ein Baum mit mehreren Ebenen auf eine einzige Ebene aus Spalten abgebildet wird. Drei Arten von Verschachtelung treten dabei auf, und jede braucht eine eigene Antwort:

  1. Verschachtelte Objekte, etwa user.adresse.stadt.
  2. Arrays einfacher Werte, etwa tags.
  3. Arrays von Objekten, etwa eine Liste von Bestellpositionen.

Dazu kommt der Sonderfall uneinheitlicher Datensätze, bei denen nicht jedes Objekt dieselben Schlüssel besitzt.

Strategie 1: Punkt-Pfade für verschachtelte Objekte

Verschachtelte Objekte sind der einfachste Fall. Jeder Pfad von der Wurzel zu einem Einzelwert wird zu einem Spaltennamen, wobei die Ebenen durch einen Punkt verbunden werden. Aus dem Pfad user, adresse, stadt wird die Spalte user.adresse.stadt. Das ist eindeutig, verlustfrei und lässt sich wieder zurückbauen, solange kein Schlüssel selbst einen Punkt enthält.

Betrachten Sie folgendes JSON:

{
  "id": 1,
  "name": "Anna Berg",
  "adresse": {
    "stadt": "Hamburg",
    "plz": "20095",
    "geo": {
      "lat": 53.55,
      "lng": 9.99
    }
  }
}

Beim Flachklopfen wandert jede Blattebene in eine eigene Spalte. Die Zwischenobjekte adresse und geo erscheinen nicht selbst als Spalte, sondern nur als Präfix im Pfad:

id,name,adresse.stadt,adresse.plz,adresse.geo.lat,adresse.geo.lng
1,Anna Berg,Hamburg,20095,53.55,9.99

Der Algorithmus dahinter ist eine rekursive Tiefensuche. Sie laufen über alle Schlüssel eines Objekts. Ist der Wert ein Einzelwert, schreiben Sie den aktuellen Pfad als Spaltennamen. Ist der Wert ein Objekt, hängen Sie den Schlüssel an den Pfad an und steigen eine Ebene tiefer. So entsteht für jedes Blatt genau eine Spalte.

Ein praktischer Hinweis: Wenn Ihre Schlüssel selbst Punkte enthalten, etwa "version.major", wird der Punkt als Trenner mehrdeutig. In dem Fall lohnt sich ein anderes Trennzeichen wie __. Halten Sie die Wahl fest, damit der Rückweg von CSV zu JSON eindeutig bleibt.

Strategie 2: Arrays als Index-Spalten

Arrays einfacher Werte lassen sich über ihren Index in eigene Spalten auflösen. Aus dem Array tags werden die Spalten tags[0], tags[1], tags[2] und so weiter. Der Index tritt an die Stelle des Schlüssels. Der Konverter auf json-csv.de schreibt diese Form im Modus „Eigene Spalten“.

{
  "id": 7,
  "name": "Projekt Nord",
  "tags": ["intern", "prio-hoch", "q3"]
}

Daraus wird:

id,name,tags[0],tags[1],tags[2]
7,Projekt Nord,intern,prio-hoch,q3

Diese Variante ist verlustfrei und behält die Reihenfolge der Elemente. Ihr Schwachpunkt liegt bei Arrays unterschiedlicher Länge. Die Spaltenzahl richtet sich nach dem längsten Array im gesamten Datensatz. Ein Objekt mit nur einem Tag erzeugt dann leere Zellen in den höheren Index-Spalten:

id,name,tags[0],tags[1],tags[2]
7,Projekt Nord,intern,prio-hoch,q3
8,Projekt Süd,extern,,

Bei stark schwankenden Längen wird die Tabelle dünn besetzt und schwer lesbar. Für solche Fälle ist die nächste Strategie meist die bessere Wahl.

Strategie 3: Arrays als zusammengefasster Text

Statt jedes Array-Element in eine eigene Spalte zu schreiben, können Sie das gesamte Array zu einem einzigen Text zusammenfügen. Die Elemente werden mit einem Trennzeichen verbunden, das nicht mit dem CSV-Trennzeichen kollidieren sollte, etwa ; bei einer kommagetrennten Datei.

{
  "id": 7,
  "name": "Projekt Nord",
  "tags": ["intern", "prio-hoch", "q3"]
}

ergibt mit Join über Semikolon:

id,name,tags
7,Projekt Nord,intern;prio-hoch;q3

Diese Variante hält die Spaltenzahl stabil, egal wie lang die einzelnen Arrays sind. Sie eignet sich für Anzeige und Export, etwa wenn ein Mensch die CSV in einer Tabellenkalkulation öffnet und die Tags nur lesen, nicht einzeln auswerten will. Der Preis: Die einzelnen Elemente sind nicht mehr direkt adressierbar. Eine Pivot-Auswertung pro Tag oder ein Filter auf ein einzelnes Element ist nicht mehr ohne weiteres Parsen möglich. Achten Sie zudem darauf, dass das gewählte Trennzeichen nicht selbst in den Werten vorkommt, sonst wird die spätere Rückumwandlung mehrdeutig.

Zwei weitere Modi des Konverters bleiben hier: „Nur das erste Element“ gibt intern aus, „Nur die Anzahl“ gibt 3 aus. Beide verwerfen Information und taugen nur, wenn Sie genau das wollen.

Strategie 4: Arrays explodieren in mehrere Zeilen

Sobald ein Array nicht aus einfachen Werten, sondern aus Objekten besteht, stoßen Index-Spalten und Join-Texte an ihre Grenzen. Hier hilft das Explodieren, auch Unnesting oder Normalisieren genannt. Pro Array-Element entsteht eine eigene Zeile, während die Felder der äußeren Ebene in jeder dieser Zeilen wiederholt werden. Der Konverter auf json-csv.de macht das nicht. Er schreibt solche Arrays als JSON-Text in eine Zelle oder, im Modus „Eigene Spalten“, als positionen[0].artikel und so weiter. Zum Explodieren eignen sich Python mit pandas oder SQL.

{
  "bestellung": 1001,
  "kunde": "Anna Berg",
  "positionen": [
    { "artikel": "Tastatur", "menge": 1, "preis": 49.9 },
    { "artikel": "Maus", "menge": 2, "preis": 19.5 }
  ]
}

Beim Explodieren wird die Bestellung auf zwei Zeilen verteilt, eine pro Position. Die Felder bestellung und kunde erscheinen in beiden Zeilen, die Positionsfelder werden über Punkt-Pfade flachgeklopft:

bestellung,kunde,positionen.artikel,positionen.menge,positionen.preis
1001,Anna Berg,Tastatur,1,49.9
1001,Anna Berg,Maus,2,19.5

Diese Form entspricht der Denkweise relationaler Datenbanken: Eine Bestellung mit mehreren Positionen wird zur Detailtabelle, in der jede Zeile eine Position ist. Genau diese Struktur brauchen Sie, wenn Sie danach gruppieren, summieren oder per SQL importieren wollen. Der Nachteil ist die Redundanz der äußeren Felder und die Tatsache, dass eine Zeile nicht mehr genau einem JSON-Objekt entspricht. Haben Sie mehrere Arrays auf derselben Ebene, die Sie gleichzeitig explodieren wollen, entsteht ein Kreuzprodukt, das schnell groß wird. In solchen Fällen ist es sauberer, pro Array eine getrennte CSV mit einem Fremdschlüssel auf die Bestell-ID zu erzeugen.

Uneinheitliche Schemata: die Spalten-Union

In der Praxis sind JSON-Arrays selten perfekt einheitlich. Ein Objekt hat ein Feld telefon, das nächste nicht, dafür ein Feld fax. Damit eine Tabelle entsteht, müssen Sie die Vereinigungsmenge aller vorkommenden Schlüssel bilden. Jeder Schlüssel, der in mindestens einem Objekt auftaucht, wird zur Spalte. Objekte, denen dieser Schlüssel fehlt, bekommen an dieser Stelle eine leere Zelle.

[
  { "id": 1, "name": "Anna", "telefon": "040-111" },
  { "id": 2, "name": "Ben", "fax": "040-222" },
  { "id": 3, "name": "Cleo", "telefon": "040-333", "newsletter": true }
]

Die Spalten-Union umfasst id, name, telefon, fax und newsletter. Fehlende Felder werden zu leeren Zellen:

id,name,telefon,fax,newsletter
1,Anna,040-111,,
2,Ben,,040-222,
3,Cleo,040-333,,true

Wichtig ist die Reihenfolge der Arbeitsschritte: Sie müssen den gesamten Datensatz einmal durchlaufen, um alle Schlüssel zu sammeln, bevor Sie die Kopfzeile schreiben können. Ein einziger Durchlauf reicht für die Kopfzeile nicht, wenn neue Schlüssel erst in späteren Objekten auftauchen. Der Konverter auf json-csv.de ordnet die Spalten nach dem ersten Auftreten, hier also id, name, telefon, fax, newsletter. Beachten Sie außerdem die schon angesprochene Unterscheidung zwischen einem fehlenden Schlüssel und einem Schlüssel mit Wert null. In der CSV sehen beide gleich aus, nämlich als leere Zelle.

Die Strategien im Vergleich

Die Wahl der Strategie folgt einer einfachen Logik: Was steckt in der Verschachtelung, und was wollen Sie danach damit tun? Die folgende Tabelle fasst die Abwägung zusammen.

Strategie Geeignet für Vorteil Nachteil
Punkt-Pfade Verschachtelte Objekte Verlustfrei, eindeutig, rückbaubar Bei tiefer Verschachtelung lange Spaltennamen
Index-Spalten Arrays fester Länge Verlustfrei, Reihenfolge bleibt Viele leere Zellen bei variabler Länge
Join-Text Arrays einfacher Werte variabler Länge Stabile Spaltenzahl, gut lesbar Elemente nicht einzeln auswertbar
Explode Arrays von Objekten Pro Element eine Zeile, datenbanktauglich Redundanz, Kreuzprodukt bei mehreren Arrays
Spalten-Union Uneinheitliche Objekte Robust gegen unterschiedliche Schemata Dünn besetzte Tabelle, zwei Durchläufe nötig

In realen Daten kombinieren Sie diese Verfahren. Ein typischer Datensatz hat verschachtelte Objekte, die Sie per Punkt-Pfad auflösen, ein Array einfacher Werte, das Sie zusammenfügen, und ein Objekt-Array, das Sie entweder explodieren oder in eine eigene CSV auslagern. Es gibt keinen Schalter, der alles abnimmt, weil die richtige Entscheidung von der fachlichen Bedeutung der Felder abhängt.

Verarbeitung in der Praxis

Egal welche Strategie, der erste Schritt ist immer derselbe: das JSON zuverlässig parsen. In JavaScript erledigt das JSON.parse(), das aus einem Text die entsprechende Objekt- oder Array-Struktur erzeugt. Erst auf dieser geparsten Struktur arbeiten Sie mit Ihrem Flattening-Algorithmus. Lesen Sie die Daten nie mit regulären Ausdrücken aus dem Rohtext, denn an Escapes, Unicode und verschachtelten Klammern scheitert jeder selbstgebaute Parser.

Beim Schreiben der CSV sollten Sie RFC 4180 ernst nehmen. Felder, die das Trennzeichen, Anführungszeichen oder Zeilenumbrüche enthalten, müssen in doppelte Anführungszeichen gesetzt werden, und enthaltene Anführungszeichen werden verdoppelt. Aus dem Wert Berg, Anna wird in der CSV "Berg, Anna". Wer dieses Quoting auslässt, produziert Dateien, die in der ersten Tabellenkalkulation mit Komma im Datenfeld zerbrechen.

Ein letzter Hinweis zur Reihenfolge der Spalten: Sammeln Sie zuerst alle Pfade über den gesamten Datensatz ein, legen Sie eine feste Reihenfolge fest und schreiben Sie dann erst Kopfzeile und Zeilen. So bleibt die Spaltenreihenfolge stabil, und zwei Exporte derselben Daten sind vergleichbar.

Worauf es ankommt

Flachklopfen ist kein mechanischer Vorgang, sondern eine Reihe von Entscheidungen. Verschachtelte Objekte gehen verlustfrei per Punkt-Pfad in Spalten über. Arrays einfacher Werte werden entweder als Index-Spalten verlustfrei abgebildet oder als Join-Text kompakt zusammengefasst, je nachdem, ob Sie die Elemente später einzeln brauchen. Objekt-Arrays gehören explodiert, sobald Sie pro Element auswerten wollen. Uneinheitliche Datensätze verlangen eine Spalten-Union mit einem vollständigen Durchlauf vorab. Wer diese Muster beherrscht und sauber nach RFC 4180 quotet, bekommt aus jedem tief verschachtelten JSON eine flache, weiterverarbeitbare Tabelle.

FAQ

Häufige Fragen

Wie behandle ich null-Werte beim Flachklopfen?

Ein null im JSON wird in CSV meist zur leeren Zelle. Wichtig ist die Unterscheidung zwischen „Schlüssel fehlt“ und „Schlüssel ist null“. Bei uneinheitlichen Objekten entsteht durch fehlende Schlüssel ohnehin eine leere Zelle, sodass beide Fälle in der CSV gleich aussehen. Wenn die Differenz fachlich relevant ist, schreiben Sie null als Text, wie es der Konverter auf json-csv.de optional anbietet.

Was passiert mit Arrays unterschiedlicher Länge bei der Index-Notation?

Bei tags[0], tags[1], tags[2] richtet sich die Spaltenzahl nach dem längsten Array im gesamten Datensatz. Objekte mit kürzeren Arrays bekommen in den überschüssigen Spalten leere Zellen. Das führt bei stark schwankenden Längen zu vielen leeren Feldern, weshalb sich dann eher der Join-String oder ein Explode anbietet.

Wann sollte ich Explode statt Join verwenden?

Explode lohnt sich, wenn jedes Array-Element selbst ein Objekt mit mehreren Feldern ist oder wenn Sie die Daten danach in einer Pivot-Tabelle oder Datenbank pro Element auswerten wollen. Ein Join-String reicht, solange die Array-Elemente einfache Werte sind und Sie sie nur anzeigen, nicht aggregieren möchten.

Wie verhindere ich, dass Punkt-Pfade mit echten Punkten in Schlüsseln kollidieren?

Wenn Ihre JSON-Schlüssel selbst Punkte enthalten, wird der Punkt als Trennzeichen mehrdeutig. Wählen Sie in diesem Fall ein anderes Zeichen wie den doppelten Unterstrich für die Pfadbildung und halten Sie es in einer Begleitnotiz fest. Der Konverter auf json-csv.de verwendet immer den Punkt.

Anzeige

Quellen

Worauf dieser Ratgeber sich stützt

Veröffentlicht · zuletzt geprüft
Verantwortlich: Jan-Tristan Rudat
Anzeige
Anzeige
Anzeige
Anzeige