El Editor de XML muestra tu código y su árbol de elementos uno al lado del otro. Lo que escribes aparece al instante en el árbol (elementos, atributos, texto, comentarios, CDATA y espacios de nombres), y un clic en cualquier nodo te lleva a su lugar en el código. También puedes editar nombres, valores y texto directamente en el árbol, hacer consultas XPath y convertir el documento a JSON o YAML.
Todo se ejecuta en tu navegador. Los documentos no se suben, no hay registro ni publicidad.
Etiquetas, atributos, valores, entidades, comentarios y CDATA con sus propios colores, números de línea, etiquetas de cierre que se cierran solas y una lista clara de problemas con línea y columna.
Pliega y despliega elementos, ve atributos, texto, comentarios, instrucciones de procesamiento y espacios de nombres, y sigue la ruta del nodo seleccionado.
Renombra elementos y atributos, cambia valores y texto, añade, mueve y quita elementos: todo se escribe en el código como pequeñas ediciones, con los caracteres especiales escapados.
Un campo XPath 1.0 marca los nodos que coinciden; la búsqueda encuentra nombres, valores y texto. Los prefijos de espacio de nombres del documento funcionan en XPath.
Nunca se carga una DTD, un esquema ni una entidad externa, y no se expande ninguna entidad, así que XXE y las bombas de entidades no funcionan.
Sangra o minifica el documento, o conviértelo a JSON o YAML: los atributos como @name, el texto como #text y los elementos repetidos como listas.
Cualquier página https (y localhost) puede integrar el editor con un <iframe> y ?embed=1, sin registro y sin clave. Integrado, el editor oculta este texto y muestra un botón Guardar. Hay dos formas de meter y sacar el documento.
src= abre un archivo (tu servidor debe permitir CORS), webhook= hace que «Guardar» (Ctrl+S) envíe el documento a esa dirección. Añade &token=… para una cabecera Authorization: Bearer … y &auto para guardar después de cada cambio.
<iframe src="https://xml.giit.ch/?embed=1&src=https://your-site.com/data/catalog.xml&webhook=https://your-site.com/save.php"
allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
El webhook recibe un POST con JSON { editor: "xml", event: "save", id, name, content, updated }. Un pequeño script PHP que lo guarda:
<?php
header('Access-Control-Allow-Origin: https://xml.giit.ch');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Methods: POST, OPTIONS');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') exit;
if (($_SERVER['HTTP_AUTHORIZATION'] ?? '') !== 'Bearer SECRET') { http_response_code(403); exit; }
$d = json_decode(file_get_contents('php://input'), true);
$name = preg_replace('/[^\w\- ]/u', '_', $d['name']);
file_put_contents(__DIR__ . "/data/$name.xml", $d['content']);
echo '{"ok":true}';
El editor dice xmleditor:ready, tu página responde con xmleditor:load, el editor informa con xmleditor:loaded, con xmleditor:change en cada edición real y con xmleditor:save cuando el usuario guarda. Tu página puede enviar xmleditor:get (el estado actual) o xmleditor:save (pulsar Guardar). Así el guardado pasa por tu propio inicio de sesión y tu sesión.
<iframe id="ed" src="https://xml.giit.ch/?embed=1" allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
<script>
const ed = document.getElementById('ed');
const ORIGIN = 'https://xml.giit.ch';
addEventListener('message', async e => {
if (e.source !== ed.contentWindow || e.origin !== ORIGIN) return;
const m = e.data;
if (m.type === 'xmleditor:ready') { // el editor está listo: pásale el documento
ed.contentWindow.postMessage({
type: 'xmleditor:load',
name: 'Catalog',
content: await (await fetch('/data/catalog.xml')).text()
}, ORIGIN);
}
if (m.type === 'xmleditor:change') document.title = '● not saved'; // una edición real
if (m.type === 'xmleditor:save') { // el usuario hizo clic en «Guardar»
await fetch('/api/save', { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: m.name, content: m.content }) });
document.title = 'Saved';
}
});
// Un botón de guardar en tu propia página: la respuesta llega como xmleditor:save
function saveNow() { ed.contentWindow.postMessage({ type: 'xmleditor:get' }, ORIGIN); }
</script>
Asistente de IA dentro de tu página: también funciona en el marco. Con allow="clipboard-write" en el iframe, «Copiar prompt» usa el portapapeles directamente (si no, el editor recurre al antiguo comando de copiar o muestra el prompt para copiarlo a mano). Un enlace que envía la IA no puede llegar a un editor dentro de otro sitio web, así que el editor indica a la IA y al usuario que peguen la respuesta completa de la IA en el editor, o que abran el editor en una ventana propia.
window.open("https://xml.giit.ch/?embed=window", "xmleditor-17") abre el editor completo en su propia ventana y usa los mismos mensajes con window.opener. Ahí sí le llegan los enlaces de una IA. xmleditor:load también puede llevar context: { host, title, rules } (el prompt de IA dice entonces a dónde pertenece el documento y sigue tus reglas) y hook: { url, token }, un webhook solo para este documento que nunca se guarda. Al cerrar la ventana con cambios sin guardar se envía xmleditor:closing.
Pasa al editor tu propio prompt, una dirección en tu sitio y una clave para esta sesión del editor. El diálogo de IA muestra entonces «Conectado a» tu sitio, lo que le dices a la IA y la opción cambiar el documento actual o crear uno nuevo; Copiar prompt lo junta todo. La IA envía su resultado con la clave a tu servidor, y tu página lo abre en el editor: un documento nuevo se abre aparte y se queda en el navegador del usuario. Una clave por sesión del editor: sigue siendo válida mientras el editor esté abierto, y solo mientras no tenga ninguna el editor la pide con xmleditor:key-request. El editor nunca envía la clave por sí mismo ni la guarda; la dirección debe ser https en tu propio host o en un subdominio suyo.
const key = async () => (await fetch('/api/ai-key.php?doc=17')).json(); // una clave por sesión del editor
const k = await key();
ed.contentWindow.postMessage({ type: 'xmleditor:load', name: 'Catalog', content, ai: {
label: 'My Site', prompt: 'Keep the sku attributes. Prices in CHF.',
endpoint: 'https://your-site.com/api/ai-result.php', key: k.key } }, ORIGIN);
// recuerda el id de xmleditor:loaded e ignora change/save/closing con otro id
// solo mientras el editor no tenga clave:
if (m.type === 'xmleditor:key-request') { const k = await key(); ed.contentWindow.postMessage({ type: 'xmleditor:ai', key: k.key }, ORIGIN); }
// mientras el editor esté abierto, avisa a tu servidor cada minuto; cerrar el editor o la página anula la clave
setInterval(() => fetch('/api/ai-key.php?alive=' + k.key.slice(0, 8)), 60000);
// tu servidor tiene un resultado (polling, SSE …): target es «current» o «new»
ed.contentWindow.postMessage({ type: 'xmleditor:load', name: 'Catalog', content: draft, from: 'ai', target }, ORIGIN);
Crea claves con al menos 128 bits aleatorios, guarda solo su hash, vincula cada una al usuario con sesión iniciada, al documento y a esta sesión del editor, crea una por sesión, mantenla válida solo mientras tu página informe de que la sesión está abierta, y anúlala cuando se cierre el editor o la página.
El protocolo completo está en llms.txt: dáselo a una IA y construirá la conexión para tu sistema. El Editor de LaTeX y el Editor de SVG funcionan igual con los prefijos latexeditor: y svgeditor:.
No. El editor se ejecuta por completo en tu navegador. Tus documentos nunca se envían a un servidor, salvo que tú mismo configures un webhook a tu propio servidor.
Sí. Usa el analizador XML propio del navegador y muestra el primer error de buena formación con su línea y columna, además de prefijos de espacio de nombres no declarados e ids usados dos veces. No valida con una DTD ni con un XML Schema.
Sí. El editor nunca carga una DTD, un esquema ni una entidad externa y nunca expande entidades de una DTD, así que los ataques XXE y de expansión de entidades no funcionan. Las referencias a esas entidades se quedan en el texto tal como están escritas.
Escribe una expresión XPath 1.0 encima del árbol, por ejemplo //book[price > 30]/title. Los nodos que coinciden se marcan en el árbol; las flechas van de uno al siguiente. Los prefijos declarados en el documento funcionan, y _: representa el espacio de nombres predeterminado del elemento raíz.
Sí. En Convertir o Exportar, el documento se convierte en JSON o YAML: los atributos como @name, el texto como #text y los elementos repetidos como listas.
Solo en tu navegador. Haz clic en el botón de carpeta arriba a la izquierda (Mis documentos) para abrirlos, renombrarlos, duplicarlos, descargarlos o eliminarlos. Si borras los datos del sitio en tu navegador, desaparecen; descarga los que quieras conservar, o deja que el editor los envíe a tu propio servidor («Guardar en servidor»).
Sí, cualquier IA: ChatGPT, Claude, Gemini, Copilot o la IA de tu herramienta de programación. Haz clic en «Asistente de IA» y luego en «Copiar prompt», pégalo en tu IA y dile qué debe escribir. La IA responde con un enlace; haz clic en él y el documento aparece en tu editor. «Deshacer» revierte cada cambio.
Sí. Intégralo con un iframe e intercambia documentos con postMessage, o deja que envíe cada versión guardada a tu servidor con un webhook. Mira Usa el editor en tu propio sitio web para ver ejemplos.
No. El editor es gratuito, sin anuncios y sin registro.