Aller au contenu
jsonbeautifiers
Français

Aplatir du JSON

Transforme du JSON imbriqué en chemins de clés à un seul niveau, et inversement.

Imbriqué
Aplati

Rien de ce que vous collez ne quitte votre navigateur. La liste d’autorisation connect-src en fait une garantie du navigateur plutôt qu’une promesse. Vérifiez-le vous-même

Aplatir transforme un document imbriqué en un seul niveau de chemins pointés : {"a":{"b":1}} devient {"a.b":1}. Désaplatir fait l’inverse.

C’est ce que l’on fait avant de charger du JSON dans quoi que ce soit de rectangulaire : un tableur, un data frame, un magasin de feature flags, un fichier d’environnement, un formulaire.

L’aller-retour, et le seul cas qui le casse

Aplatir puis désaplatir redonne le document d’origine, objets et tableaux vides compris, que plusieurs implémentations font discrètement disparaître.

Il y a exactement un cas où c’est impossible : une clé qui contient elle-même le séparateur. Avec {"a.b": 1}, le chemin aplati "a.b" est indiscernable d’un {"a":{"b":1}} imbriqué. Cet outil le détecte et vous avertit plutôt que de produire quelque chose qui ne reviendra pas. Choisissez alors un autre séparateur.

Tableaux : notation par index ou par crochets

La notation pointée donne tags.0 et tags.1. La notation à crochets donne tags[0] et tags[1]. Les deux font l’aller-retour ici, et l’analyseur d’entrée accepte l’une comme l’autre.

La notation pointée est celle que produit json_normalize de pandas et celle qu’attendent la plupart des chaînes CSV. La notation à crochets se lit mieux quand une clé pourrait plausiblement être numérique, parce que tags[0] et tags.0 sont ambigus là où tags["0"] ne l’est pas.

Là où aplatir perd de l’information

Une clé d’objet numérique devient indiscernable d’un index de tableau une fois aplatie. {"2024": {"total": 1}} s’aplatit en "2024.total", et le désaplatir avec la détection de tableaux activée produit un tableau comportant 2024 cases vides.

Désactivez « clés numériques comme tableaux » quand vos clés sont réellement des chaînes numériques, ce qui est courant pour tout ce qui est indexé par année, par code de statut HTTP ou par identifiant.

How to do this in code

Aplatir en code.

py Python, pandas

record_path est l’argument qui transforme une relation un-à-plusieurs en lignes plutôt qu’en colonnes numérotées.

import pandas as pd

# The workhorse. sep defaults to '.'
df = pd.json_normalize(records)

# Explode a nested array into one row per element
df = pd.json_normalize(
    records,
    record_path='items',
    meta=['id', 'created_at'],
)
sh jq
# Every leaf as a dotted path
jq -r 'paths(scalars) as $p | "\($p | join(".")) = \(getpath($p))"' in.json

# A flat object rather than lines
jq '[leaf_paths as $p | {(($p | map(tostring) | join("."))): getpath($p)}] | add' in.json
js JavaScript

La branche des conteneurs vides est la ligne que la plupart des implémentations omettent, et c’est pour cela qu’elles ne font pas l’aller-retour.

function flatten(value, prefix = '', out = {}) {
  if (value && typeof value === 'object') {
    const entries = Array.isArray(value)
      ? value.map((v, i) => [i, v])
      : Object.entries(value);
    if (entries.length === 0) {
      out[prefix] = value;      // preserve {} and []
      return out;
    }
    for (const [k, v] of entries) {
      flatten(v, prefix ? `${prefix}.${k}` : String(k), out);
    }
    return out;
  }
  out[prefix] = value;
  return out;
}

Questions fréquentes

Quel séparateur choisir ?
Un point, sauf si vos clés contiennent des points. Le tiret bas est le second choix habituel, et la barre oblique est utile quand le résultat part vers quelque chose qui raisonne déjà en chemins.
Puis-je n’aplatir qu’une partie du document ?
Fixez une limite de profondeur. Tout ce qui se trouve au-delà reste une valeur imbriquée, ce que vous voulez quand la partie profonde est un bloc opaque que vous stockez plutôt que vous interrogez.
Que devient null ?
Il est conservé par défaut, sous forme de clé plate avec une valeur null. Une option permet de l’omettre : utile pour un diff, dangereuse pour un aller-retour.