Kodokon kodokon.com

Del HTML al DOM: análisis y recuperación de errores

Comprende cómo el navegador convierte cualquier flujo HTML, incluso mal formado, en un árbol DOM determinista.

10 min · 3 preguntas

Abrir esta lección en Kodokon

A diferencia de XML, HTML no tiene algo como un error fatal: la especificación del WHATWG define, byte a byte, cómo cualquier flujo de entrada - incluso mal formado - debe convertirse en un árbol DOM. El analizador funciona en dos etapas: el tokenizador divide el flujo en tokens (etiquetas, texto, comentarios), luego el constructor del árbol los inserta según una máquina de estados cuyos estados se llaman modos de inserción (in body, in table, etc.). Cada "error de análisis" tiene una recuperación estandarizada: dos navegadores conformes producen exactamente el mismo DOM.

HTML
<table>
  <tr><td>Cell</td></tr>
</table>
El DOM resultante contiene un tbody que nunca escribiste.

El analizador inserta etiquetas implícitas: aparece un <tbody> alrededor de las filas, y <li>, <p> u <option> se cierran automáticamente ante ciertas etiquetas de apertura. Más radical aún: cualquier contenido encontrado dentro de una <table> donde no está permitido es extraído de ella y reinsertado justo antes, un mecanismo llamado foster parenting. Tus selectores CSS y tus scripts siempre funcionan sobre el DOM corregido, nunca sobre tu fuente.

JAVASCRIPT
const html =
  "<table><div>out</div><tr><td>ok</td></tr></table>";
const doc = new DOMParser()
  .parseFromString(html, "text/html");
console.log(doc.body.innerHTML);
// <div>out</div><table>...</table>
Foster parenting observado con DOMParser.

Las etiquetas de formato mal anidadas activan el algoritmo de la agencia de adopción, una de las partes más retorcidas de la especificación: el analizador clona y redistribuye los elementos de formato activos para producir un árbol correctamente anidado. El marcado cruzado de abajo muestra el resultado.

HTML
<p>
  <b>One <i>two</b> three</i>
</p>
DOM resultante: <b>One <i>two</i></b><i> three</i> - la i se divide en dos elementos.

El analizador es un analizador de flujo (streaming): construye el árbol a medida que llegan los bytes. Un <script> síncrono lo suspende - el script puede llamar a document.write e inyectar tokens en el flujo -, pero el escáner de precarga (preload scanner) sigue recorriendo el HTML restante para precargar imágenes, hojas de estilo y scripts. Llamado después de que el análisis ha terminado, document.write desencadena document.open y borra toda la página: es una de las trampas más antiguas de la plataforma.

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. ¿Qué le pasa al <div> en <table><div>Out</div><tr><td>A</td></tr></table>?
    • Se elimina silenciosamente del DOM
    • Se mueve delante de la tabla por foster parenting
    • Se envuelve en una celda <td> creada para él
    • Permanece como hijo directo de la tabla
  2. ¿Cómo maneja la especificación de HTML un documento mal formado?
    • Deja que cada navegador elija su propia estrategia de recuperación
    • Exige cambiar al modo quirks
    • Define un algoritmo de recuperación determinista, idéntico en todos los navegadores conformes
    • Exige detener el análisis en el primer error
  3. ¿Qué DOM produce el fragmento <p><div>X</div></p>?
    • <p></p><div>X</div><p></p>: el div cierra el primer p, y la </p> huérfana crea un segundo, vacío
    • <p><div>X</div></p>, conservado tal cual
    • <div><p>X</p></div>, el analizador invierte el anidamiento