← Todos los artículos

Conversión de XML a JSON: atributos, nodos de texto, arrays y namespaces

Convierte XML a JSON correctamente: cómo se mapean atributos, nodos de texto, elementos repetidos y namespaces a JSON — con convenciones, casos límite y código JS/Python.

Convertir XML a JSON suena mecánico hasta que te topas con las partes del XML para las que JSON no tiene equivalente directo: atributos, contenido mixto de texto y elementos, elementos que aparecen una o varias veces y namespaces. No hay un único mapeo "correcto" —— sólo convenciones. Esta guía explica las convenciones estándar, las decisiones que debes tomar y cómo convertir XML a JSON en JavaScript, Python y el navegador.

El mapeo de un vistazo

La mayoría de conversores XML a JSON (xmltodict, fast-xml-parser y la herramienta de este sitio) siguen la misma forma: cada elemento se convierte en un objeto, los atributos en claves con prefijo especial y el texto en el valor o en una clave reservada.

<!-- XML -->
<note id="1" priority="high">
  <to>Ada</to>
  <from>Bob</from>
  <body>Hello &amp; welcome</body>
</note>
// JSON
{
  "note": {
    "@id": "1",
    "@priority": "high",
    "to": "Ada",
    "from": "Bob",
    "body": "Hello & welcome"
  }
}

Atributos → claves con prefijo @

Los objetos JSON no tienen noción de atributo, así que la convención casi universal es anteponer @ a los nombres de atributo. Eso los distingue de los elementos hijos y hace reversible el mapeo.

<book id="b1" lang="en"/>
→ { "book": { "@id": "b1", "@lang": "en" } }

Algunas herramientas usan otro prefijo ($, _) o un objeto anidado "@attributes". Elige uno y aplícalo de forma consistente —— el código que lo consuma necesita saber dónde están los atributos.

Nodos de texto y contenido mixto

Cuando un elemento contiene solo texto, se reduce a un valor de cadena. Pero cuando un elemento tiene atributos y texto, el texto necesita un sitio —— por convención, la clave #text.

<price currency="USD">9.99</price>
→ { "price": { "@currency": "USD", "#text": "9.99" } }

<title>Effective TypeScript</title>
→ { "title": "Effective TypeScript" }

El contenido verdaderamente mixto (texto intercalado con elementos hijos, como en marcado tipo HTML) es el caso más difícil —— la mayoría de conversores orientados a datos concatenan o descartan el texto suelto. Si tu XML es de estilo documento en vez de datos, espera pérdida aquí.

El problema de uno vs array

Esta es la trampa que rompe más código que ninguna otra. Un elemento que aparece una vez se convierte en objeto; el mismo elemento apareciendo dos veces se convierte en array. La forma JSON depende de los datos, no del esquema:

<tags><tag>a</tag></tags>
→ { "tags": { "tag": "a" } }          // objeto

<tags><tag>a</tag><tag>b</tag></tags>
→ { "tags": { "tag": ["a", "b"] } }   // array

Los consumidores que esperan tags.tag como array siempre se romperán con un solo elemento. Dos soluciones: configura el parser para tratar elementos repetibles conocidos siempre como arrays, o normaliza después de parsear (const arr = [].concat(node.tag ?? [])).

Namespaces

Los namespaces XML usan prefijos (soap:Envelope) ligados por declaraciones xmlns. JSON no tiene concepto de namespace, así que los conversores suelen optar por una de estas estrategias:

  • Mantén el prefijo en la clave —— "soap:Envelope". Simple y reversible, pero la clave contiene dos puntos y necesitarás acceso por corchetes (obj["soap:Envelope"]).
  • Quita el prefijo —— "Envelope". Claves más limpias, pero pierdes el namespace y arriesgas colisiones entre dos namespaces que comparten el mismo nombre local.
  • Mantén xmlns como atributos —— las declaraciones se convierten en claves "@xmlns:soap" para que el vínculo sobreviva al round-trip.

Para la mayoría de tareas de datos, mantener el prefijo en la clave es el valor por defecto más seguro —— nunca pierde información.

Entidades y CDATA

Un conversor correcto decodifica las cinco entidades predefinidas (&lt;, &gt;, &amp;, &quot;, &apos;) y las referencias numéricas (&#169;) a sus caracteres, y trata los bloques <![CDATA[...]]> como texto literal.

Nombres de convención: BadgerFish, GData, Parker

La asignación "@ para atributos / #text para texto" no es la única en circulación. Tres convenciones con nombre que verás leyendo salidas XML→JSON de otros sistemas:

  • BadgerFish —— atributos bajo una clave prefijada con @; texto bajo $; declaraciones de namespace bajo @xmlns. Verboso pero sin pérdida.
  • GData —— variante de Google: atributos prefijados con $; texto bajo $t; los elementos repetidos siempre son arrays. Sin pérdida y forma predecible.
  • Parker —— descarta los atributos por completo; el mapeo más simple y con más pérdida. Útil cuando controlas ambos lados y solo te importan los valores de los elementos.

Cuando integras con un sistema que ya produce JSON-from-XML, identifica primero qué convención usa antes de escribir el código de parsing.

Consultar el resultado con JSONPath

Una vez convertido el XML, puedes referenciar valores con JSONPath. Dos pequeños ajustes respecto a las costumbres de XPath:

  • Las claves de atributo llevan el prefijo @ del mapeo, así que el @id de XPath se convierte en $..['@id'] en JSONPath.
  • La cuestión de uno vs array hace que un XPath que funciona como book/title pueda necesitar ser $..book[*].title en JSONPath para gestionar ambas formas.

Cómo convertir XML a JSON en código

// JavaScript (navegador) —— DOMParser + un pequeño recorrido, o una librería:
import { XMLParser } from 'fast-xml-parser';
const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@' });
const obj = parser.parse(xmlString);

# Python —— xmltodict mapea atributos a "@name" y texto a "#text"
import xmltodict, json
doc = xmltodict.parse(xml_string)
print(json.dumps(doc, indent=2))

Convertir XML a JSON online

Para una conversión rápida, pega tu XML en el conversor JSON ⇄ XML y haz clic en To JSON. Aplica las convenciones de arriba —— @ para atributos, #text para contenido mixto, arrays para elementos repetidos —— y se ejecuta enteramente en tu navegador, así que los feeds internos y payloads de API nunca salen de tu máquina.

Preguntas frecuentes

¿Cómo se representan los atributos XML en JSON?

Por convención se convierten en claves prefijadas con @ (p. ej. @id), distintas de los elementos hijo, para que el mapeo pueda revertirse.

¿Por qué el mismo elemento se convierte a veces en objeto y a veces en array?

Porque la forma sigue a los datos: una aparición se mapea a objeto, varias a array. Configura tu parser para tratar como array los elementos repetibles conocidos, o normaliza con [].concat(value) tras parsear.

¿Qué pasa con el texto dentro de un elemento con atributos?

Se guarda bajo la clave reservada #text, ya que el objeto ya contiene los atributos. Un elemento con solo texto se reduce a una cadena simple.

¿Cómo se manejan los namespaces XML?

JSON no tiene namespaces. El enfoque más seguro mantiene el prefijo en la clave ("soap:Envelope") y las declaraciones xmlns como atributos @xmlns:* para no perder nada.

Herramientas y guías relacionadas