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. Utilisezjq, Python, DuckDB, Excel ou une application. - Des objets imbriqués (
"address": {"city": "Leeds"}) : aplatissez-les en colonnes à points,address.city.json_normalizede 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,itemsouresults), 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 :
| id | name | address.city |
|---|---|---|
| 1 | Ada | Leeds |
| 2 | Lin | Hue |
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 :
| Approche | Résultat | Utile pour |
|---|---|---|
| Colonnes indexées | tags[0], tags[1], … | Listes courtes au maximum connu |
| Éclater en lignes | Une ligne par tag, autres colonnes répétées | Compter ou filtrer par tag |
| Joindre en une cellule | admin;editor | Lire, 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"et42deviennent tous deux42.truedevient le textetrue. - 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.

L'aperçu est gratuit, vous voyez donc exactement à quoi ressemblera le CSV. Copier ou enregistrer le résultat est réservé à Pro.
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 faitUne 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 :
- Le nombre de lignes. Correspond-il au nombre d'enregistrements du tableau (ou davantage, si vous avez éclaté une liste exprès) ?
- Le nombre de colonnes. Un champ présent seulement dans certains enregistrements a-t-il bien atteint l'en-tête ?
- Une valeur imbriquée. Prenez un enregistrement avec un objet imbriqué et vérifiez que sa valeur est dans la bonne colonne à points.