De YAML a JSON (y vuelta)

Pega una configuración y elige el sentido. Los errores llegan con la línea correcta, y la página te dice qué valores un lector YAML 1.1 leería de otra forma: «no» que se convierte en false, «22:22» que se convierte en 1342.

El texto y los archivos se quedan en tu navegador: la conversión ocurre en tu dispositivo y no se envía nada a nadie.

Por qué «no» se convierte en false: el problema de Noruega

YAML existe en dos versiones que se usan las dos. La 1.1 es de 2005 y es la de PyYAML, o sea de Python y de Ansible; la 1.2 es de 2009 y es la de los lectores más recientes, incluido el de esta página. El texto del archivo es el mismo, pero algunas palabras escritas sin comillas para las dos versiones son cosas distintas.

El ejemplo que dio nombre al problema es el código de Noruega: en una lista de países NO para un lector 1.1 es el booleano falso, y Noruega desaparece. No es el único caso. yes, on y off también son booleanos, y de hecho la clave on: de los workflows de GitHub Actions, leída con PyYAML, se convierte en true. 0755 es un número octal y vale 493. 22:22, el mapeo de un puerto en un docker-compose, es un número en base 60 y vale 1342. En YAML 1.2 son todos texto, salvo 0755, que se convierte en el número 755.

Por eso la página no se limita a convertir: para cada valor escrito sin comillas pregunta a los dos lectores qué ven, y si no están de acuerdo te lo dice, con la línea, el valor de aquí y el de la otra versión. Con el menú Leer el YAML como eliges qué lector imitar. La lectura 1.1 es la de PyYAML, carácter por carácter; la especificación 1.1 incluye también y y n entre los booleanos, pero PyYAML no lo hace y aquí se sigue a PyYAML, porque es el lector 1.1 que la gente usa de verdad. La cura, en todos los casos, es la misma: las comillas.

Los errores, en la línea correcta

Es el motivo por el que casi todos abren un conversor: el programa dice que el archivo no va, y no dice dónde. Aquí cada error tiene un nombre, la línea y un extracto con la línea resaltada, y el botón Ir a la línea la selecciona en el recuadro.

Los casos más comunes tienen una explicación propia. Un tabulador en la sangría, que YAML no acepta y que a simple vista no se distingue de los espacios (en el extracto se ve como una flecha); y, en la lectura 1.1, también uno después de los dos puntos o al final de la línea, que YAML 1.2 deja pasar y PyYAML no. Una sangría que no está alineada con las líneas del mismo nivel. Un valor con dos puntos seguidos de un espacio, como título: Roma: una guía, que YAML toma por una clave nueva. Un apóstrofo dentro de las comillas simples, como en 'Don't panic', que cierra el texto a la mitad. Un valor sin comillas que empieza por una arroba, como @types/node, o por una variable de Ansible, como {{ app_version }}. El espacio que falta después de los dos puntos. Una clave repetida, que PyYAML aceptaría sin decir nada quedándose con la última.

El caso más traicionero es la comilla que se queda abierta: el lector se da cuenta solo líneas más tarde, y señala la línea equivocada. Aquí se busca la línea donde la comilla o el paréntesis se abre sin cerrarse, y se resalta esa. Debajo queda el mensaje original del lector, para quien lo quiera.

Lo que JSON no sabe decir, dicho

Las fechas se quedan como texto, exactamente como están escritas, porque JSON no tiene un tipo para las fechas; la página enumera las líneas, porque PyYAML en cambio las convertiría. Los números enteros por encima de 2^53, como un código de pedido de veinte cifras, se escriben en el JSON cifra por cifra, pero la página avisa de que un programa JavaScript que los vuelve a leer los redondea: 12345678901234567890 se convertiría en 12345678901234567000. Los valores infinito y «no es un número» se convierten en null, y se enumeran. Los números que cambian de forma se señalan aparte: 3.10 se convierte en 3.1, que es el mismo número pero no la misma versión de Python.

Las etiquetas como !Ref y !Sub de CloudFormation o !reference de GitLab no existen en JSON: el valor se queda, la etiqueta no, y la página enumera cuáles y dónde. Varios documentos separados por --- se convierten en una lista. Las anclas y los alias se expanden, y aquí hay un límite declarado: si la expansión añade más de 100.000 valores, la conversión se para. Es la defensa contra el ataque llamado «billion laughs», diez líneas que expandidas se convierten en mil millones de valores y bloquean cualquier programa que las lea hasta el final.

De JSON a YAML: las comillas que hacen falta de verdad

En el sentido contrario el riesgo es al revés. Un texto como "no", "010" o "12:30" en el JSON es claramente un texto; escrito en el YAML sin comillas, el primer lector 1.1 lo convierte en un booleano o en un número. Aquí cada texto que aunque sea uno solo de los dos lectores leería como otra cosa se pone entre comillas, y la página te dice cuáles son.

Elige la sangría, dos o cuatro espacios, o la forma compacta en una sola línea. Si el JSON es una lista, puedes convertirlo en varios documentos YAML separados por ---, como se hace con los archivos de Kubernetes. Y si el JSON no se puede leer, el error tiene nombre también aquí: la coma final antes del cierre, las comillas simples, el comentario, la clave sin comillas. El lector JSON está escrito a propósito: el del navegador redondea los enteros grandes, y cada navegador señala el error a su manera. Para arreglar un JSON sin cambiar de formato, sangrarlo u ordenar sus claves, está Formatear y validar JSON.

Cómo se ha probado

El juez no es esta página: es PyYAML, el lector YAML de Python, usado de dos maneras. Tal cual da la lectura 1.1; con las reglas del Core Schema reescritas a partir del texto de la especificación 1.2 da la lectura 1.2. En 500 documentos generados al azar, llenos de las trampas de arriba, con anclas, fusiones y varios documentos, los valores de la página deben coincidir con los suyos en las dos lecturas, y la lista de líneas señaladas debe ser exactamente la de las líneas en las que las dos lecturas de PyYAML no están de acuerdo, ni una más ni una menos. Lo mismo vale para los tabuladores: en 600 documentos con un tabulador puesto al azar, la lectura 1.1 de la página acepta y rechaza exactamente los que acepta y rechaza PyYAML, y cuando se para por el tabulador señala la misma línea y la misma columna.

En el otro sentido, 400 estructuras JSON generadas al azar, escritas con tres sangrías distintas, dan la vuelta completa: del JSON al YAML y otra vez al JSON, y al final deben volver idénticas. Por el camino el YAML producido lo vuelve a leer PyYAML en las dos versiones, y debe dar el mismo dato que el JSON de partida. Por último, el lector JSON se compara con el módulo json de Python en 1200 textos estropeados a propósito: deben aceptar y rechazar los mismos, y señalar la misma línea.

Lo que no hace

No conserva los comentarios. JSON no los tiene, así que al pasar de YAML a JSON desaparecen, y al volver no reaparecen. No comprueba que el archivo sea una configuración válida para el programa que la leerá: si un docker-compose tiene los campos correctos solo lo sabe docker. No convierte las etiquetas de CloudFormation en la forma larga que se usa en el JSON de ese servicio, las quita y lo dice. No adivina todas las codificaciones: lee UTF-8 y UTF-16, y un archivo guardado con otra se lee como Windows-1252, diciéndolo.

No convierte otros formatos. Para el XML está XML a JSON y al revés, para convertir una lista JSON en una tabla está JSON a CSV, y si el archivo YAML está dentro de una respuesta de ChatGPT o de Claude, para sacarlo limpio está Extrae el código de la IA.