JSON Toolkit

Los límites de la conversión entre JSON ↔ YAML y XML

En resumen: La afirmación de que JSON es un subconjunto de YAML solo garantiza una dirección, y XML no tiene ningún mapeo oficial a JSON: todo se apoya en convenciones.

Intermedio~12 min de lecturaPublicado el 2026-10-30Actualizado el 2026-10-30
Portada de Los límites de la conversión entre JSON ↔ YAML y XML

En resumen: usa JSON como formato intermedio: analiza el origen en un modelo de datos y después serializa al destino; antes de convertir, decide si los comentarios, los atributos y espacios de nombres de XML y los tipos numéricos o booleanos deben sobrevivir.

Que una tubería de conversión sea usable no depende de lo bonita que se vea la salida, sino de si eres consciente de cuánto ha descartado.

1. JSON y YAML: contención en una sola dirección

La especificación YAML 1.2 lo dice claramente: JSON es un subconjunto de YAML. Es decir, cualquier JSON válido es YAML válido:

{"name": "json", "tags": ["a", "b"], "count": 3}

Este fragmento es a la vez JSON y estilo flow de YAML. Lo contrario no se cumple.

Característica JSON YAML 1.2
Comentarios ✗ ✓
Anclas y alias ✗ ✓
Varios documentos (---) ✗ ✓
Claves que no son cadenas ✗ ✓ (1: a, true: b)
Claves complejas ✗ ✓ (? [a, b])
Sensible a la indentación ✗ ✓ (se rechaza la indentación con tabuladores)
Inferencia de tipos explícita implícita (0o17, 0x1F, .inf)
Legibilidad en una sola línea buena mala (el contenido largo depende de la sintaxis de plegado)

1.1 La inferencia de tipos es la mayor trampa

YAML analiza algunos valores que parecen cadenas como otros tipos:

zip: 01234        # ¿cadena o entero octal? el esquema core de YAML 1.2 lo trata como cadena
version: 1.10     # 1.1 (un float); la semántica se pierde
country: NO       # una cadena en YAML 1.2; booleano false en YAML 1.1
date: 2026-10-30  # algunas implementaciones lo analizan como objeto de fecha

El ejemplo de NO ha quemado a mucha gente: con un analizador YAML 1.1 (algunas bibliotecas antiguas), country: NO se convierte en false. Contramedida: entrecomilla todos los identificadores que "parecen un número o un booleano", como en version: "1.10".

1.2 Anclas, alias y múltiples documentos

defaults: &defaults
  retries: 3
  timeout: 30

serviceA:
  <<: *defaults
  host: a.example.com

---
serviceB:
  <<: *defaults
  host: b.example.com

Tras expandir las anclas y convertir a JSON, normalmente acabas con dos objetos de configuración duplicados, o con un array (los múltiples documentos deben convertirse en [{...}, {...}]). De cualquier forma, las anclas no se restauran en la conversión inversa: esa pérdida es inevitable.

1.3 Conversión que preserva los comentarios

La mayoría de las bibliotecas simplemente descartan los comentarios durante la conversión. Cuando necesites conservarlos, usa la API de Document del paquete yaml:

import { parseDocument } from 'yaml';

const document = parseDocument(`
# Configuración del servicio
port: 8080
`);

document.set('port', 3000);
console.log(document.toString());
// # Configuración del servicio
// port: 3000

La prueba es sencilla: si este archivo va a ser editado por personas una y otra vez, no tomes el camino "analizar → objeto → serializar".

1.4 Cómo verificar la consistencia de ida y vuelta

/**
 * Verifica la consistencia de ida y vuelta para JSON → YAML → JSON.
 * @param sourceValue Valor JSON original
 * @param stringify Función de serialización YAML
 * @param parse Función de análisis YAML
 * @returns Si los dos resultados son exactamente iguales
 */
function isRoundTripStable(
  sourceValue: unknown,
  stringify: (input: unknown) => string,
  parse: (input: string) => unknown,
): boolean {
  const yamlText = stringify(sourceValue);
  const restored = parse(yamlText);
  return JSON.stringify(restored) === JSON.stringify(sourceValue);
}

Ejecutarla contra datos reales vale más que leer la documentación diez veces. Asegúrate de que tu conjunto de muestras cubra: null, la cadena vacía, el array vacío, "00", "1e5", cero negativo, enteros mayores que 2^53 y cadenas largas que contengan saltos de línea.

2. JSON y XML: no existe un mapeo estándar

XML es bastante anterior a JSON y tiene capacidades estructurales mucho más potentes (atributos, espacios de nombres, contenido mixto, DTD). Entre los dos no hay ninguna especificación de mapeo oficial; todas las herramientas hacen lo mismo: elegir una convención e intentar no perder demasiado.

2.1 Convenciones habituales

Convención Representación Ejemplo
Elemento → clave de objeto Un elemento con el mismo nombre se convierte en un campo <a>1</a> → {"a": "1"}
Atributo → prefijo @ @name <a id="1"/> → {"a": {"@id": "1"}}
Texto → #text Cuando hay tanto atributo como texto <a id="1">hi</a> → {"a": {"@id": "1", "#text": "hi"}}
Elemento repetido → array Dos o más apariciones se convierten en un array <i>1</i><i>2</i> → {"i": ["1","2"]}
Espacio de nombres → prefijo ns:tag <ns:tag/> → {"ns:tag": ...}
<order id="A1001">
  <item sku="X1" qty="2">笔记本</item>
  <item sku="X2" qty="1">钢笔</item>
</order>
{
  "order": {
    "@id": "A1001",
    "item": [
      { "@sku": "X1", "@qty": "2", "#text": "笔记本" },
      { "@sku": "X2", "@qty": "1", "#text": "钢笔" }
    ]
  }
}

2.2 Cinco pérdidas inevitables

  1. Orden de los elementos: los objetos JSON no tienen orden, mientras que XML es una secuencia ordenada de elementos;
  2. Atributos frente a elementos hijos: tienen semánticas distintas en XML, pero ambos se convierten en campos simples en JSON;
  3. Contenido mixto: estructuras como <p>你好 <b>世界</b> 再见</p> no pueden expresarse con un objeto simple;
  4. Declaraciones de espacio de nombres: xmlns es un concepto de ámbito; una vez aplanado en campos, el ámbito se pierde;
  5. CDATA y entidades: <![CDATA[...]]> y &amp; no son más que texto en JSON.

2.3 El dilema de "un elemento o un array"

<list><item>1</item></list>

Con un único item, xml2js devuelve un objeto por defecto y solo devuelve un array cuando hay dos. Como resultado, el código del frontend tiene que escribir Array.isArray(x) ? x : [x].

Contramedida: activa la opción "siempre array" al analizar, o declara el campo como tipo array según un schema.

import { parseStringPromise } from 'xml2js';

const parsed = await parseStringPromise(xmlText, {
  explicitArray: true,   // devuelve un array incluso para un solo elemento
  trim: true,
  explicitRoot: false,
});

2.4 Recordatorio de seguridad

Antes de analizar XML no confiable debes desactivar las entidades externas, de lo contrario puedes desencadenar XXE (lectura de archivos locales, sondeo de redes internas):

// En el ecosistema Node, las DTD y las entidades externas suelen desactivarse mediante opciones del analizador
const parserOptions = { doctype: false, externalEntities: false };

XML → JSON es solo la primera capa de la conversión; convertir no elimina la superficie de ataque que trae XML.

3. Dónde encaja cada uno de los tres formatos

Escenario Formato recomendado Motivo
API HTTP públicas JSON Admitido de forma nativa por los navegadores y todos los lenguajes
Configuración mantenida a mano YAML Comentarios, indentación, legibilidad
Documentos que necesitan un schema fuerte y espacios de nombres (SOAP, Office Open XML, SVG) XML Capacidades estructurales y ecosistema existente
Interacción con herramientas de operaciones (K8s, CI) YAML El valor por defecto del ecosistema
Persistencia, cachés, registros JSON / JSONL Universal y sin dependencias

4. Notas de implementación

import { stringify as toYaml } from 'yaml';

/**
 * Convierte un valor JSON a texto YAML sin escapar los caracteres chinos.
 * @param value El valor JSON que se va a convertir
 * @returns El texto YAML
 */
function jsonToYaml(value: unknown): string {
  return toYaml(value, {
    indent: 2,
    lineWidth: 0,      // desactiva el ajuste automático para que las cadenas largas no se dividan
    defaultStringType: 'QUOTE_DOUBLE',
  });
}

Algunas opciones prácticas:

  • lineWidth: 0 desactiva el ajuste automático; de lo contrario, las URL largas se parten entre líneas y se vuelven difíciles de leer;
  • entrecomillar todo con comillas dobles evita que valores como NO y 1.10 se malinterpreten;
  • para datos con precisión numérica sensible, convierte a cadenas antes de serializar.

Para la dirección de XML, fija una única función de mapeo y pon el "prefijo de atributo", el "nombre de la clave de texto" y la "estrategia de arrays" en su firma en lugar de dispersarlos:

type XmlMappingOptions = {
  attributePrefix: string;
  textKey: string;
  alwaysArray: boolean;
};

const defaultMapping: XmlMappingOptions = {
  attributePrefix: '@',
  textKey: '#text',
  alwaysArray: false,
};

5. Lista de comprobación

  • [ ] Todo identificador "parecido a número/booleano" en YAML está entrecomillado;
  • [ ] Se ha definido un conjunto de muestras de validación para JSON → YAML → JSON y está cubierto por tests;
  • [ ] Cuando hay que preservar comentarios, se usa la API de Document en lugar de una ida y vuelta por objeto;
  • [ ] La convención de mapeo XML está escrita y el equipo comparte un único conjunto de parámetros;
  • [ ] Las DTD y las entidades externas están desactivadas al analizar XML no confiable;
  • [ ] Se comparan recuentos de bytes y de campos antes y después de la conversión, y cualquier anomalía genera una alerta.

Preguntas frecuentes

¿Cómo debo elegir la dirección de conversión entre JSON, YAML y XML?

Prefiere JSON como formato intermedio: analiza primero YAML y XML en un modelo de datos y después serializa desde ese modelo en lugar de reescribir el texto. Usa la API de Document de YAML cuando los comentarios deban sobrevivir, y fija una convención de mapeo XML antes de necesitar atributos o espacios de nombres.

¿Por qué la conversión de XML a JSON pierde atributos y espacios de nombres?

JSON no tiene el concepto de atributos ni de espacios de nombres, así que los atributos, prefijos y URI de espacio de nombres de XML deben plegarse en claves ordinarias, normalmente con un prefijo @ o un nodo #text. En cuanto las reglas de mapeo divergen, el mismo XML produce JSON distintos y no puede ir y volver.

¿Debo mantener JSON, YAML y XML sincronizados de forma bidireccional a largo plazo?

No. Los comentarios, las anclas, los atributos de XML y los espacios de nombres tienen pérdidas entre formatos, y la sincronización bidireccional va acumulando diferencias. Elige un formato de origen y trata los demás como exportaciones puntuales o vistas temporales.

Referencias

Artículos relacionados

Convertir JSON a y desde CSV y datos tabulares

CSV es bidimensional, JSON tiene forma de árbol. La parte difícil de la conversión no es el código, sino decidir de antemano cómo se aplanan los arrays y cómo se preservan los tipos.

Principiante~10 min de lecturaActualizado el 2026-10-30

Gestión de JSON para configuración, fixtures y datos locales

La configuración debe estar por capas y validada; los fixtures deben ser deterministas, legibles y comparables con diff. Si estos dos tipos de archivos se gestionan mal, el coste de diagnóstico se mantiene alto durante mucho tiempo.

Principiante~10 min de lecturaActualizado el 2026-10-30

JSON a YAML desde la línea de comandos: cuatro trampas detrás de un solo comando yq

El comando más copiado en los tutoriales, yq -P input.json > output.yaml, sigue emitiendo JSON en yq v4. Medimos yq v4.44.6, PyYAML 6.0.3 y js-yaml con una muestra de 2.39 MB, explicamos por qué la extensión de entrada fija el formato de salida y damos las recetas correctas para conversión por lotes, comillas, indentación y precisión de enteros grandes.

Intermedio~9 min de lecturaActualizado el 2026-11-03