3.3. Ejemplo con librería (fast-xml-parser + Tabulator)
En este apartado vamos a ver cómo procesar un XML utilizando librerías externas para simplificar el parseo (XML → JSON) y la visualización (tabla interactiva).
Trabajaremos con el dataset de agenda cultural (eventos.xml) del portal de Datos Abiertos de la Junta de Castilla y León.
📦 Cómo incluir las librerías
En este curso usaremos CDN (no hace falta npm). Inserta los scripts/estilos en tu HTML antes de tu código:
<!-- fast-xml-parser: convierte XML → JSON -->
<script src="https://cdn.jsdelivr.net/npm/fast-xml-parser@4.4.0/dist/fast-xml-parser.min.js"></script>
<!-- Tabulator: tabla interactiva -->
<link
rel="stylesheet"
href="https://unpkg.com/tabulator-tables@6.2.5/dist/css/tabulator.min.css">
<script src="https://unpkg.com/tabulator-tables@6.2.5/dist/js/tabulator.min.js"></script>
<!-- Tu script -->
<script type="module" src="main.js"></script>
Consejo
Si más adelante empaquetas con Vite/Webpack, podrás:
import { XMLParser } from "fast-xml-parser";
import Tabulator from "tabulator-tables";
📌 Flujo de trabajo con librería
- Incluir
fast-xml-parsery Tabulator desde CDN. - Descargar el XML con
fetch(url).then(res => res.text()). - Parsear el XML con
XMLParser→ obtendrás un objeto JS. - Localizar la lista de elementos (p. ej.
json.root.elemento similar). - Mapear a un modelo de columnas útil para la interfaz.
- Renderizar una tabla interactiva con Tabulator (columnas, paginación, ordenación).
- Gestionar errores de red/parseo y mostrar un estado accesible.
🧩 Código paso a paso
1) Cargar y convertir el XML a JSON con fast-xml-parser
// Ruta del XML (ajusta a tu estructura)
const URL_XML = "datasets/xml/eventos.xml";
async function cargarXMLcomoJSON() {
// 1) Descargar XML como texto
const res = await fetch(URL_XML, { cache: "no-cache" });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const xmlText = await res.text();
// 2) Configurar el parser
const options = {
ignoreAttributes: false, // conserva atributos
attributeNamePrefix: "", // nombres de atributo sin prefijo
parseAttributeValue: true, // convierte "123" a número si procede
// Fuerza arrays para nodos donde esperas lista (opcional):
isArray: (name, jpath) => ["element", "evento", "monumento"].includes(name)
};
// 3) Parsear XML → JSON
const parser = new fxp.XMLParser(options);
const json = parser.parse(xmlText);
return json;
}
2) Detectar la forma del dataset y quedarnos con la lista
El nodo que agrupa cada evento puede llamarse distinto según el XML (por ejemplo, element, evento, etc.).
Ajusta este helper a tu fichero real:
function obtenerListaEventos(json) {
// Explora con console.log(json) para confirmar la ruta
const root = json.root ?? json.Eventos ?? json.eventos ?? json;
const lista = root.element ?? root.evento ?? root.Evento ?? [];
return Array.isArray(lista) ? lista : [lista]; // normaliza a array
}
3) Mapear a un modelo de columnas útil
Escogemos las claves que queremos mostrar (ajusta a tus nombres reales de etiqueta):
function aFilasTabla(eventos) {
return eventos.map(e => ({
Titulo_es: e.Titulo_es ?? e.titulo ?? "",
FechaInicio: e.FechaInicio ?? e.inicio ?? "",
FechaFin: e.FechaFin ?? e.fin ?? "",
LugarCelebracion: e.LugarCelebracion ?? e.lugar ?? "",
Municipio: e.Municipio ?? "",
Provincia: e.Provincia ?? ""
}));
}
4) Generar columnas automáticamente para Tabulator
function columnasDesdeDatos(data) {
const ejemplo = data[0] ?? {};
return Object.keys(ejemplo).map(k => ({
title: k,
field: k,
sorter: "string",
headerHozAlign: "left",
hozAlign: "left"
}));
}
5) Pintar la tabla con Tabulator
function renderTabla(selector, data) {
const columns = columnasDesdeDatos(data);
return new Tabulator(selector, {
data,
columns,
layout: "fitDataStretch",
pagination: true,
paginationSize: 10,
paginationSizeSelector: [10, 25, 50, 100],
placeholder: "No hay datos que mostrar",
progressiveRender: true,
progressiveRenderSize: 200,
columnDefaults: { headerHozAlign: "left", hozAlign: "left" }
});
}
6) Búsqueda global (opcional)
function activarBusquedaGlobal(input, table) {
input.addEventListener("input", () => {
const term = input.value.trim().toLowerCase();
if (!term) return table.clearFilter(true);
table.setFilter((row) => {
const obj = row.getData();
return Object.values(obj).some(v =>
String(v ?? "").toLowerCase().includes(term));
});
});
}
7) Ponerlo todo junto
(async () => {
try {
const json = await cargarXMLcomoJSON();
const eventos = obtenerListaEventos(json);
const filas = aFilasTabla(eventos);
const tabla = renderTabla("#tabla", filas);
// Si tienes un <input id="q"> en tu HTML:
const q = document.getElementById("q");
if (q) activarBusquedaGlobal(q, tabla);
} catch (err) {
console.error("Error al cargar/mostrar XML:", err);
const status = document.getElementById("status");
if (status) status.textContent = "❌ Error al cargar el XML. Comprueba la ruta y usa un servidor local.";
}
})();
Consejo
Explora siempre el JSON que devuelve el parser con console.log(json).
En XML reales es habitual encontrar namespaces y nodos opcionales. Con ignoreAttributes: false conservarás atributos útiles, y con isArray puedes forzar arrays para listas aunque solo haya un elemento.
⚖️ Comparación con el enfoque vanilla
| Aspecto | Vanilla (DOMParser + querySelectorAll) |
Con librerías (fast-xml-parser + Tabulator) |
|---|---|---|
| Parseo de XML | Manual (DOM, nodos, textos, atributos) | Automático XML → JSON con opciones (ignoreAttributes, isArray, etc.) |
| Namespaces | Hay que manejarlos en selectores | Serializa claves con prefijo; puedes normalizarlas después |
| Estructuras y listas | Recorres nodos y construyes tus objetos | Obtienes objetos/arrays listos para usar |
| Tabla y UI | Manual (crear <table>, filtros, paginación) |
Tabulator ofrece paginación, ordenación, filtros |
| Robustez ante formatos reales | Depende de tu lógica de recorrido | Parser probado, reporta inconsistencias y soporta múltiples opciones |
| Dependencias | Ninguna | 2 dependencias (ligeras) |
| Curva de aprendizaje | Muy baja (si conoces DOM) | Muy baja (configurar parser y columnas) |
📝 Preguntas de repaso
Repaso
- ¿Qué ventajas aporta convertir el XML a JSON antes de trabajar con él?
- ¿Para qué sirven
ignoreAttributesyisArrayenfast-xml-parser? - ¿Qué pasos das para localizar la lista de eventos dentro del JSON resultante?
- ¿Qué ventajas ofrece Tabulator frente a construir la tabla a mano?
- ¿Cómo implementarías una búsqueda global sobre todas las columnas?