Convertir JSON a CSV
Cómo convertir datos JSON a formato CSV en Python, Java y JavaScript: aplana objetos anidados, desenrolla arrays y genera salida lista para Excel.
Visión General
Convertir JSON a CSV conecta las respuestas estructuradas de las APIs con formatos compatibles con hojas de cálculo. Impulsa exportaciones de datos, pipelines de BI e interoperabilidad con flujos de trabajo basados en Excel. El verdadero trabajo no es el cambio de formato, sino aplanar la estructura anidada de JSON en filas y columnas sin perder datos. Para la operación inversa, consulta Convertir CSV a JSON.
Cuándo Usar
Usa este recurso cuando:
- Exportes datos de respuestas de API a Excel o Google Sheets para perfiles no técnicos
- Alimentes pipelines ETL que cargan en herramientas de BI o data warehouses
- Generes informes desde bases de datos NoSQL que almacenan documentos JSON
- Compartas análisis puntuales con equipos que trabajan en hojas de cálculo
Solución
Python
import json
import csv
# Array JSON plano: cada objeto se convierte en una fila
json_data = '[{"name":"Alice","age":30},{"name":"Bob","age":25}]'
records = json.loads(json_data)
with open('output.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=records[0].keys())
writer.writeheader()
writer.writerows(records)
# Aplanar JSON anidado con pandas
# pip install pandas
import json
import pandas as pd
nested = '[{"user":{"name":"Alice"},"orders":[{"id":1}]}]'
df = pd.json_normalize(json.loads(nested), sep='.')
df.to_csv('output.csv', index=False)
# JSON Lines (un objeto por línea) a CSV
import json
import csv
with open('data.jsonl', encoding='utf-8') as src, open('output.csv', 'w', newline='', encoding='utf-8') as out:
records = (json.loads(line) for line in src if line.strip())
first = next(records)
writer = csv.DictWriter(out, fieldnames=first.keys())
writer.writeheader()
writer.writerow(first)
writer.writerows(records)
# Convertir archivos grandes en streaming sin cargarlos en memoria
# pip install ijson
import csv
import ijson
# 'item' devuelve cada objeto dentro de un array JSON de primer nivel
with open('big.json', 'rb') as src, open('output.csv', 'w', newline='', encoding='utf-8') as out:
writer = None
for record in ijson.items(src, 'item'):
if writer is None:
writer = csv.DictWriter(out, fieldnames=record.keys())
writer.writeheader()
writer.writerow(record)
La versión en streaming asume claves consistentes entre registros. Para estructuras irregulares, recoge la unión de claves en una primera pasada y pásala como fieldnames.
JavaScript
// Conversión manual para arrays planos
const records = [{ name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }];
const headers = Object.keys(records[0]);
const rows = records.map(r => headers.map(h => JSON.stringify(r[h])).join(','));
const csv = [headers.join(','), ...rows].join('\n');
console.log(csv);
// Usando @json2csv para una conversión fiable
// npm install @json2csv/plainjs
import { Parser } from '@json2csv/plainjs';
const parser = new Parser();
const csv = parser.parse(records);
console.log(csv);
Java
// Jackson + commons-csv
// Maven: com.fasterxml.jackson.core:jackson-databind, org.apache.commons:commons-csv
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
public class JsonToCsv {
public static void main(String[] args) throws Exception {
String json = "[{\"name\":\"Alice\",\"age\":30},{\"name\":\"Bob\",\"age\":25}]";
ObjectMapper mapper = new ObjectMapper();
List<Map<String, Object>> records = mapper.readValue(json, List.class);
StringWriter sw = new StringWriter();
try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.withHeader("name", "age"))) {
for (Map<String, Object> record : records) {
printer.printRecord(record.get("name"), record.get("age"));
}
}
System.out.println(sw.toString());
}
}
Explicación
El desafío principal es aplanar datos jerárquicos en una tabla bidimensional. Los arrays JSON planos se mapean directamente a filas. Los objetos anidados necesitan una estrategia: aplanar claves en columnas con notación de punto (user.name), desenrollar (unwind) arrays en filas repetidas, o dividir entidades relacionadas en varios CSV vinculados por una columna ID — el mismo trade-off que la normalización en bases de datos.
Dos detalles importan en la práctica:
- Derivación de cabeceras:
records[0].keys()solo captura los campos del primer registro. Si registros posteriores traen claves extra o faltantes, las columnas se pierden o desalinean. Calcula la unión de claves de todos los registros antes de escribir. - Codificación: escribe UTF-8 explícito y antepone un BOM (
\ufeff) cuando el archivo vaya a Excel, o los caracteres no-ASCII se verán corruptos.
Para registros irregulares, la versión defensiva recoge primero la unión de claves y rellena los huecos con un valor por defecto:
fieldnames = sorted({key for r in records for key in r})
writer = csv.DictWriter(f, fieldnames=fieldnames, restval='', extrasaction='ignore')
writer.writeheader()
writer.writerows(records)
El restval='' deja los campos ausentes como celdas vacías en lugar de lanzar error, y extrasaction='ignore' protege ante claves que no se hayan capturado en la pasada de unión.
pandas.json_normalize aplana automáticamente, con las opciones record_path y meta para arrays. @json2csv soporta campos personalizados, transforms y unwind para arrays. Java no incluye un conversor JSON→CSV, así que iteras manualmente con Jackson más una librería CSV como commons-csv o univocity-parsers.
Ten en cuenta que CSV es un formato de texto: números, booleanos, nulos y fechas se convierten en cadenas, y quien lea el archivo tendrá que inferir los tipos de nuevo. Si importa la fidelidad de ida y vuelta, serializa los valores con una convención explícita (fechas ISO 8601, null como celda vacía) y documéntala para los consumidores.
Variantes
| Tecnología | Librería | Enfoque | Notas |
|---|---|---|---|
| Python | csv (stdlib) | DictWriter | Cero dependencias, requiere JSON plano |
| Python | pandas | json_normalize() | Maneja anidación; dependencia pesada |
| Python | ijson + csv | Parseo en streaming | Memoria constante para archivos grandes |
| JavaScript | @json2csv | Parser | Campos custom, transforms, unwind |
| JavaScript | Manual | Object.keys() + join() | Cero dependencias, frágil con datos complejos |
| Java | Jackson + commons-csv | Iteración manual | Robusto, con boilerplate verboso |
| Java | univocity-parsers | CsvWriter | Alternativa de alto rendimiento |
Lo que Funciona
- Deriva las cabeceras de la unión de claves de todos los registros, no solo del primero — las claves ausentes producen columnas desalineadas o truncadas.
- Sanitiza las cabeceras: elimina espacios y caracteres especiales que rompen parsers posteriores.
- Escapa comas y comillas en los valores de texto para producir CSV conforme a RFC 4180; las librerías dedicadas lo hacen automáticamente.
- Decide la estrategia para arrays desde el inicio: desenróllalos en filas repetidas o guárdalos como strings JSON dentro de las celdas.
- Procesa datasets grandes en streaming: para archivos mayores que la memoria disponible, usa
ijsonen Python o un transform stream en Node — consulta Leer archivos grandes en streaming en Node.js. - Conserva los valores en crudo: no conviertas números o booleanos a texto antes de escribir, o Excel pierde la capacidad de ordenarlos y calcularlos.
Errores Comunes
- Asumir que todos los registros tienen claves idénticas: los campos faltantes desalinean columnas; calcula primero la unión de claves.
- No manejar objetos anidados: produce
[object Object]en JS oLinkedHashMapen Java dentro de las celdas, en lugar de valores reales. - Olvidar entrecomillar valores con comas: rompe parsers que separan por comas — RFC 4180 exige entrecomillado.
- Ignorar la inyección de fórmulas CSV: las celdas que empiezan por
=,+,-o@se ejecutan como fórmulas al abrirlas en Excel. Préfixalas con'o sanitízalas al exportar, sobre todo con datos generados por usuarios (ver OWASP CSV Injection). - Cargar archivos de varios GB en memoria: un array JSON grande convertido en memoria tumba el proceso; usa streaming.
- Confiar en el delimitador por defecto de Excel: muchas configuraciones regionales esperan punto y coma — define el delimitador explícitamente para usuarios internacionales.
Cuándo No Usar Este Enfoque
- JSON irregular o profundamente recursivo: los documentos con estructuras muy distintas pierden información en una tabla plana — conserva JSON Lines o convierte a Parquet.
- Intercambio máquina a máquina: CSV pierde tipos y anidación; usa JSON, Parquet o Arrow para datos entre servicios.
- Datos que ya están en una base de datos: exporta CSV directamente con SQL (
COPY,SELECT INTO OUTFILE) en lugar de pasar por JSON. - Documentos con varias entidades: cuando un JSON contiene varias entidades relacionadas, varios CSV vinculados o un formato relacional funcionan mejor que una tabla gigante aplanada.
Ver También
- Aplanar y Desanidar Objetos —
cómo convertir nombres de columna con puntos como
user.namede vuelta a JSON anidado. - Validar JSON Schema — mantén los datos de origen bajo un contrato antes de convertirlos.
- Código complementario en GitHub — el repositorio companion de esta receta.
Preguntas frecuentes
¿Cómo convierto JSON profundamente anidado a CSV?
Usa pandas.json_normalize con sep='_' o la opción unwind de @json2csv para arrays. Para objetos muy anidados, considera si CSV es el formato adecuado — Parquet o JSON Lines pueden ser mejores alternativas. Si necesitas CSV sí o sí, aplana las claves en columnas con notación de punto.
¿Puedo convertir JSON a CSV en el navegador?
Sí. Carga @json2csv vía CDN o inclúyelo en el bundle de tu aplicación frontend. Para archivos muy grandes, usa Web Workers para no bloquear el hilo principal y envía chunks a la descarga con la Streams API o Blob/URL.createObjectURL.
¿Cómo manejo arrays dentro de objetos JSON al convertir a CSV?
Opción 1: Desenrolla el array para que cada elemento sea una fila separada (duplicando los campos del padre). Opción 2: Serializa el array como string JSON dentro de la celda CSV. Opción 3: Crea un CSV relacionado aparte y usa una columna ID para vincularlos, como en la normalización de bases de datos.
¿CSV preserva los tipos de datos de JSON?
No — cada celda es texto. Los números siguen siendo ordenables porque Excel los vuelve a inferir, pero los booleanos quedan como cadenas true/false, null se convierte en celda vacía o en el literal "null" según la librería, y las estructuras anidadas requieren aplanado o serialización. Si necesitas preservar tipos, usa Parquet o conserva los datos como JSON.
¿Por qué mi CSV se ve roto en Excel?
Dos causas frecuentes: codificación y delimitador. Excel necesita un BOM UTF-8 (\ufeff) para detectar Unicode correctamente, y en muchas configuraciones regionales espera ; en lugar de , como separador. Escribe el BOM y define el delimitador que espera tu audiencia, o comparte un .xlsx en su lugar.
Recursos Relacionados
Convertir CSV a JSON
Convertí archivos CSV a JSON estructurado con Python, JavaScript y Java. Elegí la librería adecuada para conversiones puntuales o pipelines grandes.
RecipeParsear JSON en Python, JavaScript y Java
Parsea cadenas JSON a objetos nativos en Python, JavaScript y Java — con manejo de errores, streaming para archivos grandes y validación de esquema.
RecipeAnalizar Archivos CSV
Cómo analizar archivos CSV en Python, Java y JavaScript con ejemplos de código prácticos.
RecipeValidar JSON Schema
Cómo validar datos JSON contra schemas en Python, Java y JavaScript.
RecipeLeer Archivos CSV con Python y Pandas
Cómo leer, filtrar y transformar archivos CSV grandes de forma eficiente con pandas y el módulo csv de Python.
RecipeLeer y Escribir Excel en Python (openpyxl + pandas)
Cómo leer, escribir y formatear hojas de cálculo Excel en Python con pandas y openpyxl, con ejemplos listos para copiar.