Zum Inhalt springen
jsonbeautifiers
Deutsch

Verschachteltes JSON nach CSV abflachen, ohne Daten zu verlieren

Jeder JSON-nach-CSV-Konverter trifft ein Dutzend undokumentierter Entscheidungen für Sie. Das sind die Entscheidungen.

Jede Aussage auf dieser Seite ist entweder gemessen oder belegt. Wo sie keines von beidem ist, steht das dabei.

Schicken Sie das durch fast jeden beliebigen Konverter:

[
  { "id": 1, "name": "Ada", "tags": ["admin"] },
  { "id": 2, "name": "Grace", "tags": ["admin", "ops"], "team": { "name": "core" } }
]

Viele geben Ihnen drei Spalten: id, name, tags. Das Objekt team ist weg. Nicht abgeschnitten, nicht gemeldet, einfach nicht da, weil der Konverter die Schlüssel des ersten Objekts gelesen und für das Schema gehalten hat.

CSV ist ein Rechteck: eine feste Spaltenmenge, ein Skalar pro Zelle. JSON ist ein Baum mit optionalen Schlüsseln, beliebiger Tiefe und Arrays an jeder Stelle. Es gibt keine korrekte Abbildung zwischen beiden, nur eine Menge von Regeln, und die Konverter, die sich einfach anfühlen, sind die, die die Regeln für Sie ausgewählt haben, ohne es zu sagen.

Spalten ermitteln: die Vereinigung, nicht die erste Zeile

Es gibt zwei Wege, die Spalten festzulegen. Alle Zeilen durchgehen und die Vereinigung der Blattpfade sammeln, oder ein Objekt lesen und dessen Schlüssel nehmen.

Der zweite ist keine Performance-Optimierung, sondern Datenverlust mit einer plausiblen Ausrede. Papa Parse bezieht seine Felder aus den Schlüsseln des ersten Objekts, sofern Sie keine explizite columns-Option übergeben:

Papa.unparse([{ a: 1 }, { a: 2, b: 3 }]);
// "a\r\n1\r\n2"   die Spalte b hat nie existiert

Papa.unparse(rows, { columns: ['a', 'b'] });
// die Vereinigung liefern Sie selbst

json_normalize von pandas nimmt die Vereinigung, was einer der Gründe ist, warum Leute darauf zurückgreifen. Der Preis: Ein dünn besetztes Dokument ergibt eine breite, größtenteils leere Tabelle, und das ist die ehrliche Darstellung eines dünn besetzten Dokuments. Wenn Sie weniger Spalten wollen, werfen Sie sie absichtlich weg.

Streaming macht das wirklich schwierig: Bei NDJSON kennen Sie die Spaltenmenge erst nach der letzten Zeile, Sie puffern also die Datei oder machen zwei Durchläufe.

Verschachtelte Objekte und der Trenner, den man offenlegen muss

Verschachtelte Objekte flachen zu Punktpfaden ab, aus {"team": {"name": "core"}} wird also team.name. pandas nimmt standardmäßig . und lässt Sie das ändern:

pd.json_normalize({"user": {"name": {"first": "Ada"}}})
# Spalte: user.name.first

pd.json_normalize(data, sep="__")
# Spalte: user__name__first

Der Trenner muss konfigurierbar sein, weil ein Punkt ein legales Zeichen in einem JSON-Schlüssel ist. Diese beiden Dokumente flachen zur selben Spalte ab:

{ "a": { "b": 1 } }
{ "a.b": 1 }

Sobald sie kollidieren, ist der Rückweg Raterei, und ein Konverter, der eines das andere stillschweigend überschreiben lässt, hat eine Datei erzeugt, die sich in der falschen Form rekonstruiert. Wählen Sie entweder einen Trenner, der in Ihren Schlüsseln nicht vorkommt, oder escapen Sie ihn dort, wo er in einem auftaucht. Nehmen Sie nicht an, Punkte kämen in Schlüsseln nie vor: In Event- und Analytics-Payloads kommen sie ständig vor.

Arrays: vier Regeln, eine vernünftige Vorgabe

Hier gehen die Konverter am weitesten auseinander.

Regel Ausgabe für tags: ["admin","ops"] Was es kostet
Indexspalten tags.0 = admin, tags.1 = ops Die Spaltenzahl bestimmt das längste Array der Datei. Eine Zeile mit 400 Tags gibt jeder Zeile 400 Spalten
In eine Zelle zusammenfügen tags = admin,ops Bricht, sobald ein Wert das Verbindungszeichen enthält, und [] und [""] sehen identisch aus
JSON in einer Zelle tags = ["admin","ops"] Hässlich, braucht korrektes Quoting, übersteht den Hin- und Rückweg exakt
In Zeilen aufsprengen Zwei Zeilen, übrige Felder wiederholt Die Zeilenzahl entspricht nicht mehr der Datensatzzahl, also zählen Aggregate über die anderen Spalten doppelt

Indexspalten sind bei fester kleiner Stelligkeit in Ordnung: ein Breiten-/Längenpaar, ein RGB-Tripel. Bei allem Unbegrenzten entscheidet Ihre schlechteste Zeile über die Spaltenzahl, nicht Ihre typische.

Zusammenfügen ist die häufigste Vorgabe und die schlechteste, verlustbehaftet in drei Richtungen gleichzeitig: Der Trenner kann in den Daten vorkommen, leeres Array und Array mit leerer Zeichenkette fallen zusammen, und verschachtelte Objekte werden ohnehin zu Text.

JSON in einer Zelle ist die richtige Vorgabe für Arrays, die Sie nicht aufsprengen, weil es die einzige exakt umkehrbare Regel ist. Die Zelle wird gemäß RFC 4180 in Anführungszeichen gesetzt, innere Anführungszeichen verdoppelt, und jeder Leser, der weiß, dass die Spalte JSON enthält, parst es direkt zurück. In Excel sieht es schlechter aus, und es ist richtig.

Aufsprengen ist richtig, wenn das Array die Sache ist: Positionen einer Bestellung, Ereignisse einer Sitzung. Genau das macht record_path:

import pandas as pd

data = [
    {"id": 1, "name": "Ada",   "orders": [{"sku": "A1", "qty": 2}]},
    {"id": 2, "name": "Grace", "orders": [{"sku": "B7", "qty": 1},
                                          {"sku": "C3", "qty": 5}]},
]

pd.json_normalize(data, record_path="orders", meta=["id", "name"])
#   sku  qty  id   name
# 0  A1    2   1    Ada
# 1  B7    1   2  Grace
# 2  C3    5   2  Grace

record_path benennt das Array, das zu Zeilen wird, und meta benennt die Felder des Elternobjekts, die auf jede Zeile kopiert werden. Beachten Sie, was mit einem Datensatz passiert, dessen orders-Array leer ist: Er erzeugt keine Zeile und verschwindet vollständig. Außerdem bekommen Sie ein Array pro Durchlauf, da zwei Geschwister-Arrays ein Kreuzprodukt erfordern würden; machen Sie also einen Durchlauf je Array und verbinden Sie über die ID.

Heterogene Arrays

Ein Array, dessen Objekte verschiedene Schlüssel haben, ist dasselbe Vereinigungsproblem eine Ebene tiefer. Mit Indexspalten ergibt [{"a":1},{"b":2}] die Spalten items.0.a und items.1.b, zwei Spalten, die nie beide gefüllt sind, wobei die Spaltenmenge nun von der Position des Elements abhängt. Mit Aufsprengen ergibt es zwei Zeilen mit den Spalten a und b, was besser ist, weil die Position aufhört, Teil der Identität zu sein. Arrays, die Skalare und Objekte mischen, haben überhaupt keine rechteckige Form; serialisieren Sie sie als JSON in einer Zelle.

Werte ohne CSV-Entsprechung

CSV hat einen Typ: Text. Alles andere ist Konvention.

null gegen leere Zeichenkette. JSON unterscheidet sie, CSV nicht: ,, und ,"", sind für die meisten Leser derselbe Wert, der Hin- und Rückweg lässt also eines im anderen aufgehen. Wenn das zählt, schreiben Sie einen Platzhalter wie \N (die COPY-Konvention von Postgres), oder akzeptieren Sie, dass Nullwerte als leere Zeichenketten zurückkommen, und sagen Sie es dazu.

Wahrheitswerte. Kleingeschriebenes true und false ist die JSON-Schreibweise und übersteht den Weg. Excel zeigt TRUE/FALSE, und manche Werkzeuge geben 1/0 aus; beides braucht auf dem Rückweg eine ausdrückliche Zuordnung.

Zahlen. Eine JSON-Zeichenkette mit 007 liest Excel als 7, und 1E5 wird zu 100000. CSV-Quoting verhindert das nicht, denn Excel rät den Typ, nachdem es die Anführungszeichen entfernt hat. Große ganze Zahlen stoßen an die Genauigkeitsgrenze, sobald irgendetwas in der Kette sie durch ein Float schickt; geben Sie den Quelltext der Zahl also wörtlich aus.

Datumsangaben. JSON hat keinen Datumstyp; ISO-8601- oder RFC-3339-Zeichenketten sind die Konvention. Excel wandelt eine datumsähnliche Zeichenkette wie 2026-03-04 in einen Datumswert um und zeigt sie im Gebietsschema der Maschine wieder an, und mehrdeutige Formate wie 03/04/2026 können als völlig anderer Tag zurückkommen; lassen Sie also nie eine Tabellenkalkulation eine Zwischenstation sein.

CSV-Mechanik, die zubeißt

RFC 4180 ist kurz und es lohnt sich, ihr zu folgen. Felder mit einem Komma, einem doppelten Anführungszeichen oder einem Zeilenumbruch müssen in Anführungszeichen stehen; ein wörtliches doppeltes Anführungszeichen innerhalb eines solchen Feldes wird verdoppelt; Zeilenenden sind CRLF. Eingebettete Zeilenumbrüche in einem gequoteten Feld sind legal, und reichlich CSV-Leser machen sie noch immer falsch; wenn Ihre Zeichenketten Zeilenumbrüche enthalten, testen Sie also zuerst den Konsumenten.

Der Trenner ist nicht immer ein Komma. Excel erwartet in einem Gebietsschema, in dem das Dezimaltrennzeichen ein Komma ist, semikolongetrennte Dateien, und deshalb öffnet sich eine gültige CSV-Datei auf dem Rechner einer Kollegin als eine einzige Spalte. Bieten Sie eine Trenner-Einstellung an, oder liefern Sie die erste Zeile sep=;, die Excel versteht.

Dann die Byte-Reihenfolge-Markierung: Excel liest eine UTF-8-CSV nur dann als UTF-8, wenn die Datei mit einer BOM beginnt, und ohne sie werden Zeichen mit Diakritika in der Systemcodepage dekodiert und zerlegt. Diese drei Bytes sind für jedes andere Werkzeug Rauschen; machen Sie die BOM also zu einem Schalter und schalten Sie sie für den Excel-Weg ein.

CSV-Injection

Wenn das erste Zeichen einer Zelle =, +, - oder @ ist, behandeln Excel, Google Sheets und LibreOffice die Zelle als Formel und werten sie beim Öffnen aus. Die OWASP nennt das CSV-Injection. Manche Leitfäden ergänzen Tabulator und Wagenrücklauf in der Auslöserliste.

Mit Anführungszeichen kommen Sie da nicht heraus: Der Leser entfernt die RFC-4180-Anführungszeichen, bevor die Formel ausgewertet wird. Wenn also irgendeine Zeichenkette in Ihrem JSON von einem Benutzer stammt und in einer CSV landet, die jemand öffnet, haben Sie einem Angreifer eine Formel überreicht, die in einem vertrauenswürdigen Kontext läuft. Formeln können entfernte URLs abrufen, was heißt: Nachbarzellen können das Haus verlassen.

Die Gegenmaßnahme ist, das führende Zeichen beim Schreiben der Zelle zu entschärfen:

const RISKY = /^[=+\-@\t\r]/;

function safeCell(value) {
  const s = String(value);
  return RISKY.test(s) ? "'" + s : s;
}

Der Apostroph zwingt Excel, den Inhalt als Text zu behandeln. Umsonst ist das nicht: Für einen Leser, der keine Tabellenkalkulation ist, gehört er jetzt zu den Daten, für diese Werte ist der Hin- und Rückweg also kaputt. Das Voranstellen ist richtig für Dateien, die ein Mensch in einer Tabellenkalkulation öffnet, und falsch für Dateien, die eine Maschine zurückliest, was es zu einem Schalter pro Export macht statt zu einer versteckten Vorgabe.

Der Weg zurück

CSV nach JSON hat eine große Falle: Typinferenz. Jeder Wert in der Datei ist Text, der Konverter rät also, welche davon Zahlen sind, und scheitert vorhersehbar. 007 wird zu 7, 1E5 wird zu 100000, 1.0 wird zu 1. Postleitzahlen, Teilenummern, Telefonnummern und Versionsangaben sterben alle an derselben Regel. Die sichere Vorgabe ist, jeden Wert als Zeichenkette auszugeben und den Aufrufer umwandeln zu lassen, was er kennt, wobei die Inferenz je Spalte zugeschaltet wird statt als dateiweite Heuristik. Das Werkzeug CSV zu JSON macht diesen Schalter genau aus diesem Grund explizit.

Eine Vorgabepolitik, die es wert ist, ausgesprochen zu werden

Entscheidung Vorgabe Warum
Spalten Vereinigung aller Blattpfade, sortiert Das Abtasten des ersten Objekts wirft Felder ohne Warnung weg
Verschachtelte Objekte Punktpfad, Trenner konfigurierbar Schlüssel dürfen den Trenner legal enthalten
Arrays JSON in einer Zelle Die einzige umkehrbare Regel. Aufsprengen, wenn das Array der Datensatz ist
Leere Container [] und {} wörtlich Von null und von der leeren Zeichenkette unterscheidbar
Nullwerte Leere Zelle, dokumentiert Oder ein Platzhalter, wo die Unterscheidung Last trägt
Zahlen Quelltext wörtlich Auf dem Weg nach draußen nie durch ein Float schicken
Zeilenenden CRLF RFC 4180, und LF bricht mehr Leser als CRLF
BOM Aus, mit Excel-Schalter Richtig für Pipelines, falsch für Excel, also den Nutzer entscheiden lassen
Formelzeichen Nur auf dem Excel-Weg vorangestellt Voranstellen verändert die Daten, das darf nicht stillschweigend passieren

Das sind nicht die einzigen vertretbaren Antworten. Der Punkt ist, dass jeder Konverter alle neun Entscheidungen trifft, ob er es Ihnen sagt oder nicht, und nur denen, die es sagen, kann man ein Payload anvertrauen, das zu groß ist, um es mit dem Auge zu prüfen. Der Flattener zeigt die Pfadmenge, bevor Sie sich festlegen, und die Tabellenansicht zeigt das Rechteck, das Sie gleich bekommen.