Kodokon kodokon.com

من HTML إلى DOM: التحليل والتعافي من الأخطاء

افهم كيف يحوّل المتصفح أي دفق HTML، حتى لو كان مشوّهًا، إلى شجرة DOM حتمية.

10 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

على عكس XML، لا يوجد في HTML ما يُسمى بالخطأ القاتل: تحدّد مواصفة WHATWG، بايتًا ببايت، كيف يجب أن يتحوّل أي دفق مدخلات - حتى المشوّه منه - إلى شجرة DOM. يعمل المحلّل على مرحلتين: يقطّع المُرمِّز (tokenizer) الدفق إلى رموز (وسوم، نصوص، تعليقات)، ثم يدرجها باني الشجرة (tree builder) وفقًا لآلة حالات تُسمّى حالاتها أنماط الإدراج (in body، in table، وهكذا). لكل "خطأ تحليل" تعافٍ موحّد: متصفحان متوافقان يُنتجان الـ DOM ذاته تمامًا.

HTML
<table>
  <tr><td>Cell</td></tr>
</table>
يحتوي الـ DOM الناتج على tbody لم تكتبه أبدًا.

يدرج المحلّل وسومًا ضمنية: يظهر <tbody> حول الصفوف، وتُغلق <li> و<p> و<option> تلقائيًا أمام بعض الوسوم المفتوحة. والأشدّ جذرية من ذلك: أي محتوى يوجد داخل <table> حيث لا يُسمح به يُنتزع منه ويُعاد إدراجه قبله مباشرة، وهي آلية تُسمّى الرعاية بالتبنّي (foster parenting). تعمل محدِّدات CSS ونصوصك البرمجية دائمًا على الـ DOM المصحَّح، لا على مصدرك أبدًا.

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>
الرعاية بالتبنّي مُلاحَظة عبر DOMParser.

تؤدي وسوم التنسيق المتداخلة بشكل خاطئ إلى تشغيل خوارزمية وكالة التبنّي (adoption agency algorithm)، وهي من أكثر أجزاء المواصفة مكرًا: يستنسخ المحلّل عناصر التنسيق النشطة ويعيد توزيعها لإنتاج شجرة متداخلة على نحو صحيح. يُظهر الترميز المتقاطع أدناه النتيجة.

HTML
<p>
  <b>One <i>two</b> three</i>
</p>
الـ DOM الناتج: <b>One <i>two</i></b><i> three</i> - عنصر i يُقسَم إلى عنصرين.

المحلّل هو محلّل متدفّق (streaming): يبني الشجرة مع وصول البايتات. يعلّق وسم <script> المتزامن عمله - إذ يمكن للنص البرمجي استدعاء document.write وحقن رموز في الدفق - لكن الماسح المسبق (preload scanner) يستمر في مسح ما تبقّى من HTML لتحميل الصور وأوراق الأنماط والنصوص البرمجية مسبقًا. وعند استدعائه بعد انتهاء التحليل، يُفعّل document.write استدعاءَ document.open ويمحو الصفحة بأكملها: إنه من أقدم مصائد المنصّة.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. ماذا يحدث لعنصر <div> في <table><div>Out</div><tr><td>A</td></tr></table>؟
    • يُزال بصمت من الـ DOM
    • يُنقل قبل الجدول عبر الرعاية بالتبنّي
    • يُغلَّف داخل خلية <td> تُنشأ من أجله
    • يبقى ابنًا مباشرًا للجدول
  2. كيف تتعامل مواصفة HTML مع مستند مشوّه؟
    • تترك لكل متصفح اختيار استراتيجية التعافي الخاصة به
    • تفرض التبديل إلى نمط الغرابة (quirks mode)
    • تحدّد خوارزمية تعافٍ حتمية، متطابقة عبر جميع المتصفحات المتوافقة
    • تفرض توقّف التحليل عند أول خطأ
  3. أي DOM يُنتجه المقتطف <p><div>X</div></p>؟
    • <p></p><div>X</div><p></p>: عنصر div يُغلق أول p، والوسم اليتيم </p> يُنشئ ثانيًا فارغًا
    • <p><div>X</div></p>، يُحفَظ كما هو
    • <div><p>X</p></div>، يعكس المحلّل التداخل