JSON1

Dados tabulares

JSON aninhado para CSV

CSV tem exatamente duas dimensões: linhas e colunas. JSON aninha em qualquer profundidade. Toda conversão entre os dois precisa responder a mesma pergunta — o que vira coluna — e é nessa resposta que os dados se perdem.

Objetos aninhados viram colunas com pontos

A conversão desce até cada valor folha e nomeia a coluna pelo caminho que percorreu. Um city dentro de addr dentro de user vira uma coluna chamada user.addr.city. Não há limite de profundidade, então a quantidade de colunas cresce com a forma dos seus dados, não com o número de chaves do nível superior.

Essa parte se comporta bem e em princípio é reversível: os pontos registram a estrutura de onde você partiu.

JSON de entrada

[
  { "id": 1, "user": { "name": "Ada", "addr": { "city": "London" } } },
  { "id": 2, "user": { "name": "Alan", "addr": { "city": "Wilmslow" } } }
]

CSV de saída

id,user.name,user.addr.city
1,Ada,London
2,Alan,Wilmslow
Saída real de /json-to-csv/. Três valores folha, três colunas, qualquer que seja a profundidade do aninhamento.

Arrays são a parte difícil

Um array não tem nomes para seus membros, apenas posições, então não há nome de coluna honesto a derivar. O conversor trata os dois casos de forma diferente, e vale conhecer essa divisão antes de confiar na saída.

Um array de valores simples colapsa em uma célula só, unido com ponto e vírgula mais espaço:

JSON de entrada

[
  { "id": 1, "tags": ["a", "b"] },
  { "id": 2, "tags": ["c"] }
]

CSV de saída

id,tags
1,a; b
2,c
Conveniente de ler, mas ambíguo: uma tag que já contém ; agora é indistinguível de duas tags.

Arrays de objetos geram colunas indexadas

Quando o array contém objetos, cada posição recebe seu próprio conjunto de colunas, numeradas pelo índice. É fiel — nada é mesclado — mas a quantidade de colunas é definida pela linha mais longa de todo o conjunto de dados.

Olhe a linha 2: ela tem um item, então quatro das células ficam vazias. Com um pedido de 50 itens num arquivo de 10.000 pedidos, cada outra linha carrega 49 grupos de colunas em branco.

JSON de entrada

[
  { "id": 1, "items": [{ "sku": "x", "qty": 2 }, { "sku": "y", "qty": 1 }] },
  { "id": 2, "items": [{ "sku": "z", "qty": 5 }] }
]

CSV de saída

id,items[0].sku,items[0].qty,items[1].sku,items[1].qty
1,x,2,y,1
2,z,5,,
Se seus arrays variam de tamanho, converta o próprio array: uma linha por item, com o id do pedido repetido.

Chaves ausentes se alinham, não deslocam

Em dados reais raramente todos os registros carregam as mesmas chaves. O cabeçalho é a união de todas as chaves vistas, na ordem de primeira aparição, e o registro que não tiver uma recebe uma célula vazia em vez de uma linha deslocada.

Esse é o comportamento que você quer, e vale verificar em qualquer conversor: a implementação ingênua pega as chaves do primeiro registro como cabeçalho e descarta silenciosamente todo campo que aparece só depois.

JSON de entrada

[
  { "id": 1, "name": "Ada" },
  { "id": 2, "email": "a@b.c" }
]

CSV de saída

id,name,email
1,Ada,
2,,a@b.c
email aparece só no segundo registro e ainda assim ganha coluna. Nada é descartado.

Respostas embrulhadas, e quando o desembrulho para

Respostas de API normalmente colocam as linhas dentro de um envelope. Quando exatamente uma propriedade do objeto de nível superior é um array, esse array é tratado como as linhas — então você pode colar uma resposta sem remodelá-la antes.

Um array: desembrulha

{ "items": [{ "a": 1 }, { "a": 2 }] }

CSV de saída

a
1
2

Com dois arrays, sem adivinhação

Com dois arrays não há como dizer qual contém as linhas, então o conversor para de adivinhar e achata o objeto inteiro como um único registro. O resultado é uma linha bem larga, que quase certamente não é o que você queria — e é esse o ponto: está visivelmente errado em vez de silenciosamente meio certo.

Se você vê uma única linha de colunas indexadas, escolha o array que queria e converta ele.

Dois arrays: não desembrulha

{ "items": [{ "a": 1 }], "other": [{ "b": 2 }] }

CSV de saída

items[0].a,other[0].b
1,2
Uma linha, colunas indexadas dos dois arrays. Cole só items para obter a tabela que você queria.

Aspas e o problema das fórmulas de planilha

Uma célula recebe aspas quando contém o delimitador, uma aspa ou uma quebra de linha — as regras padrão de CSV, com as aspas internas duplicadas.

Uma adição que vale conhecer: uma célula começando com =, +, - ou @ também recebe aspas. Esses caracteres fazem o Excel e o Google Sheets tratarem a célula como fórmula, que é como uma exportação CSV vira execução de código na máquina de outra pessoa. Colocar aspas é a metade barata da solução.

JSON de entrada

[{ "formula": "=1+1", "note": "a,b", "q": "say \"hi\"" }]

CSV de saída

formula,note,q
"=1+1","a,b","say ""hi"""
=1+1 recebe aspas por causa do = inicial, a,b por causa da vírgula, e as aspas internas ficam duplicadas.

O que você não recupera

Converter de volta produz chaves planas, não o aninhamento de onde você partiu. Os pontos sobrevivem como caracteres literais no nome da chave — nada os remonta em objetos, porque um leitor CSV comum não tem como saber se user.name era um campo aninhado ou uma coluna que realmente tinha um ponto no nome.

  • Os tipos são readivinhados na volta. 01234 numa célula CSV é parseado como o número 1234, do mesmo jeito que em YAML sem aspas. CEPs e identificadores de conta são as vítimas usuais.
  • `null` e string vazia viram a mesma coisa. Ambos são uma célula vazia, e uma célula vazia é relida como string vazia.
  • Arrays não voltam. Uma célula a; b é uma string com um ponto e vírgula, não uma lista.

CSV de entrada

id,user.name
1,Ada

JSON de saída

[
  {
    "id": 1,
    "user.name": "Ada"
  }
]
Uma chave plana chamada user.name, não um objeto user. Saída real de /csv-to-json/.

Conselho prático

Trate CSV como formato de exportação, não de armazenamento. É a resposta certa quando o destino é uma planilha, uma ferramenta de BI ou uma pessoa; é a resposta errada quando você planeja reler os dados como JSON depois.

  • Converta o array de onde você realmente quer as linhas, não o envelope em volta dele.
  • Se os arrays dentro dos seus registros variam de tamanho, inverta a forma: uma linha por item, com os campos do pai repetidos.
  • Confira a linha de cabeçalho antes de confiar num arquivo — ela diz exatamente quais folhas o achatamento encontrou.
  • Guarde o JSON original. É a única cópia que ainda conhece os tipos e a estrutura.