mygems

Convertir du JSON en CSV sans perdre de données

Le JSON est un arbre, le CSV un rectangle : chaque convertisseur fait des choix. Lesquels, comment aplatir un JSON imbriqué, et les outils qui s'en sortent bien.

Par mygems ·

Le JSON est un arbre. Le CSV est un rectangle. Passer de l'un à l'autre, c'est décider comment aplatir l'arbre, et chaque convertisseur prend ces décisions à votre place, généralement sans dire lesquelles. C'est pourquoi un même fichier passé dans trois convertisseurs en ligne peut donner trois tableaux différents.

Si vous connaissez les trois décisions, vous pouvez choisir l'outil, ou les réglages, qui les prennent comme vous le voulez.

La réponse rapide

  • Un tableau plat d'objets ([{"id":1,"name":"Ada"}, …]) : n'importe quel convertisseur fait l'affaire. Utilisez jq, Python, DuckDB, Excel ou une application.
  • Des objets imbriqués ("address": {"city": "Leeds"}) : aplatissez-les en colonnes à points, address.city. json_normalize de Python le fait en une ligne.
  • Des tableaux dans chaque enregistrement ("tags": ["a","b"]) : choisissez entre une colonne par élément, une ligne par élément, ou une seule cellule avec la liste jointe. Il n'y a pas de bonne réponse, seulement celle qui convient à ce que vous allez en faire.
  • Les enregistrements ne sont pas à la racine : trouvez d'abord le tableau (souvent data, items ou results), puis convertissez-le.

Décision 1 : quel tableau devient les lignes ?

Un CSV demande une liste d'éléments semblables, un par ligne. Presque aucun JSON réel ne commence par une telle liste. Une réponse d'API ressemble à ceci :

{
  "status": "ok",
  "page": 1,
  "data": {
    "items": [
      { "id": 1, "name": "Ada", "address": { "city": "Leeds" }, "tags": ["admin"] },
      { "id": 2, "name": "Lin", "address": { "city": "Hue" }, "tags": [] }
    ]
  }
}

Les lignes sont dans data.items. Un convertisseur pointé sur la racine voit un seul objet et vous donne une seule ligne avec status, page et une colonne pleine de JSON échappé. C'est la plainte « le convertisseur est cassé » la plus courante, et c'est un problème de chemin, pas de convertisseur.

Décision 2 : que deviennent les objets imbriqués ?

address est un objet à l'intérieur de chaque enregistrement. La solution habituelle, et la bonne dans la plupart des cas, est de l'aplatir en noms de colonnes à points :

idnameaddress.city
1AdaLeeds
2LinHue

L'alternative, mettre tout l'objet dans une cellule sous forme de chaîne JSON, conserve tout, mais vous obtenez une colonne impossible à trier ou à filtrer.

Décision 3 : que deviennent les tableaux dans un enregistrement ?

tags est une liste, et une liste ne tient pas dans une cellule. Trois options :

ApprocheRésultatUtile pour
Colonnes indexéestags[0], tags[1], …Listes courtes au maximum connu
Éclater en lignesUne ligne par tag, autres colonnes répétéesCompter ou filtrer par tag
Joindre en une celluleadmin;editorLire, pas analyser

Éclater change le nombre de lignes : une personne avec trois tags devient trois lignes. C'est correct pour « combien de personnes ont chaque tag » et faux pour « combien y a-t-il de personnes ». Décidez à quelle question le CSV doit répondre avant de choisir.

Les autres pertes

Même un aplatissement parfait perd des choses, parce que le CSV ne sait pas les exprimer :

  • Les types. "42" et 42 deviennent tous deux 42. true devient le texte true.
  • Null ou vide. null, "" et une clé absente deviennent tous une cellule vide.
  • Les colonnes des enregistrements incomplets. Si un seul enregistrement sur 10 000 a un champ coupon, un convertisseur qui construit l'en-tête à partir des clés du premier enregistrement l'ignorera. Les bons convertisseurs prennent l'union des clés de tous les enregistrements.

Avec jq

Pour un tableau plat à la racine :

jq -r '(.[0] | keys_unsorted) as $k | $k, (.[] | [.[$k[]]]) | @csv' in.json > out.csv

Cela construit l'en-tête à partir du premier enregistrement, donc toute clé absente du premier est perdue : c'est le problème des enregistrements incomplets vu plus haut. Pour un tableau situé plus bas, remplacez le premier . par le chemin, par exemple .data.items. Pour des données imbriquées, jq peut le faire, mais l'expression devient illisible ; passez à Python.

Avec Python

pandas.json_normalize prend les trois décisions en un seul appel, et prend l'union des clés :

import json, pandas as pd

data = json.load(open("in.json"))
df = pd.json_normalize(data["data"]["items"], sep=".")
df.to_csv("out.csv", index=False)

Les objets imbriqués deviennent address.city. Les listes restent des listes dans une cellule ; pour les éclater en lignes, ajoutez df = df.explode("tags") avant d'enregistrer.

Avec DuckDB

Pour les gros fichiers, DuckDB lit le JSON directement et écrit le CSV sans tout charger en mémoire :

duckdb -c "COPY (SELECT * FROM read_json_auto('in.json')) TO 'out.csv'"

Pour un tableau plat, c'est la voie la plus rapide. Les objets imbriqués sortent dans la notation struct propre à DuckDB, dans une seule colonne : dépliez-les dans le SELECT ou utilisez Python pour les données imbriquées.

Avec Excel

Données → Obtenir des données → À partir d'un fichier → À partir d'un JSON ouvre Power Query. Cliquez sur Vers la table, puis sur l'icône d'expansion dans l'en-tête de colonne (deux flèches) pour développer les enregistrements et les listes niveau par niveau. Tout se fait à la souris, et vous voyez chaque décision au moment où vous la prenez. Enregistrez ensuite en CSV. Attention aux conversions de types à la sortie : Excel modifie les données CSV sauf si vous lui dites de ne pas le faire.

Convertisseurs en ligne

Ils fonctionnent, et pour des données publiques ils conviennent. Deux précautions. La plupart cachent les trois décisions, donc comparez le nombre de lignes et de colonnes du résultat avec ce que vous attendiez. Et le JSON d'une API contient souvent des jetons, des e-mails ou des fiches clients : préférez un convertisseur qui tourne dans le navigateur sans rien envoyer.

Sur iPhone et iPad

Smart Json convertit le JSON en CSV dans ce qu'il appelle le mode enregistrements : un tableau d'objets devient les lignes, les valeurs imbriquées sont aplaties en colonnes à points (address.city, tags[0]), et l'en-tête est l'union des clés de tous les enregistrements. L'application trouve elle-même le premier tableau d'objets et vous laisse en choisir un autre, ou saisir un JSONPath comme $.data.items. Le séparateur est réglable, et un document sans tableau d'objets le dit clairement au lieu de produire un export inutile à deux colonnes.

La feuille Convertir avec les onglets YAML, CSV, TOML et XML, une note sur ce que le format ne peut pas conserver, et un aperçu du document converti
Chaque format indique ce qu'il ne peut pas conserver avant l'export

L'aperçu est gratuit, vous voyez donc exactement à quoi ressemblera le CSV. Copier ou enregistrer le résultat est réservé à Pro.

JSON Editor: Smart JsoniPhone et iPad

Affiche un aperçu du JSON en CSV avec les valeurs imbriquées aplaties en colonnes à points, vous laisse choisir le tableau d'enregistrements par JSONPath, et dit clairement ce que le CSV ne peut pas conserver.

Ce que ça fait

Une fois que vous avez un CSV, l'ouvrir sur le téléphone est un petit problème à part ; ce guide en parle.

Vérifier le résultat

Quel que soit l'outil, trois vérifications :

  1. Le nombre de lignes. Correspond-il au nombre d'enregistrements du tableau (ou davantage, si vous avez éclaté une liste exprès) ?
  2. Le nombre de colonnes. Un champ présent seulement dans certains enregistrements a-t-il bien atteint l'en-tête ?
  3. Une valeur imbriquée. Prenez un enregistrement avec un objet imbriqué et vérifiez que sa valeur est dans la bonne colonne à points.

Questions

Comment convertir du JSON imbriqué en CSV ?
Aplatissez les objets imbriqués en noms de colonnes à points, comme address.city. En Python, pandas.json_normalize le fait en un appel ; Power Query d'Excel le fait avec le bouton d'expansion ; certaines applications JSON le font automatiquement. Les tableaux dans les enregistrements demandent une décision à part : colonnes indexées, une ligne par élément, ou une cellule jointe.
Pourquoi mon convertisseur JSON vers CSV ne donne-t-il qu'une ligne ?
Les enregistrements ne sont pas à la racine du document. Les réponses d'API les enveloppent généralement, par exemple dans data.items. Pointez le convertisseur sur ce tableau, par son chemin, plutôt que sur l'objet racine.
Excel peut-il ouvrir un fichier JSON ?
Oui, via Données → Obtenir des données → À partir d'un fichier → À partir d'un JSON, ce qui ouvre Power Query. Convertissez le résultat en table et utilisez les boutons d'expansion pour aplatir les enregistrements imbriqués, puis enregistrez en CSV.
Que perd-on en convertissant du JSON en CSV ?
Les types (nombres, booléens et chaînes deviennent tous du texte), la différence entre null, vide et absent, et l'imbrication elle-même. Les champs présents dans seulement certains enregistrements peuvent aussi disparaître si le convertisseur construit l'en-tête à partir du premier enregistrement.
Comment convertir du JSON en CSV en ligne de commande ?
Pour un tableau plat, jq avec @csv ou le COPY … TO 'out.csv' de DuckDB fonctionnent tous deux en une ligne. Pour du JSON imbriqué, un court script Python avec pandas.json_normalize est plus fiable et plus lisible.

mygems — Développe Smart Json, dont l'export CSV aplatit le JSON imbriqué, et Smart CSV Viewer, qui lit le résultat.