Qué se pierde al convertir entre JSON, YAML, CSV y XML
Toda conversión entre formatos de datos descarta lo que el origen podía expresar y el destino no. Algunas pérdidas son evidentes: los comentarios desaparecen en cuanto YAML se convierte en JSON. La mayoría son silenciosas. Una fecha llega como cadena, un array se convierte en cinco columnas, un identificador que terminaba en 3 ahora termina en 2. La costumbre útil es saber qué detalle se va a perder antes de que se pierda.
Qué puede transportar cada formato
| Comentarios | Tipos | Anidamiento | Fechas | Orden de claves | Claves duplicadas | |
|---|---|---|---|---|---|---|
| JSON | No | string, number, boolean, null, object, array | Sí | Sin tipo nativo | Sin orden según la especificación, conservado por la mayoría de analizadores | Sin definir; suele ganar la última |
| YAML | Sí, # | Los de JSON, más marcas de tiempo y algunos más en 1.1 | Sí | Sí en 1.1, depende de la etiqueta en 1.2 | Se conserva en el archivo, no tras analizarlo | No válidas, pero a menudo se aceptan |
| CSV | No | Ninguno, cada celda es texto | No, solo filas planas | No | Lo fija la fila de cabecera | Válidas y ambiguas |
| XML | Sí, <!-- --> | Ninguno sin esquema; con tipos usando XSD | Sí | Solo a través de un esquema | Los elementos van ordenados, los atributos no | Los elementos repetidos son normales, los atributos duplicados son un error |
| TOML | Sí, # | string, integer, float, boolean, date, time, date-time, array, table | Sí, mediante tablas | Sí, de primera clase | No es significativo | Un error, siempre |
Dos columnas causan la mayoría de las sorpresas. Los tipos deciden si 007 sobrevive o llega como el número 7, y el anidamiento decide si es posible convertir a CSV sin inventarse una convención.
CSV es plano y cada celda es texto
CSV tiene una sola forma: filas de campos. No hay manera de expresar un objeto dentro de una celda, así que un conversor tiene que inventarse algo. Normalmente aplana con rutas separadas por puntos, de modo que esto:
[{ "id": 1, "name": { "first": "Ada" }, "tags": ["admin", "ops"] }]
se convierte en:
id,name.first,tags.0,tags.1
1,Ada,admin,ops
Eso se desaplana limpiamente hasta que pasan dos cosas. Los arrays de longitudes distintas ensanchan la cabecera hasta el registro más largo, así que una fila con tres etiquetas añade una columna tags.2 y deja a todas las demás filas una celda vacía. Y una clave que ya contenía un punto se vuelve después indistinguible de una ruta anidada, así que el viaje de vuelta reconstruye la estructura equivocada. La alternativa es meter una cadena JSON en la celda, "[""admin"",""ops""]" con las comillas dobladas como exige CSV, que no pierde nada y que no entiende nada de lo que venga después.
Los tipos son la otra mitad. Una celda contiene caracteres, así que quien la lee tiene que adivinar. Adivinar convierte 007 en 7, 1.0 y 1 en un mismo valor, un código postal en su versión sin el cero inicial y un código de empresa TRUE en un booleano. No adivinar deja todos los números como cadenas. La inferencia de tipos en CSV a JSON, o en TSV a JSON, es una conjetura con valores por defecto sensatos, no una recuperación, porque los tipos originales nunca llegaron a escribirse.
Una celda en blanco puede significar cadena vacía, nulo, cero o «no aplica»; decide qué significa y dilo, porque el archivo no puede. Cambiar de separador, como hace CSV a TSV, es la única conversión segura aquí: no hay tipos que estropear.
YAML adivina el tipo por ti
YAML infiere los tipos a partir del texto sin comillas, que es lo que lo hace agradable de escribir y arriesgado de convertir.
country: no
version: 1.20
build: 010
start: 12:30
Con un analizador de YAML 1.1, que es lo que siguen implementando PyYAML y muchas bibliotecas antiguas, eso es:
{ "country": false, "version": 1.2, "build": 8, "start": 750 }
Los cuatro cambiaron de significado. no es el problema de Noruega: YAML 1.1 trata y, yes, no, on y off como booleanos, así que el código de país se convierte en false. 1.20 es un número en coma flotante, así que el cero final desaparece. 010 encaja con el patrón octal y se convierte en 8. 12:30 encaja con el patrón sexagesimal y se convierte en 750, un número de minutos.
Un analizador con el esquema básico de YAML 1.2, como el js-yaml actual, lee ese mismo archivo con "no" como cadena, 010 como 10 y "12:30" como cadena. Un archivo, dos analizadores, datos distintos. Las especificaciones discrepan de verdad; 1.2 eliminó a propósito las reglas del sexagesimal y de las palabras booleanas.
La defensa es un solo carácter. Entrecomilla todo lo que deba ser texto: country: "no", version: "1.20". El conversor entre YAML y JSON muestra qué ha entendido un analizador de un archivo, porque JSON no tiene dónde esconder la ambigüedad.
JSON no tiene fechas, no tiene comentarios y tiene un techo de 53 bits
Los números de JSON son dobles IEEE 754, así que los enteros solo se mantienen exactos hasta 2^53, que es 9007199254740992. A partir de ahí:
{ "id": 9007199254740993 }
Analiza y vuelve a serializar eso en la mayoría de lenguajes y vuelve como 9007199254740992. El valor no se puede representar en absoluto, así que más que redondeado está sencillamente fuera de alcance. Por eso Discord, Twitter y otras API de tipo snowflake envían los identificadores como cadenas: un entero de 64 bits no cabe en un número de JSON.
Tampoco hay un tipo fecha, así que las fechas viajan como cadenas, por convención en ISO 8601, y nada marca "2026-08-25" como fecha en lugar de como texto. Al pasar por TOML o por un analizador de YAML 1.1 puede convertirse en una fecha real y luego volver con otro formato. JSON tampoco tiene comentarios ni comas finales, así que las anotaciones de un origen YAML o TOML se pierden, no se trasladan. Generar interfaces de TypeScript a partir de una muestra hereda los dos puntos ciegos: una cadena no es una fecha, y un campo ausente no es un campo opcional.
XML no cabe dentro de JSON, en ninguna de las dos direcciones
XML distingue los atributos de los elementos hijos, y JSON solo tiene claves.
<user id="7" active="true">
<name>Ada</name>
<tag>admin</tag>
<tag>ops</tag>
</user>
Un conversor elige una convención, normalmente prefijando los atributos con @ y agrupando los elementos repetidos en un array. Eso pierde información de una forma concreta: con un solo <tag> no hay array, así que la forma de la salida depende de los datos y no del esquema, y el código que espera una lista se rompe con el registro que tiene una sola etiqueta. El contenido mixto, como <p>Hello <b>there</b> friend</p>, no tiene equivalente en JSON, y los espacios de nombres, las secciones CDATA y los comentarios desaparecen.
El camino inverso pierde otras cosas. Los nombres de elemento no pueden empezar por un dígito ni contener espacios, así que hay que retorcer las claves arbitrarias de JSON. null se convierte por convención en un elemento vacío o en xsi:nil. Un array de nivel superior necesita un elemento envolvente que nunca estuvo en el origen. Y nada en JSON registra si un valor fue en su momento un atributo, así que de JSON a XML solo se emiten elementos. La conversión de CSV a XML plantea esa elección abiertamente y pregunta si quieres elementos o atributos.
Orden de claves y claves duplicadas
El orden de las claves no está garantizado en ninguna parte y se conserva en casi todas. La especificación de JSON dice que los objetos no están ordenados y aun así todos los analizadores mayoritarios mantienen el orden de inserción. Ordenar las claves sigue siendo más seguro para todo lo que se compare o se sume por comprobación, porque una diferencia entre dos documentos cuyas claves solo han cambiado de sitio es ilegible. Comparar de forma estructural, como hace la herramienta de comparación de JSON, empareja por clave y no por posición, y evita la cuestión.
Las claves duplicadas son el filo más peligroso. JSON no dice nada, así que los analizadores difieren y la mayoría se queda en silencio con el último valor. YAML las prohíbe y muchos analizadores las aceptan igualmente. TOML las rechaza sin más. CSV permite dos columnas con la misma cabecera y deja que decida quien lo lea, motivo suficiente para pasar antes un validador de CSV por un archivo desconocido. XML es el único en el que la repetición es significativa en vez de accidental.
Convertir a propósito
Toda cadena de procesamiento tiene un paso con pérdidas. Elige cuál es en lugar de descubrirlo más tarde.
- Llega al formato más estrecho el último. De XML a JSON a CSV pierdes los atributos en el primer paso y el anidamiento en el segundo. Si el destino es CSV, decide qué campos importan y aplana a propósito.
- Entrecomilla antes de convertir, no después. Los números de versión, los códigos de país, los códigos postales y todo lo que lleve un cero inicial van entre comillas en el origen. Una vez que
noesfalse, el texto original es irrecuperable. - Revisa la salida como datos. Formatéala, confirma el número de registros e inspecciona una fila que sepas que es problemática: la coma dentro de un nombre, el array más largo, el identificador más grande.
- Compara una ida y vuelta. Convierte, vuelve a convertir y compara. Lo que señale la comparación es lo que la conversión no puede transportar.
- Conserva el original. El archivo convertido es un derivado, y cuando dentro de tres meses alguien pregunte si un campo estaba vacío o ausente, solo el origen puede responder.