1. 13.2 解析 HTML 文档
      1. 13.2.1 解析模型概述
      2. 13.2.2 解析错误
      3. 13.2.3 输入字节流
        1. 13.2.3.1 使用已知字符编码解析
        2. 13.2.3.2 确定字符编码
        3. 13.2.3.3 字符编码
        4. 13.2.3.4 在解析过程中更改编码
        5. 13.2.3.5 预处理输入流
      4. 13.2.4 解析状态
        1. 13.2.4.1 插入模式
        2. 13.2.4.2 开放元素栈
        3. 13.2.4.3 活动格式化元素列表
        4. 13.2.4.4 元素指针
        5. 13.2.4.5 其他解析状态标志
      5. 13.2.5 标记化
        1. 13.2.5.1 数据状态
        2. 13.2.5.2 RCDATA 状态
        3. 13.2.5.3 RAWTEXT 状态
        4. 13.2.5.4 脚本数据状态
        5. 13.2.5.5 PLAINTEXT 状态
        6. 13.2.5.6 标签打开状态
        7. 13.2.5.7 结束标签打开状态
        8. 13.2.5.8 标签名状态
        9. 13.2.5.9 RCDATA 小于号状态
        10. 13.2.5.10 RCDATA 结束标签打开状态
        11. 13.2.5.11 RCDATA 结束标签名状态
        12. 13.2.5.12 RAWTEXT 小于号状态
        13. 13.2.5.13 RAWTEXT 结束标签打开状态
        14. 13.2.5.14 RAWTEXT 结束标签名状态
        15. 13.2.5.15 脚本数据小于号状态
        16. 13.2.5.16 脚本数据结束标签打开状态
        17. 13.2.5.17 脚本数据结束标签名状态
        18. 13.2.5.18 脚本数据转义开始状态
        19. 13.2.5.19 脚本数据转义开始连字符状态
        20. 13.2.5.20 脚本数据转义状态
        21. 13.2.5.21 脚本数据转义连字符状态
        22. 13.2.5.22 脚本数据转义连字符连字符状态
        23. 13.2.5.23 脚本数据转义小于号状态
        24. 13.2.5.24 脚本数据转义结束标签打开状态
        25. 13.2.5.25 脚本数据转义结束标签名状态
        26. 13.2.5.26 脚本数据双重转义开始状态
        27. 13.2.5.27 脚本数据双重转义状态
        28. 13.2.5.28 脚本数据双重转义连字符状态
        29. 13.2.5.29 脚本数据双重转义连字符连字符状态
        30. 13.2.5.30 脚本数据双重转义小于号状态
        31. 13.2.5.31 脚本数据双重转义结束状态
        32. 13.2.5.32 属性名前状态
        33. 13.2.5.33 属性名状态
        34. 13.2.5.34 属性名后状态
        35. 13.2.5.35 属性值前状态
        36. 13.2.5.36 属性值(双引号)状态
        37. 13.2.5.37 属性值(单引号)状态
        38. 13.2.5.38 属性值(无引号)状态
        39. 13.2.5.39 属性值后(引号)状态
        40. 13.2.5.40 自闭合开始标签状态
        41. 13.2.5.41 错误注释状态
        42. 13.2.5.42 标记声明打开状态
        43. 13.2.5.43 注释开始状态
        44. 13.2.5.44 注释开始连字符状态
        45. 13.2.5.45 注释状态
        46. 13.2.5.46 注释小于号状态
        47. 13.2.5.47 注释小于号感叹号状态
        48. 13.2.5.48 注释小于号感叹号连字符状态
        49. 13.2.5.49 注释小于号感叹号连字符连字符状态
        50. 13.2.5.50 注释结束连字符状态
        51. 13.2.5.51 注释结束状态
        52. 13.2.5.52 注释结束感叹号状态
        53. 13.2.5.53 DOCTYPE 状态
        54. 13.2.5.54 DOCTYPE 名前状态
        55. 13.2.5.55 DOCTYPE 名状态
        56. 13.2.5.56 DOCTYPE 名后状态
        57. 13.2.5.57 DOCTYPE 公共关键字后状态
        58. 13.2.5.58 DOCTYPE 公共标识符前状态
        59. 13.2.5.59 DOCTYPE 公共标识符(双引号)状态
        60. 13.2.5.60 DOCTYPE 公共标识符(单引号)状态
        61. 13.2.5.61 DOCTYPE 公共标识符后状态
        62. 13.2.5.62 DOCTYPE 公共标识符和系统标识符之间状态
        63. 13.2.5.63 DOCTYPE 系统关键字后状态
        64. 13.2.5.64 DOCTYPE 系统标识符前状态
        65. 13.2.5.65 DOCTYPE 系统标识符(双引号)状态
        66. 13.2.5.66 DOCTYPE 系统标识符(单引号)状态
        67. 13.2.5.67 DOCTYPE 系统标识符后状态
        68. 13.2.5.68 错误 DOCTYPE 状态
        69. 13.2.5.69 CDATA 部分状态
        70. 13.2.5.70 CDATA 部分方括号状态
        71. 13.2.5.71 CDATA 部分结束状态
        72. 13.2.5.72 字符引用状态
        73. 13.2.5.73 命名的字符引用状态
        74. 13.2.5.74 模糊的和号状态
        75. 13.2.5.75 数字字符引用状态
        76. 13.2.5.76 十六进制字符引用开始状态
        77. 13.2.5.77 十进制字符引用开始状态
        78. 13.2.5.78 十六进制字符引用状态
        79. 13.2.5.79 十进制字符引用状态
        80. 13.2.5.80 数字字符引用结束状态
      6. 13.2.6 树构建
        1. 13.2.6.1 创建和插入节点
        2. 13.2.6.2 解析仅包含文本的元素
        3. 13.2.6.3 关闭具有隐式结束标签的元素
        4. 13.2.6.4 在 HTML 内容中解析标记的规则
          1. 13.2.6.4.1 “初始”插入模式
          2. 13.2.6.4.2 “html 之前”插入模式
          3. 13.2.6.4.3 “head 之前”插入模式
          4. 13.2.6.4.4 “在 head 中”插入模式
          5. 13.2.6.4.5 “在 head noscript 中”插入模式
          6. 13.2.6.4.6 “head 之后”插入模式
          7. 13.2.6.4.7 “在 body 中”插入模式
          8. 13.2.6.4.8 “文本”插入模式
          9. 13.2.6.4.9 “在 table 中”插入模式
          10. 13.2.6.4.10 “在 table 文本中”插入模式
          11. 13.2.6.4.11 “在 caption 中”插入模式
          12. 13.2.6.4.12 “在 column group 中”插入模式
          13. 13.2.6.4.13 “在 table body 中”插入模式
          14. 13.2.6.4.14 “在 row 中”插入模式
          15. 13.2.6.4.15 “在 cell 中”插入模式
          16. 13.2.6.4.16 “在 select 中”插入模式
          17. 13.2.6.4.17 “在 select 在 table 中”插入模式
          18. 13.2.6.4.18 “在 template 中”插入模式
          19. 13.2.6.4.19 “body 之后”插入模式
          20. 13.2.6.4.20 “在 frameset 中”插入模式
          21. 13.2.6.4.21 “frameset 之后”插入模式
          22. 13.2.6.4.22 “body 之后之后”插入模式
          23. 13.2.6.4.23 “frameset 之后之后”插入模式
        5. 13.2.6.5 在外部内容中解析标记的规则
      7. 13.2.7 结束
      8. 13.2.8 推测性 HTML 解析
      9. 13.2.9 将 HTML DOM 强制转换为信息集
      10. 13.2.10 解析器中错误处理和奇特情况介绍
        1. 13.2.10.1 嵌套错误的标签:<b><i></b></i>
        2. 13.2.10.2 嵌套错误的标签:<b><p></b></p>
        3. 13.2.10.3 表格中意外的标记
        4. 13.2.10.4 在解析过程中修改页面的脚本
        5. 13.2.10.5 跨多个文档执行的脚本
        6. 13.2.10.6 未关闭的格式化元素
    2. 13.3 序列化 HTML 片段
    3. 13.4 解析 HTML 片段

13.2 解析 HTML 文档

本节仅适用于用户代理、数据挖掘工具和一致性检查器。

将 XML 文档解析为 DOM 树的规则在下一节中介绍,标题为 "XML 语法"。

用户代理必须使用本节中描述的解析规则,从 text/html 资源生成 DOM 树。这些规则共同定义了所谓的 HTML 解析器

虽然本规范中描述的 HTML 语法与 SGML 和 XML 非常相似,但它是一种具有自身解析规则的独立语言。

早期版本的 HTML(特别是从 HTML2 到 HTML4)基于 SGML 并使用 SGML 解析规则。但是,很少有(如果有的话)网络浏览器曾经为 HTML 文档实施真正的 SGML 解析;历史上,唯一严格将 HTML 作为 SGML 应用程序处理的用户代理是验证器。由此产生的混乱——验证器声称文档具有一个表示形式,而广泛部署的网络浏览器以可互操作的方式实施了不同的表示形式——浪费了数十年的生产力。因此,本版本的 HTML 回到非 SGML 基础。

鼓励有兴趣在创作流程中使用 SGML 工具的作者使用 XML 工具和 HTML 的 XML 序列化。

为了满足一致性检查器的目的,如果确定某个资源属于 HTML 语法,则它是一个 HTML 文档

术语部分所述,对 元素类型 的引用,如果未明确指定命名空间,则始终引用 HTML 命名空间 中的元素。例如,如果规范中提到“一个 menu 元素”,那么指的是具有本地名称“menu”、命名空间“http://www.w3.org/1999/xhtml”和接口 HTMLMenuElement 的元素。在可能的情况下,对这类元素的引用都超链接到其定义。

13.2.1 解析模型概述

HTML 解析过程的输入包括一个 代码点 流,该流将通过 标记化 阶段,然后是 树构建 阶段。输出是一个 Document 对象。

不支持脚本的实现不必实际创建 DOM Document 对象,但在这种情况下,DOM 树仍然用作规范中其他部分的模型。

在常见情况下,标记化阶段处理的数据来自网络,但 它也可以来自用户代理中运行的脚本,例如使用 document.write() API。

标记器阶段和树构建阶段只有一组状态,但树构建阶段是可重入的,这意味着当树构建阶段处理一个标记时,标记器可能会恢复,导致在第一个标记处理完成之前发出和处理更多标记。

在以下示例中,树构建阶段将在处理“script”结束标记时被调用来处理“p”开始标记。

...
<script>
 document.write('<p>');
</script>
...

为了处理这些情况,解析器有一个 脚本嵌套级别,它必须最初设置为零,以及一个 解析器暂停标志,它必须最初设置为 false。

13.2.2 解析错误

本规范定义了 HTML 文档的解析规则,无论它们是语法上正确还是不正确。解析算法中的某些点被称为 解析错误。解析错误的错误处理是明确定义的(即本规范中描述的处理规则),但用户代理在解析 HTML 文档时,可能会在遇到第一个 中止解析器解析错误 时中止,他们不希望应用本规范中描述的规则。

一致性检查器必须向用户报告至少一个解析错误条件,如果文档中存在一个或多个解析错误条件,并且如果文档中不存在解析错误条件,则必须不报告解析错误条件。如果文档中存在多个解析错误条件,一致性检查器可能会报告多个解析错误条件。

解析错误只是 HTML 语法 中的错误。除了检查解析错误之外,一致性检查器还将验证文档是否遵守本规范中描述的所有其他一致性要求。

一些解析错误在下面的表格中概述了专用代码,这些代码应由一致性检查器在报告中使用。

下面表格中的错误描述是非规范性的。

代码描述
abrupt-closing-of-empty-comment

如果解析器遇到一个空 注释,该注释被 U+003E (>) 代码点(即,<!--><!--->)突然关闭,则会发生此错误。解析器表现得好像注释已正确关闭。

abrupt-doctype-public-identifier

如果解析器在 DOCTYPE 公开标识符中遇到 U+003E (>) 代码点(例如,<!DOCTYPE html PUBLIC "foo>),则会发生此错误。在这种情况下,如果 DOCTYPE 被正确放置为文档前置,解析器会将 文档 设置为 怪癖模式

abrupt-doctype-system-identifier

如果解析器在 DOCTYPE 系统标识符中遇到 U+003E (>) 代码点(例如,<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "foo>),则会发生此错误。在这种情况下,如果 DOCTYPE 被正确放置为文档前置,解析器会将 文档 设置为 怪癖模式

absence-of-digits-in-numeric-character-reference

如果解析器遇到一个数字 字符引用,该引用不包含任何数字(例如,&#qux;),则会发生此错误。在这种情况下,解析器不会解析字符引用。

cdata-in-html-content

如果解析器在外部内容(SVG 或 MathML)之外遇到 CDATA 部分,则会发生此错误。解析器将这些 CDATA 部分(包括前导“[CDATA[”和尾随“]]”字符串)视为注释。

character-reference-outside-unicode-range

如果解析器遇到一个数字 字符引用,该引用引用一个大于有效 Unicode 范围的 代码点,则会发生此错误。解析器将此类字符引用解析为 U+FFFD 替换字符。

control-character-in-input-stream

如果 输入流 包含一个不是 ASCII 空格 或 U+0000 NULL 的 控制 代码点,则会发生此错误。此类代码点按原样解析,通常在解析规则不应用任何其他限制的情况下,会进入 DOM。

control-character-reference

如果解析器遇到一个数字 字符引用,该引用引用一个不是 ASCII 空格 或 U+000D 回车的 控制 代码点,则会发生此错误。解析器按原样解析这些字符引用,除了 C1 控制引用,它们将根据 数字字符引用结束状态 进行替换。

duplicate-attribute

如果解析器在标记中遇到一个 属性,该标记已经具有相同名称的属性,则会发生此错误。解析器会忽略属性的所有此类重复出现。

end-tag-with-attributes

如果解析器遇到一个带 属性结束标记,则会发生此错误。结束标记中的属性将被忽略,并且不会进入 DOM。

end-tag-with-trailing-solidus

如果解析器遇到一个 结束标记,该标记在关闭的 U+003E (>) 代码点之前有一个 U+002F (/) 代码点(例如,</div/>),则会发生此错误。此类标记被视为常规结束标记。

eof-before-tag-name

如果解析器在预期标记名称的地方遇到 输入流 的结尾,则会发生此错误。在这种情况下,解析器会将 开始标记(即,<)或 结束标记(即,</)的开头视为文本内容。

eof-in-cdata

如果解析器在 CDATA 部分 中遇到 输入流 的结尾,则会发生此错误。解析器将此类 CDATA 部分视为它们在输入流结束之前立即关闭。

eof-in-comment

如果解析器在 注释 中遇到 输入流 的结尾,则会发生此错误。解析器将此类注释视为它们在输入流结束之前立即关闭。

eof-in-doctype

如果解析器在 DOCTYPE 中遇到输入流的结尾,则会发生此错误。在这种情况下,如果 DOCTYPE 被正确放置为文档前置,解析器会将 文档 设置为 怪癖模式

eof-in-script-html-comment-like-text

如果解析器在类似于 HTML 注释 的文本中遇到 输入流 的结尾,该文本位于 script 元素内容中(例如,<script><!-- foo),则会发生此错误。

类似于 HTML 注释的语法结构在 script 元素中被解析为文本内容。它们可以是脚本语言特定语法结构的一部分,或者如果脚本语言支持它们,则被视为 HTML 类似的注释(例如,HTML 类似的注释的解析规则可以在 JavaScript 规范的附录 B 中找到)。此错误的常见原因是违反了 script 元素内容的限制[JAVASCRIPT]

eof-in-tag

如果解析器在 开始标记结束标记 中遇到 输入流 的结尾(例如,<div id=),则会发生此错误。此类标记将被忽略。

incorrectly-closed-comment

如果解析器遇到一个 注释,该注释被“--!>代码点 序列关闭,则会发生此错误。解析器将此类注释视为它们被“-->”代码点序列正确关闭。

incorrectly-opened-comment

如果解析器遇到“<!代码点 序列,该序列没有紧随其后是两个 U+002D (-) 代码点,并且不是 DOCTYPECDATA 部分 的开头,则会发生此错误。在“<!”代码点序列之后的直到 U+003E (>) 代码点(如果存在)或直到 输入流 结尾的所有内容都被视为注释。

此错误的一个可能原因是在 HTML 中使用 XML 标记声明(例如,<!ELEMENT br EMPTY>)。

invalid-character-sequence-after-doctype-name

如果解析器在 DOCTYPE 名称之后遇到任何不是“PUBLIC”和“SYSTEM”关键字的 代码点 序列,则会发生此错误。在这种情况下,解析器会忽略任何后续的公开或系统标识符,如果 DOCTYPE 被正确放置为文档前置,并且如果 解析器不能更改模式标志 为 false,则会将 文档 设置为 怪癖模式

invalid-first-character-of-tag-name

如果解析器在预期 开始标记 名称或 结束标记 名称的第一个代码点的地方遇到一个不是 ASCII 字母代码点,则会发生此错误。如果预期开始标记,则此类代码点和前面的 U+003C (<) 被视为文本内容,并且所有后续内容被视为标记。而如果预期结束标记,则此类代码点和所有后续内容(直到 U+003E (>) 代码点(如果存在)或直到 输入流 的结尾)都被视为注释。

例如,考虑以下标记

<42></42>

这将被解析为

虽然标签名称的第一个代码点限制为 ASCII 字母,但后续位置允许使用广泛的代码点(包括 ASCII 数字)。

missing-attribute-value

如果解析器在预期属性值的地方遇到 U+003E (>) 代码点(例如,<div id=>),则会发生此错误。解析器将该属性视为具有空值。

missing-doctype-name

如果解析器遇到缺少名称的 DOCTYPE(例如,<!DOCTYPE>),则会发生此错误。在这种情况下,如果 DOCTYPE 正确地放置为文档序言,解析器会将 Document 设置为 怪癖模式

missing-doctype-public-identifier

如果解析器在预期 DOCTYPE 公共标识符的开头处遇到 U+003E (>) 代码点(例如,<!DOCTYPE html PUBLIC >),则会发生此错误。在这种情况下,如果 DOCTYPE 正确地放置为文档序言,解析器会将 Document 设置为 怪癖模式

missing-doctype-system-identifier

如果解析器在预期 DOCTYPE 系统标识符的开头处遇到 U+003E (>) 代码点(例如,<!DOCTYPE html SYSTEM >),则会发生此错误。在这种情况下,如果 DOCTYPE 正确地放置为文档序言,解析器会将 Document 设置为 怪癖模式

missing-end-tag-name

如果解析器在预期结束标签名称的地方遇到 U+003E (>) 代码点,即 </>,则会发生此错误。解析器会忽略整个“</>”代码点序列。

missing-quote-before-doctype-public-identifier

如果解析器遇到没有被引号引起来的 DOCTYPE 公共标识符(例如,<!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01//EN">),则会发生此错误。在这种情况下,解析器会忽略公共标识符,并且如果 DOCTYPE 正确地放置为文档序言,会将 Document 设置为 怪癖模式

missing-quote-before-doctype-system-identifier

如果解析器遇到没有被引号引起来的 DOCTYPE 系统标识符(例如,<!DOCTYPE html SYSTEM http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">),则会发生此错误。在这种情况下,解析器会忽略系统标识符,并且如果 DOCTYPE 正确地放置为文档序言,会将 Document 设置为 怪癖模式

missing-semicolon-after-character-reference

如果解析器遇到没有以 U+003B (;) 代码点 结束的 字符引用,则会发生此错误。通常,解析器会像字符引用以 U+003B (;) 代码点结束一样进行处理;但是,在某些情况下,解析器会将后续代码点包含在字符引用中。

例如,&not;in 将被解析为“¬in”,而 &notin 将被解析为“”。

missing-whitespace-after-doctype-public-keyword

如果解析器遇到 DOCTYPE,其“PUBLIC”关键字和公共标识符没有以 ASCII 空格 分隔,则会发生此错误。在这种情况下,解析器会像存在 ASCII 空格一样进行处理。

missing-whitespace-after-doctype-system-keyword

如果解析器遇到 DOCTYPE,其“SYSTEM”关键字和系统标识符没有以 ASCII 空格 分隔,则会发生此错误。在这种情况下,解析器会像存在 ASCII 空格一样进行处理。

missing-whitespace-before-doctype-name

如果解析器遇到 DOCTYPE,其“DOCTYPE”关键字和名称没有以 ASCII 空格 分隔,则会发生此错误。在这种情况下,解析器会像存在 ASCII 空格一样进行处理。

missing-whitespace-between-attributes

如果解析器遇到没有以 ASCII 空格 分隔的 属性(例如,<div id="foo"class="bar">),则会发生此错误。在这种情况下,解析器会像存在 ASCII 空格一样进行处理。

missing-whitespace-between-doctype-public-and-system-identifiers

如果解析器遇到 DOCTYPE,其公共标识符和系统标识符没有以 ASCII 空格 分隔,则会发生此错误。在这种情况下,解析器会像存在 ASCII 空格一样进行处理。

nested-comment

如果解析器遇到嵌套的 注释(例如,<!-- <!-- nested --> -->),则会发生此错误。这样的注释将由第一个出现的“-->代码点 序列关闭,后面的一切都将被视为标记。

noncharacter-character-reference

如果解析器遇到引用 非字符 的数字 字符引用,则会发生此错误。解析器会按原样解析这些字符引用。

noncharacter-in-input-stream

如果 输入流 包含 非字符,则会发生此错误。这些 代码点 会被按原样解析,通常,在解析规则没有应用任何其他限制的情况下,会进入 DOM。

non-void-html-element-start-tag-with-trailing-solidus

如果解析器遇到不是 空元素 列表中的元素或不是外国内容(即不是 SVG 或 MathML 元素)的开始标签,该标签在闭合 U+003E (>) 代码点之前有一个 U+002F (/) 代码点,则会发生此错误。解析器会像 U+002F (/) 不存在一样进行处理。

例如,考虑以下标记

<div/><span></span><span></span>

这将被解析为

开始标签名称中尾部的 U+002F (/) 只能在外国内容中用于指定自闭合标签。(自闭合标签在 HTML 中不存在。)对于空元素也允许使用它,但在这种情况下没有任何影响。

null-character-reference

如果解析器遇到引用 U+0000 NULL 代码点 的数字 字符引用,则会发生此错误。解析器会将这些字符引用解析为 U+FFFD 替换字符。

surrogate-character-reference

如果解析器遇到引用 代理 的数字 字符引用,则会发生此错误。解析器会将这些字符引用解析为 U+FFFD 替换字符。

surrogate-in-input-stream

如果 输入流 包含 代理,则会发生此错误。这些 代码点 会被按原样解析,通常,在解析规则没有应用任何其他限制的情况下,会进入 DOM。

代理只能通过脚本 API(如 document.write())进入输入流。

unexpected-character-after-doctype-system-identifier

如果解析器遇到除 ASCII 空格 或闭合 U+003E (>) 之外的任何 代码点,这些代码点位于 DOCTYPE 系统标识符之后,则会发生此错误。解析器会忽略这些代码点。

unexpected-character-in-attribute-name

如果解析器在 属性名称 中遇到 U+0022 (")、U+0027 (') 或 U+003C (<) 代码点,则会发生此错误。解析器会将这些代码点包含在属性名称中。

触发此错误的代码点通常是另一个语法结构的一部分,并且可能是属性名称周围出现错误的标志。

例如,考虑以下标记

<div foo<div>

由于在 foo 之后忘记了 U+003E (>) 代码点,解析器将此标记视为一个具有“foo<div”属性的单个 div 元素。

作为此错误的另一个示例,请考虑以下标记

<div id'bar'>

由于在属性名称和值之间忘记了 U+003D (=) 代码点,解析器将此标记视为一个具有“id'bar'”属性的 div 元素,该属性具有空值。

unexpected-character-in-unquoted-attribute-value

如果解析器在没有引号引起来的 属性值 中遇到 U+0022 (")、U+0027 (')、U+003C (<)、U+003D (=) 或 U+0060 (`) 代码点,则会发生此错误。解析器会将这些代码点包含在属性值中。

触发此错误的代码点通常是另一个语法结构的一部分,并且可能是属性值周围出现错误的标志。

U+0060 (`) 位于触发此错误的代码点列表中,因为某些旧版用户代理将其视为引号。

例如,考虑以下标记

<div foo=b'ar'>

由于 U+0027 (') 代码点放置错误,解析器将“foo”属性的值设置为“b'ar'”。

unexpected-equals-sign-before-attribute-name

如果解析器在属性名称之前遇到 U+003D (=) 代码点,则会发生此错误。在这种情况下,解析器会将 U+003D (=) 视为属性名称的第一个代码点。

此错误的常见原因是忘记了属性名称。

例如,考虑以下标记

<div foo="bar" ="baz">

由于忘记了属性名称,解析器将此标记视为一个具有两个属性的 div 元素:一个具有“bar”值的“foo”属性和一个具有空值的“="baz"”属性。

unexpected-null-character

如果解析器在某些位置的 输入流 中遇到 U+0000 NULL 代码点,则会发生此错误。一般情况下,这些代码点会被忽略,或者出于安全原因,会被替换为 U+FFFD 替换字符。

unexpected-question-mark-instead-of-tag-name

如果解析器遇到 U+003F (?) 代码点,而此处应为开始标签名称的第一个代码点,则会发生此错误。U+003F (?) 及其后的所有内容,直至遇到 U+003E (>) 代码点(如果存在)或输入流结束,都会被视为注释。

例如,考虑以下标记

<?xml-stylesheet type="text/css" href="style.css"?>

这将被解析为

此错误的常见原因是,在 HTML 中使用了 XML 处理指令(例如,<?xml-stylesheet type="text/css" href="style.css"?>)或 XML 声明(例如,<?xml version="1.0" encoding="UTF-8"?>)。

unexpected-solidus-in-tag

如果解析器遇到 U+002F (/) 代码点,而该代码点既不属于引用的 属性 值,也不紧跟在标签中的 U+003E (>) 代码点之后(例如,<div / id="foo">),则会发生此错误。在这种情况下,解析器将表现得好像遇到 ASCII 空格

unknown-named-character-reference

如果解析器遇到 歧义的与号,则会发生此错误。在这种情况下,解析器不会解析 字符引用

13.2.3 输入字节流

构成标记化阶段输入的代码点流,最初会被用户代理视为字节流(通常来自网络或本地文件系统)。字节根据特定的字符编码对实际字符进行编码,用户代理使用该编码将字节解码为字符。

对于 XML 文档,用户代理必须使用 XML 中给出的算法来确定字符编码。本节不适用于 XML 文档。 [XML]

通常,使用下面定义的 编码嗅探算法 来确定字符编码。

给定字符编码,必须将 输入字节流 中的字节转换为标记器的 输入流 中的字符,方法是将 输入字节流 和字符编码传递给 decode

前导字节顺序标记 (BOM) 会导致忽略字符编码参数,并且它本身也会被跳过。

原始字节流中不符合编码标准的字节或字节序列(例如,UTF-8 输入字节流中的无效 UTF-8 字节序列)是符合性检查器应报告的错误。 [ENCODING]

解码器算法描述了如何处理无效输入;出于安全原因,务必严格遵循这些规则。处理无效字节序列方式的差异会导致脚本注入漏洞(“XSS”)等问题。

当 HTML 解析器解码输入字节流时,它会使用字符编码和 置信度。置信度可以是初步确定无关紧要。使用的编码以及对该编码的置信度是初步还是确定,将 在解析期间使用 来确定是否要 更改编码。如果不需要编码(例如,因为解析器正在操作 Unicode 流,并且根本不需要使用字符编码),那么 置信度无关紧要

一些算法通过直接将字符添加到 输入流 来为解析器提供数据,而不是将字节添加到 输入字节流

13.2.3.1 使用已知字符编码进行解析

当 HTML 解析器要操作具有 已知确定编码 的输入字节流时,字符编码即为该编码,而 置信度确定

13.2.3.2 确定字符编码

在某些情况下,在解析文档之前明确确定编码可能不切实际。因此,本规范提供了一种包含可选预扫描的双遍机制。如下所述,实现允许在开始解析文档之前,对可用的字节应用简化的解析算法。然后,使用从该预解析和其他带外元数据得出的初步编码,启动真正的解析器。如果在加载文档时,用户代理发现与该信息冲突的字符编码声明,那么解析器可以重新调用以使用真正的编码执行文档解析。

用户代理必须使用以下算法(称为 编码嗅探算法)来确定解码文档时在第一遍中要使用的字符编码。该算法将用户代理可用的任何带外元数据(例如,文档的 Content-Type 元数据)和到目前为止可用的所有字节作为输入,并返回字符编码和一个 置信度,该置信度可以是初步确定

  1. 如果 BOM 嗅探 的结果是编码,则返回该编码,其 置信度确定

    虽然 decode 算法本身会根据字节顺序标记的存在来更改要使用的编码,但该算法还会嗅探 BOM 以设置正确的 文档的字符编码置信度

  2. 如果用户已明确指示用户代理使用特定编码覆盖文档的字符编码,则可以选择返回该编码,其 置信度确定

    通常,用户代理会在各个会话之间记住此类用户请求,并在某些情况下将其应用于 iframe 中的文档。

  3. 用户代理可以等待资源的更多字节变得可用,无论是在此步骤还是在该算法中的任何后续步骤。例如,用户代理可以等待 500 毫秒或 1024 字节,以先到者为准。通常,预解析源代码以查找编码可以提高性能,因为它减少了在找到编码信息时丢弃解析时使用的數據结构的需要。但是,如果用户代理延迟过久以获取数据来确定编码,那么延迟成本可能会超过预解析带来的任何性能改进。

    字符编码声明的作者符合性要求将其限制为仅出现在 前 1024 个字节中。因此,鼓励用户代理对前 1024 个字节使用下面的预扫描算法(如这些步骤调用),但不要超过该限制。

  4. 如果传输层指定字符编码,并且该编码受支持,则返回该编码,其 置信度确定

  5. 可选地 预扫描字节流以确定其编码,其结束条件 是用户代理决定扫描更多字节将效率低下时。鼓励用户代理仅预扫描前 1024 个字节。用户代理可以决定扫描任何字节都效率低下,在这种情况下,这些子步骤将完全跳过。

    上述算法将返回字符编码或失败。如果它返回字符编码,那么返回相同的编码,其 置信度初步

  6. 如果正在运行此算法的 HTML 解析器Document d 相关联,而该文档的 容器文档 不为空,那么

    1. parentDocument 设置为 d容器文档

    2. 如果 parentDocument来源d来源 相同,并且 parentDocument字符编码 不是 UTF-16BE/LE,那么返回 parentDocument字符编码,其 置信度初步

  7. 否则,如果用户代理有关于该页面可能编码的信息(例如,基于上次访问该页面时的编码),那么返回该编码,其 置信度初步

  8. 用户代理可以尝试通过对数据流应用频率分析或其他算法来自动检测字符编码。此类算法可以使用关于资源的信息,而不是资源的内容,包括资源的地址。如果自动检测成功确定字符编码,并且该编码是受支持的编码,那么返回该编码,其 置信度初步[UNIVCHARDET]

    通常不鼓励用户代理尝试自动检测通过网络获取的资源的编码,因为这样做涉及本质上不可互操作的启发式方法。尝试根据 HTML 文档的序言检测编码尤其棘手,因为 HTML 标记通常仅使用 ASCII 字符,并且 HTML 文档往往以大量标记而不是文本内容开头。

    UTF-8 编码具有高度可检测的位模式。来自本地文件系统的文件,如果包含大于 0x7F 的字节且与 UTF-8 模式匹配,则很可能为 UTF-8,而字节序列不匹配的文档很可能不是。当用户代理可以检查整个文件,而不是仅仅检查前导字节时,专门检测 UTF-8 会特别有效。 [PPUTF8] [UTF8DET]

  9. 否则,返回一个 实现定义的 或用户指定的默认字符编码,并将其 置信度 设置为 暂定

    在受控环境或文档编码可以预定义的环境中(例如,专用于新网络的专用用户代理),建议使用全面的 UTF-8 编码。

    在其他环境中,默认编码通常取决于用户的区域设置(用户可能经常访问的页面语言,以及由此产生的编码的近似值)。下表根据用户的区域设置提供了建议的默认值,以确保与传统内容的兼容性。区域设置由 BCP 47 语言标签标识。 [BCP47] [ENCODING]

    区域设置语言建议的默认编码
    ar阿拉伯语windows-1256
    az阿塞拜疆语windows-1254
    ba巴什基尔语windows-1251
    be白俄罗斯语windows-1251
    bg保加利亚语windows-1251
    cs捷克语windows-1250
    el希腊语ISO-8859-7
    et爱沙尼亚语windows-1257
    fa波斯语windows-1256
    he希伯来语windows-1255
    hr克罗地亚语windows-1250
    hu匈牙利语ISO-8859-2
    ja日语Shift_JIS
    kk哈萨克语windows-1251
    ko韩语EUC-KR
    ku库尔德语windows-1254
    ky吉尔吉斯语windows-1251
    lt立陶宛语windows-1257
    lv拉脱维亚语windows-1257
    mk马其顿语windows-1251
    pl波兰语ISO-8859-2
    ru俄语windows-1251
    sah雅库特语windows-1251
    sk斯洛伐克语windows-1250
    sl斯洛文尼亚语ISO-8859-2
    sr塞尔维亚语windows-1251
    tg塔吉克语windows-1251
    th泰语windows-874
    tr土耳其语windows-1254
    tt鞑靼语windows-1251
    uk乌克兰语windows-1251
    vi越南语windows-1258
    zh-Hans, zh-CN, zh-SG简体中文GBK
    zh-Hant, zh-HK, zh-MO, zh-TW繁体中文Big5
    所有其他区域设置windows-1252

    该表的内容源于 Windows、Chrome 和 Firefox 默认值的交集。

用户代理必须立即将 文档的字符编码 设置为该算法返回的值,同时使用返回值选择用于输入字节流的解码器。


当算法要求用户代理 预扫描字节流以确定其编码 时,给定一些定义的 结束条件,则必须运行以下步骤。如果在这些步骤中的任何时刻(包括在此步骤调用的 获取属性 算法的实例期间),用户代理要么耗尽字节(意味着在第一步中创建的 位置 指针超出了迄今为止获得的字节流的末尾),要么达到了其 结束条件,则中止 预扫描字节流以确定其编码 算法并返回结果 获取应用于相同字节的 XML 编码,这些字节是 预扫描字节流以确定其编码 算法应用到的字节。否则,这些步骤将返回一个字符编码。

  1. 回退编码 为 null。

  2. 位置 为指向输入字节流中一个字节的指针,最初指向第一个字节。

  3. 预扫描 UTF-16 XML 声明:如果 位置 指向:

    以以下字节序列开头的序列:0x3C, 0x0, 0x3F, 0x0, 0x78, 0x0(区分大小写的 UTF-16 小端“<?x”)

    返回 UTF-16LE

    以以下字节序列开头的序列:0x0, 0x3C, 0x0, 0x3F, 0x0, 0x78(区分大小写的 UTF-16 大端“<?x”)

    返回 UTF-16BE

    出于历史原因,前缀比 XML 中的 附录 F 长两个字节,并且不检查编码名称。

  4. 循环:如果 位置 指向:

    以以下字节序列开头的序列:0x3C 0x21 0x2D 0x2D(`<!--`)

    位置 指针向前移动,使其指向紧接在找到的 0x3C 字节之后、且前面有两个 0x2D 字节(即 ASCII“-->”序列的末尾)的第一个 0x3E 字节。(两个 0x2D 字节可以与“<!--”序列中的字节相同。)

    以以下字节序列开头的序列:0x3C, 0x4D 或 0x6D, 0x45 或 0x65, 0x54 或 0x74, 0x41 或 0x61,以及 0x09、0x0A、0x0C、0x0D、0x20、0x2F 之一(不区分大小写的 ASCII“<meta”后跟空格或斜杠)
    1. 位置 指针向前移动,使其指向下一个 0x09、0x0A、0x0C、0x0D、0x20 或 0x2F 字节(上述字符序列中的字节)。

    2. 属性列表 为一个空的字符串列表。

    3. 已获取 pragma 为 false。

    4. 需要 pragma 为 null。

    5. 字符集 为 null 值(出于此算法的目的,它与无法识别的编码或空字符串不同)。

    6. 属性获取属性 及其值。如果没有嗅探到属性,则跳到下面的 处理 步骤。

    7. 如果属性名称已存在于 属性列表 中,则返回到标记为 属性 的步骤。

    8. 将属性名称添加到 属性列表 中。

    9. 如果适用,则从以下列表中运行适当的步骤。

      如果属性名称为“http-equiv

      如果属性值为“content-type”,则将 已获取 pragma 设置为 true。

      如果属性名称为“content

      应用 meta 元素中提取字符编码的算法,将属性值作为要解析的字符串提供。如果返回了字符编码,且 字符集 仍然设置为 null,则令 字符集 为返回的编码,并将 需要 pragma 设置为 true。

      如果属性名称为“charset

      字符集 为从属性值 获取编码 的结果,并将 需要 pragma 设置为 false。

    10. 返回到标记为 属性 的步骤。

    11. 处理:如果 需要 pragma 为 null,则跳到下面标记为 下一个字节 的步骤。

    12. 如果 需要 pragma 为 true 但 已获取 pragma 为 false,则跳到下面标记为 下一个字节 的步骤。

    13. 如果 字符集 为失败,则跳到下面标记为 下一个字节 的步骤。

    14. 如果 字符集UTF-16BE/LE,则将 字符集 设置为 UTF-8

    15. 如果 字符集x-user-defined,则将 字符集 设置为 windows-1252

    16. 返回 字符集

    以以下字节序列开头的序列:一个 0x3C 字节(<),可选地一个 0x2F 字节(/),最后是一个在 0x41-0x5A 或 0x61-0x7A 范围内的字节(A-Z 或 a-z)
    1. 位置 指针向前移动,使其指向下一个 0x09 (HT)、0x0A (LF)、0x0C (FF)、0x0D (CR)、0x20 (SP) 或 0x3E (>) 字节。

    2. 重复 获取属性,直到无法找到更多属性,然后跳到下面标记为 下一个字节 的步骤。

    以以下字节序列开头的序列:0x3C 0x21(`<!`)
    以以下字节序列开头的序列:0x3C 0x2F(`</`)
    以以下字节序列开头的序列:0x3C 0x3F(`<?`)

    位置 指针向前移动,使其指向紧接在找到的 0x3C 字节之后、第一个 0x3E 字节 (>)。

    任何其他字节

    对该字节不做任何操作。

  5. 下一个字节:移动 位置,使其指向输入字节流中的下一个字节,然后返回到上面标记为 循环 的步骤。

预扫描字节流以确定其编码 算法指示 获取属性 时,这意味着执行以下操作。

  1. 如果 位置 处的字节是 0x09 (HT)、0x0A (LF)、0x0C (FF)、0x0D (CR)、0x20 (SP) 或 0x2F (/) 之一,则将 位置 向前移动到下一个字节,并重新执行此步骤。

  2. 如果 位置 处的字节是 0x3E (>),则中止 获取属性 算法。没有属性。

  3. 否则,位置 处的字节是属性名称的开头。令 属性名称属性值 为空字符串。

  4. 位置 处的字节进行以下处理。

    如果它是 0x3D (=),并且 属性名称 长度大于空字符串
    位置 向前移动到下一个字节,并跳到下面标记为 的步骤。
    如果它是 0x09 (HT)、0x0A (LF)、0x0C (FF)、0x0D (CR) 或 0x20 (SP)
    跳到下面标记为 空格 的步骤。
    如果它是 0x2F (/) 或 0x3E (>)
    中止 获取属性 算法。属性名称的值是 属性名称 的值,属性值是空字符串。
    如果它在 0x41 (A) 到 0x5A (Z) 范围内
    将代码点 b+0x20 追加到 属性名称 中(其中 b位置 处字节的值)。(这将输入转换为小写。)
    任何其他情况
    将与 位置 处字节值相同的代码点追加到 属性名称 中。(实际上,这里如何处理 ASCII 范围之外的字节并不重要,因为只有 ASCII 字节才能参与字符编码的检测。)
  5. 位置 向前移动到下一个字节,并返回到上一步。

  6. 空格:如果 位置 处的字节是 0x09 (HT)、0x0A (LF)、0x0C (FF)、0x0D (CR) 或 0x20 (SP) 之一,则将 位置 向前移动到下一个字节,然后重复此步骤。

  7. 如果在位置 position 处的字节为 0x3D (=),则中止获取属性算法。属性的名称为 attribute name 的值,其值为空字符串。

  8. position 递进到 0x3D (=) 字节之后。

  9. : 如果在 position 处的字节为 0x09 (HT),0x0A (LF),0x0C (FF),0x0D (CR) 或 0x20 (SP) 之一,则将 position 递进到下一个字节,然后重复此步骤。

  10. 位置 处的字节进行以下处理。

    如果它为 0x22 (") 或 0x27 (')
    1. b 为在 position 处的字节的值。
    2. 引号循环: 将 position 递进到下一个字节。
    3. 如果在 position 处的字节的值为 b 的值,则将 position 递进到下一个字节并中止“获取属性”算法。属性的名称为 attribute name 的值,其值为 attribute value 的值。
    4. 否则,如果在 position 处的字节的值在 0x41 (A) 到 0x5A (Z) 的范围内,则将一个代码点附加到 attribute value,其值为在 position 处的字节的值加 0x20。
    5. 否则,将一个代码点附加到 attribute value,其值与在 position 处的字节的值相同。
    6. 返回到上面标记为引号循环的步骤。
    如果它为 0x3E (>)
    中止获取属性算法。属性的名称为 attribute name 的值,其值为空字符串。
    如果它在 0x41 (A) 到 0x5A (Z) 范围内
    将代码点 b+0x20 附加到 attribute value(其中 b 为在 position 处的字节的值)。将 position 递进到下一个字节。
    任何其他情况
    将一个与在 position 处的字节的值相同的代码点附加到 attribute value。将 position 递进到下一个字节。
  11. 位置 处的字节进行以下处理。

    如果它为 0x09 (HT),0x0A (LF),0x0C (FF),0x0D (CR),0x20 (SP) 或 0x3E (>)
    中止获取属性算法。属性的名称为 attribute name 的值,其值为 attribute value 的值。
    如果它在 0x41 (A) 到 0x5A (Z) 范围内
    将代码点 b+0x20 附加到 attribute value(其中 b 为在 position 处的字节的值)。
    任何其他情况
    将一个与在 position 处的字节的值相同的代码点附加到 attribute value
  12. 位置 向前移动到下一个字节,并返回到上一步。

预扫描字节流以确定其编码算法中止而没有返回编码时,获取 XML 编码意味着执行此操作。

即使在text/html中,也需要查找类似于 XML 声明的语法,以确保与现有内容的兼容性。

  1. encodingPosition 为指向流开头的指针。

  2. 如果 encodingPosition 不指向字节序列 0x3C,0x3F,0x78,0x6D,0x6C (`<?xml`) 的开头,则返回失败。

  3. xmlDeclarationEnd 为指向输入字节流中下一个为 0x3E (>) 的字节的指针。如果没有这样的字节,则返回失败。

  4. encodingPosition 设置为在当前 encodingPosition 处或之后出现的字节子序列 0x65,0x6E,0x63,0x6F,0x64,0x69,0x6E,0x67 (`encoding`) 的第一个位置。如果没有这样的序列,则返回失败。

  5. encodingPosition 递进到 0x67 (g) 字节之后。

  6. 当在 encodingPosition 处的字节小于或等于 0x20(即,它是 ASCII 空格或控制字符)时,将 encodingPosition 递进到下一个字节。

  7. 如果在 encodingPosition 处的字节不为 0x3D (=),则返回失败。

  8. encodingPosition 递进到下一个字节。

  9. 当在 encodingPosition 处的字节小于或等于 0x20(即,它是 ASCII 空格或控制字符)时,将 encodingPosition 递进到下一个字节。

  10. quoteMark 为在 encodingPosition 处的字节。

  11. 如果 quoteMark 不为 0x22 (") 或 0x27 (') 之一,则返回失败。

  12. encodingPosition 递进到下一个字节。

  13. encodingEndPosition 为在 encodingPosition 处或之后出现的下一个 quoteMark 的位置。如果 quoteMark 没有再次出现,则返回失败。

  14. potentialEncoding 为在 encodingPosition(包含)和 encodingEndPosition(不包含)之间的字节序列。

  15. 如果 potentialEncoding 包含一个或多个字节值小于或等于 0x20 的字节,则返回失败。

  16. encoding获取编码给定 potentialEncoding 同构解码的结果。

  17. 如果 encodingUTF-16BE/LE,则将其更改为UTF-8

  18. 返回 encoding

为了互操作性,用户代理不应该使用与上面描述的算法返回不同结果的预扫描算法。(但是,如果你确实使用了,请至少让我们知道,这样我们就可以改进这个算法,让每个人都受益......)

13.2.3.3 字符编码

用户代理必须支持在编码中定义的编码,包括但不限于,UTF-8ISO-8859-2ISO-8859-7ISO-8859-8windows-874windows-1250windows-1251windows-1252windows-1254windows-1255windows-1256windows-1257windows-1258GBKBig5ISO-2022-JPShift_JISEUC-KRUTF-16BEUTF-16LEUTF-16BE/LEx-user-defined。用户代理不得支持其他编码。

以上禁止支持例如 CESU-8,UTF-7,BOCU-1,SCSU,EBCDIC 和 UTF-32。本规范没有尝试在其算法中支持禁止的编码;因此,支持和使用禁止的编码会导致意外行为。[CESU8] [UTF7] [BOCU1] [SCSU]

13.2.3.4 解析时更改编码

当解析器要求用户代理更改编码时,它必须执行以下步骤。如果上面描述的编码嗅探算法无法找到字符编码,或者如果它找到了与文件实际编码不匹配的字符编码,则可能会发生这种情况。

  1. 如果用于解释输入流的编码为UTF-16BE/LE,则将置信度设置为确定并返回。新的编码将被忽略;如果它不是相同的编码,那么它显然是错误的。

  2. 如果新的编码为UTF-16BE/LE,则将其更改为UTF-8

  3. 如果新的编码为x-user-defined,则将其更改为windows-1252

  4. 如果新的编码与用于解释输入流的编码相同或等效,则将置信度设置为确定并返回。当文件中找到的编码信息与编码嗅探算法确定的编码相匹配时,以及在解析器第二次遍历时,如果第一次遍历发现前面部分中描述的编码嗅探算法未能找到正确的编码时,就会发生这种情况。

  5. 如果当前解码器转换的最后一个字节之前的所有字节在当前编码和新编码中都具有相同的 Unicode 解释,并且如果用户代理支持在运行时更改转换器,那么用户代理可以在运行时更改为新编码的转换器。将文档的字符编码和用于转换输入流的编码设置为新的编码,将置信度设置为确定,并返回。

  6. 否则,重新启动导航算法,并将historyHandling 设置为 "replace",其他输入保持不变,但这次跳过编码嗅探算法,而是直接将编码设置为新编码,并将置信度设置为确定。只要有可能,应该在不实际联系网络层的情况下完成此操作(字节应该从内存中重新解析),即使例如,文档被标记为不可缓存。如果这不可能,并且联系网络层将涉及重复使用非“GET”方法的请求,那么改为将置信度设置为确定,并忽略新编码。资源将被错误地解释。用户代理可能会通知用户这种情况,以帮助应用程序开发。

此算法仅在 meta 元素上发现新的编码声明时被调用。

13.2.3.5 预处理输入流

输入流 由当输入字节流被解码或来自直接操作输入流的各种 API 时推送到其中的字符组成。

输入流中出现的任何 代理项 都是 输入流中的代理项 解析错误。输入流中出现的任何 非字符 都是 输入流中的非字符 解析错误,并且输入流中出现的任何 控制字符(除了 ASCII 空格 和 U+0000 NULL 字符)都是 输入流中的控制字符 解析错误

对 U+0000 NULL 字符的处理方式取决于字符所在的位置,并会在解析的后期阶段进行。它们要么被忽略,要么出于安全原因被替换为 U+FFFD REPLACEMENT CHARACTER。这种处理方式必然需要跨越标记化阶段和树构建阶段。

标记化 阶段之前,必须通过 规范化换行符 对输入流进行预处理。因此,HTML DOM 中的换行符由 U+000A LF 字符表示,输入到 标记化 阶段的输入流中永远不会出现 U+000D CR 字符。

下一个输入字符输入流 中第一个尚未被 消耗 或被本节要求显式忽略的字符。最初,下一个输入字符 是输入流中的第一个字符。 当前输入字符 是最后被消耗的字符。

插入点 是一个位置(紧接字符之前或紧接输入流末尾之前),使用 document.write() 插入的内容将实际插入到该位置。插入点相对于紧接其后的字符的位置,而不是输入流中的绝对偏移量。最初,插入点是未定义的。

下表中的 "EOF" 字符是一个概念字符,表示 输入流 的结尾。如果解析器是 脚本创建的解析器,则当 显式 "EOF" 字符(由 document.close() 方法插入)被消耗时,就会到达 输入流 的结尾。否则,"EOF" 字符不是流中的真实字符,而是表示没有更多字符。

13.2.4 解析状态

13.2.4.1 插入模式

插入模式 是一个状态变量,用于控制树构建阶段的主要操作。

最初,插入模式 为 "initial"。它可以更改为 "before html"、"before head"、"in head"、"in head noscript"、"after head"、"in body"、"text"、"in table"、"in table text"、"in caption"、"in column group"、"in table body"、"in row"、"in cell"、"in select"、"in select in table"、"in template"、"after body"、"in frameset"、"after frameset"、"after after body" 和 "after after frameset",这些模式在解析过程中会发生变化,如 树构建 阶段所述。插入模式会影响标记的处理方式以及是否支持 CDATA 部分。

其中几种模式,即 "in head"、"in body"、"in table" 和 "in select",比较特殊,因为其他模式会在不同时间委托给它们。当以下算法提到用户代理需要“使用 m 插入模式的规则”时,其中 m 是上述模式之一,用户代理必须使用在 m 插入模式 的部分中描述的规则,但除非 m 本身将 插入模式 切换到新的值,否则必须保持 插入模式 不变。

当插入模式切换到 "text" 或 "in table text" 时,还会设置 原始插入模式。这是树构建阶段将返回的插入模式。

类似地,为了解析嵌套的 template 元素,会使用一个 模板插入模式堆栈。它最初为空。 当前模板插入模式 是最近添加到 模板插入模式堆栈 的插入模式。以下部分中的算法会插入模式推入此堆栈,这意味着将指定的插入模式添加到堆栈中,并会弹出堆栈中的插入模式,这意味着必须从堆栈中删除最近添加的插入模式。


当以下步骤要求 UA 适当地重置插入模式 时,这意味着 UA 必须遵循以下步骤

  1. last 设置为 false。

  2. node 设置为 打开元素堆栈 中的最后一个节点。

  3. 循环:如果 node 是打开元素堆栈中的第一个节点,则将 last 设置为 true,并且如果解析器是在 HTML 片段解析算法片段情况)中创建的,则将 node 设置为传递给该算法的 上下文 元素。

  4. 如果 node 是一个 select 元素,请运行以下子步骤

    1. 如果 last 为 true,请跳转到下面标记为done的步骤。

    2. ancestor 设置为 node

    3. 循环:如果 ancestor 是打开元素堆栈中的第一个节点,请跳转到下面标记为done的步骤。

    4. ancestor 设置为打开元素堆栈中 ancestor 之前的节点。

    5. 如果 ancestor 是一个 template 节点,请跳转到下面标记为done的步骤。

    6. 如果 ancestor 是一个 table 节点,请将 插入模式 切换到 "in select in table" 并返回。

    7. 跳转回标记为loop的步骤。

    8. Done:将 插入模式 切换到 "in select" 并返回。

  5. 如果 node 是一个 tdth 元素,并且 last 为 false,则将 插入模式 切换到 "in cell" 并返回。

  6. 如果 node 是一个 tr 元素,则将 插入模式 切换到 "in row" 并返回。

  7. 如果 node 是一个 tbodytheadtfoot 元素,则将 插入模式 切换到 "in table body" 并返回。

  8. 如果 node 是一个 caption 元素,则将 插入模式 切换到 "in caption" 并返回。

  9. 如果 node 是一个 colgroup 元素,则将 插入模式 切换到 "in column group" 并返回。

  10. 如果 node 是一个 table 元素,则将 插入模式 切换到 "in table" 并返回。

  11. 如果 node 是一个 template 元素,则将 插入模式 切换到 当前模板插入模式 并返回。

  12. 如果 node 是一个 head 元素,并且 last 为 false,则将 插入模式 切换到 "in head" 并返回。

  13. 如果 node 是一个 body 元素,则将 插入模式 切换到 "in body" 并返回。

  14. 如果 node 是一个 frameset 元素,则将 插入模式 切换到 "in frameset" 并返回。(片段情况)

  15. 如果 node 是一个 html 元素,则运行以下子步骤

    1. 如果 head 元素指针 为 null,则将 插入模式 切换到 "before head" 并返回。(片段情况)

    2. 否则,head 元素指针 不为 null,将 插入模式 切换到 "after head" 并返回。

  16. 如果 last 为 true,则将 插入模式 切换到 "in body" 并返回。(片段情况)

  17. 现在让 node 成为 node打开元素栈 中的前一个节点。

  18. 返回到标记为 loop 的步骤。

13.2.4.2 打开元素栈

最初,打开元素栈 是空的。栈向下增长;栈顶部的节点是最先添加到栈的节点,栈底部的节点是最近添加到栈的节点(尽管当栈在随机访问方式下被操作时,作为 处理错误嵌套标签 的一部分)。

"before html" 插入模式 创建 html 文档元素,然后将其添加到栈中。

片段情况 中,打开元素栈 被初始化为包含一个 html 元素,该元素是在 该算法 的一部分中创建的。(片段情况 跳过 "before html" 插入模式。)

无论 html 节点如何创建,它都是栈顶部的节点。只有当解析器 结束 时,它才会从栈中弹出。

当前节点是这个 打开元素栈 中最底部的节点。

调整后的当前节点是 上下文 元素(如果解析器是在 HTML 片段解析算法 的一部分中创建的,并且 打开元素栈 中只有一个元素),否则,调整后的当前节点是当前节点。

当当前节点从 打开元素栈 中移除时,处理内部资源链接(给定当前节点的 节点文档)。

打开元素栈中的元素可以分为以下几类

特殊

以下元素具有不同程度的特殊解析规则:HTML 的 address, applet, area, article, aside, base, basefont, bgsound, blockquote, body, br, button, caption, center, col, colgroup, dd, details, dir, div, dl, dt, embed, fieldset, figcaption, figure, footer, form, frame, frameset, h1, h2, h3, h4, h5, h6, head, header, hgroup, hr, html, iframe, img, input, keygen, li, link, listing, main, marquee, menu, meta, nav, noembed, noframes, noscript, object, ol, p, param, plaintext, pre, script, search, section, select, source, style, summary, table, tbody, td, template, textarea, tfoot, th, thead, title, tr, track, ul, wbr, xmp; MathML mi, MathML mo, MathML mn, MathML ms, MathML mtext, 以及 MathML annotation-xml; 以及 SVG foreignObject, SVG desc, 以及 SVG title.

树构建器处理 image 开始标签标记,但它不在此列表中,因为它不是元素;它将被转换为一个 img 元素。

格式化

以下 HTML 元素最终会出现在 活动格式化元素列表 中:abbigcodeemfontinobrssmallstrikestrongttu

普通

在解析 HTML 文档时找到的所有其他元素。

通常,特殊 元素的开始和结束标签令牌会得到专门处理,而 普通 元素的令牌则属于“任何其他开始标签”和“任何其他结束标签”子句,树构建器的某些部分会检查 打开元素堆栈 中的特定元素是否属于 特殊 类别。但是,某些元素(例如,option 元素)的开始或结束标签令牌会得到专门处理,但仍不属于 特殊 类别,因此在其他地方会得到 普通 处理。

当以下算法在匹配状态下终止时,据说 打开元素堆栈 在由元素类型列表 list 组成的特定范围内包含元素 target node

  1. node 初始化为 当前节点(堆栈中最底部的节点)。

  2. 如果 node 是目标节点,则在匹配状态下终止。

  3. 否则,如果 nodelist 中的元素类型之一,则在失败状态下终止。

  4. 否则,将 node 设置为 打开元素堆栈 中的上一项,并返回步骤 2。(这永远不会失败,因为如果堆栈顶部(html 元素)被访问,循环将始终在上一步骤中终止。)

打开元素堆栈 在范围内包含特定元素 时,它 在由以下元素类型组成的特定范围内包含该元素

打开元素堆栈 在列表项范围内包含特定元素 时,它 在由以下元素类型组成的特定范围内包含该元素

打开元素堆栈 在按钮范围内包含特定元素 时,它 在由以下元素类型组成的特定范围内包含该元素

打开元素堆栈 在表格范围内包含特定元素 时,它 在由以下元素类型组成的特定范围内包含该元素

打开元素堆栈 在选择范围内包含特定元素 时,它 在由所有元素类型组成的特定范围内包含该元素,但以下类型除外

如果在任何时候 打开元素堆栈 中的任何元素被移至 Document 树中的新位置或从该树中移除,则不会发生任何情况。特别是,堆栈在这种情况下不会发生改变。这可能会导致(除其他奇怪的效果外)内容被追加到不再位于 DOM 中的节点。

在某些情况下(即,当 关闭嵌套错误的格式化元素 时),堆栈会以随机访问方式进行操作。

13.2.4.3 活动格式化元素列表

最初,活动格式化元素列表 是空的。它用于处理嵌套错误的 格式化元素标签

该列表包含 格式化 类别中的元素和 标记。当进入 appletobjectmarqueetemplatetdthcaption 元素时,会插入 标记,它们用于防止格式化“泄漏” appletobjectmarqueetemplatetdthcaption 元素中。

此外,活动格式化元素列表 中的每个元素都与其创建的令牌相关联,以便在需要时可以为此令牌创建更多元素。

当以下步骤要求 UA 将元素 element 推入活动格式化元素列表 时,UA 必须执行以下步骤

  1. 如果在最后一个 标记(如果有)之后或列表中没有任何 标记 的情况下,活动格式化元素列表 中已经存在三个元素,它们与 element 具有相同的标签名称、命名空间和属性,那么从 活动格式化元素列表 中移除最早的此类元素。出于这些目的,属性必须按解析器创建元素时的状态进行比较;如果两个元素的所有解析属性都可以配对,并且每对中的两个属性具有相同的名称、命名空间和值(属性的顺序无关紧要),那么这两个元素具有相同的属性。

    这是诺亚方舟条款。但每个家庭要三个人而不是两个人。

  2. element 添加到 活动格式化元素列表 中。

当以下步骤要求 UA 重建活动格式化元素 时,UA 必须执行以下步骤

  1. 如果 活动格式化元素列表 中没有条目,则无需重建;停止此算法。

  2. 如果 活动格式化元素列表 中的最后一个(最近添加的)条目是 标记,或者它是在 打开元素堆栈 中的元素,则无需重建;停止此算法。

  3. entry活动格式化元素列表 中的最后一个(最近添加的)元素。

  4. 倒带:如果 活动格式化元素列表 中没有条目位于 entry 之前,则跳至标记为创建的步骤。

  5. entry活动格式化元素列表 中比 entry 早一个条目的条目。

  6. 如果 entry 既不是 标记,也不是 打开元素栈 中的元素,则转到标记为 rewind 的步骤。

  7. Advance:令 entry活动格式化元素列表 中比 entry 晚一个的元素。

  8. Create插入 用于创建元素 entry 的标记的 HTML 元素,以获得 new element

  9. new element 的条目替换列表中 entry 的条目。

  10. 如果 活动格式化元素列表new element 的条目不是列表中的最后一个条目,则返回到标记为 advance 的步骤。

这将重新打开在当前正文、单元格或标题(以最年轻者为准)中打开的所有尚未显式关闭的格式化元素。

按照本规范的编写方式,活动格式化元素列表 始终按时间顺序排列,最近添加的元素在最前面,最晚添加的元素在最后(当然,在执行上述算法的步骤 7 到 10 时除外)。

当以下步骤要求 UA 清除活动格式化元素列表直到最后一个标记 时,UA 必须执行以下步骤

  1. entry活动格式化元素列表 中的最后一个(最近添加的)条目。

  2. 活动格式化元素列表 中删除 entry

  3. 如果 entry 是一个 标记,则在此处停止算法。该列表已清除到最后一个 标记

  4. 转到步骤 1。

13.2.4.4 元素指针

最初,head 元素指针form 元素指针 都为空。

一旦解析了 head 元素(无论是隐式还是显式),head 元素指针 将被设置为指向该节点。

form 元素指针 指向最后打开的 form 元素,并且其结束标记尚未出现。由于历史原因,它用于使表单控件在遇到严重错误的标记时与表单关联。在 template 元素内部,它会被忽略。

13.2.4.5 其他解析状态标志

如果 脚本已启用,则 脚本标志 被设置为“启用”,该脚本与解析器创建时关联的 Document 相关联,否则被设置为“禁用”。

即使解析器是作为 HTML 片段解析算法 的一部分创建的,脚本标志 也可以启用,即使在这种情况下 script 元素不会执行。

frameset-ok 标志 在解析器创建时被设置为“ok”。在看到某些标记后,它被设置为“not ok”。

13.2.5 标记化

实现必须表现得好像它们使用以下状态机对 HTML 进行标记化。该状态机必须从 数据状态 开始。大多数状态消耗单个字符,这可能会有各种副作用,并且要么将状态机切换到一个新状态以 重新消耗 当前输入字符,要么切换到一个新状态以消耗 下一个字符,要么保持在同一状态以消耗下一个字符。某些状态的行为更复杂,可以在切换到另一个状态之前消耗多个字符。在某些情况下,标记化状态也会受到树构建阶段的影响。

当一个状态说要 重新消耗 在指定状态下匹配的字符时,这意味着切换到该状态,但当它尝试消耗 下一个输入字符 时,请提供 当前输入字符 而不是。

某些状态的确切行为取决于 插入模式打开元素栈。某些状态还使用 临时缓冲区 来跟踪进度,而 字符引用状态 使用 返回状态 返回到它被调用的状态。

标记化步骤的输出是一系列零个或多个以下标记:DOCTYPE、开始标记、结束标记、注释、字符、文件结束。DOCTYPE 标记具有名称、公共标识符、系统标识符和 force-quirks 标志。当创建 DOCTYPE 标记时,它的名称、公共标识符和系统标识符必须标记为丢失(这是一个与空字符串不同的状态),并且 force-quirks 标志 必须设置为 off(它的另一个状态是 on)。开始和结束标记具有标记名称、自闭合标志 和属性列表,每个属性都有名称和值。当创建开始或结束标记时,它的 自闭合标志 必须取消设置(它的另一个状态是设置),并且它的属性列表必须为空。注释和字符标记具有数据。

当发出标记时,它必须立即由 树构建 阶段处理。树构建阶段会影响标记化阶段的状态,并可以将其他字符插入到流中。(例如,script 元素会导致脚本执行并使用 动态标记插入 API 将字符插入正在标记化的流中。)

创建标记和发出标记是不同的操作。标记可以被创建但隐式放弃(永远不会发出),例如,如果在处理被解析为开始标记的字符时文件意外结束。

当发出一个开始标记,其 自闭合标志 被设置时,如果该标志在被树构建阶段处理时没有被 确认,则这是一个 非空 HTML 元素开始标记带尾部斜杠 解析错误

当发出一个结束标记,其带有属性时,则这是一个 结束标记带属性 解析错误

当发出一个结束标记,其 自闭合标志 被设置时,则这是一个 结束标记带尾部斜杠 解析错误

合适的结束标记 是一个结束标记,其标记名称与从该标记器发出的最后一个开始标记的标记名称匹配(如果有)。如果该标记器没有发出任何开始标记,则没有结束标记是合适的。

如果 返回状态属性值(双引号)状态属性值(单引号)状态属性值(无引号)状态,则称 字符引用消耗为属性的一部分

当一个状态说要 刷新作为字符引用消耗的代码点 时,这意味着对于 临时缓冲区 中的每个 代码点(按照它们添加到缓冲区的顺序),用户代理必须将缓冲区中的代码点追加到当前属性的值(如果字符引用被 消耗为属性的一部分),或者将代码点发出为字符标记(否则)。

在标记器的每个步骤之前,用户代理必须首先检查 解析器暂停标志。如果它是 true,则标记器必须中止对标记器任何嵌套调用的处理,将控制权返回给调用者。

标记器状态机由以下小节中定义的状态组成。

13.2.5.1 数据状态

消耗 下一个输入字符

U+0026 AMPERSAND (&)
返回状态 设置为 数据状态。切换到 字符引用状态
U+003C LESS-THAN SIGN (<)
切换到 标记打开状态
U+0000 NULL
这是一个 意外空字符 解析错误。将 当前输入字符 作为字符标记发出。
EOF
发出文件结束标记。
任何其他情况
当前输入字符 作为字符标记发出。
13.2.5.2 RCDATA 状态

消耗 下一个输入字符

U+0026 AMPERSAND (&)
返回状态 设置为 RCDATA 状态。切换到 字符引用状态
U+003C LESS-THAN SIGN (<)
切换到 RCDATA 小于号状态
U+0000 NULL
这是一个 意外空字符 解析错误。发出一个 U+FFFD 替换字符字符标记。
EOF
发出文件结束标记。
任何其他情况
当前输入字符 作为字符标记发出。
13.2.5.3 RAWTEXT 状态

消耗 下一个输入字符

U+003C LESS-THAN SIGN (<)
切换到 RAWTEXT 小于号状态
U+0000 NULL
这是一个 意外的空字符 解析错误。发出一个 U+FFFD 替换字符字符标记。
EOF
发出文件结束标记。
任何其他情况
当前输入字符 作为字符标记发出。
13.2.5.4 脚本数据状态

消耗 下一个输入字符

U+003C LESS-THAN SIGN (<)
切换到 脚本数据小于符号状态
U+0000 NULL
这是一个 意外的空字符 解析错误。发出一个 U+FFFD 替换字符字符标记。
EOF
发出文件结束标记。
任何其他情况
当前输入字符 作为字符标记发出。
13.2.5.5 纯文本状态

消耗 下一个输入字符

U+0000 NULL
这是一个 意外的空字符 解析错误。发出一个 U+FFFD 替换字符字符标记。
EOF
发出文件结束标记。
任何其他情况
当前输入字符 作为字符标记发出。
13.2.5.6 标签打开状态

消耗 下一个输入字符

U+0021 感叹号 (!)
切换到 标记声明打开状态
U+002F 斜杠 (/)
切换到 结束标签打开状态
ASCII 字母
创建一个新的开始标签标记,将其标签名称设置为空字符串。在 标签名称状态重新消耗
U+003F 问号 (?)
这是一个 意外的问号而不是标签名称 解析错误。创建一个注释标记,其数据为空字符串。在 虚假注释状态重新消耗
EOF
这是一个 标签名称前的 EOF 解析错误。发出一个 U+003C 小于号字符标记和一个文件结束标记。
任何其他情况
这是一个 无效的标签名称第一个字符 解析错误。发出一个 U+003C 小于号字符标记。在 数据状态重新消耗
13.2.5.7 结束标签打开状态

消耗 下一个输入字符

ASCII 字母
创建一个新的结束标签标记,将其标签名称设置为空字符串。在 标签名称状态重新消耗
U+003E 大于号 (>)
这是一个 缺少结束标签名称 解析错误。切换到 数据状态
EOF
这是一个 标签名称前的 EOF 解析错误。发出一个 U+003C 小于号字符标记,一个 U+002F 斜杠字符标记和一个文件结束标记。
任何其他情况
这是一个 无效的标签名称第一个字符 解析错误。创建一个注释标记,其数据为空字符串。在 虚假注释状态重新消耗
13.2.5.8 标签名称状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
切换到 属性名称之前状态
U+002F 斜杠 (/)
切换到 自闭合开始标签状态
U+003E 大于号 (>)
切换到 数据状态。发出当前标签标记。
ASCII 大写字母
当前输入字符 的小写版本(在字符的代码点中添加 0x0020)附加到当前标签标记的标签名称。
U+0000 NULL
这是一个 意外的空字符 解析错误。将一个 U+FFFD 替换字符附加到当前标签标记的标签名称。
EOF
这是一个 标签中的 EOF 解析错误。发出一个文件结束标记。
任何其他情况
当前输入字符 附加到当前标签标记的标签名称。
13.2.5.9 RCDATA 小于符号状态

消耗 下一个输入字符

U+002F 斜杠 (/)
临时缓冲区 设置为空字符串。切换到 RCDATA 结束标签打开状态
任何其他情况
发出一个 U+003C 小于号字符标记。在 RCDATA 状态重新消耗
13.2.5.10 RCDATA 结束标签打开状态

消耗 下一个输入字符

ASCII 字母
创建一个新的结束标签标记,将其标签名称设置为空字符串。在 RCDATA 结束标签名称状态重新消耗
任何其他情况
发出一个 U+003C 小于号字符标记和一个 U+002F 斜杠字符标记。在 RCDATA 状态重新消耗
13.2.5.11 RCDATA 结束标签名称状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
如果当前结束标签标记是 适当的结束标签标记,则切换到 属性名称之前状态。否则,按照下面的“其他情况”条目处理。
U+002F 斜杠 (/)
如果当前结束标签标记是 适当的结束标签标记,则切换到 自闭合开始标签状态。否则,按照下面的“其他情况”条目处理。
U+003E 大于号 (>)
如果当前结束标签标记是 适当的结束标签标记,则切换到 数据状态 并发出当前标签标记。否则,按照下面的“其他情况”条目处理。
ASCII 大写字母
当前输入字符 的小写版本(在字符的代码点中添加 0x0020)附加到当前标签标记的标签名称。将 当前输入字符 附加到 临时缓冲区
ASCII 小写字母
当前输入字符 附加到当前标签标记的标签名称。将 当前输入字符 附加到 临时缓冲区
任何其他情况
发出一个 U+003C 小于号字符标记,一个 U+002F 斜杠字符标记,以及 临时缓冲区 中每个字符的字符标记(按照它们添加到缓冲区的顺序)。在 RCDATA 状态重新消耗
13.2.5.12 RAWTEXT 小于符号状态

消耗 下一个输入字符

U+002F 斜杠 (/)
临时缓冲区 设置为空字符串。切换到 RAWTEXT 结束标签打开状态
任何其他情况
发出一个 U+003C 小于号字符标记。在 RAWTEXT 状态重新消耗
13.2.5.13 RAWTEXT 结束标签打开状态

消耗 下一个输入字符

ASCII 字母
创建一个新的结束标签标记,将其标签名称设置为空字符串。在 RAWTEXT 结束标签名称状态重新消耗
任何其他情况
发出一个 U+003C 小于号字符标记和一个 U+002F 斜杠字符标记。在 RAWTEXT 状态重新消耗
13.2.5.14 RAWTEXT 结束标签名称状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
如果当前结束标签标记是 适当的结束标签标记,则切换到 属性名称之前状态。否则,按照下面的“其他情况”条目处理。
U+002F 斜杠 (/)
如果当前结束标签标记是 适当的结束标签标记,则切换到 自闭合开始标签状态。否则,按照下面的“其他情况”条目处理。
U+003E 大于号 (>)
如果当前结束标签标记是 适当的结束标签标记,则切换到 数据状态 并发出当前标签标记。否则,按照下面的“其他情况”条目处理。
ASCII 大写字母
当前输入字符 的小写版本(在字符的代码点中添加 0x0020)附加到当前标签标记的标签名称。将 当前输入字符 附加到 临时缓冲区
ASCII 小写字母
当前输入字符 附加到当前标签标记的标签名称。将 当前输入字符 附加到 临时缓冲区
任何其他情况
发出一个 U+003C 小于号字符标记,一个 U+002F 斜杠字符标记,以及 临时缓冲区 中每个字符的字符标记(按照它们添加到缓冲区的顺序)。在 RAWTEXT 状态重新消耗
13.2.5.15 脚本数据小于符号状态

消耗 下一个输入字符

U+002F 斜杠 (/)
临时缓冲区 设置为空字符串。切换到 脚本数据结束标签打开状态
U+0021 感叹号 (!)
切换到 脚本数据转义开始状态。发出一个 U+003C 小于符号字符标记和一个 U+0021 感叹号字符标记。
任何其他情况
发出一个 U+003C 小于符号字符标记。在 脚本数据状态重新消耗
13.2.5.16 脚本数据结束标签打开状态

消耗 下一个输入字符

ASCII 字母
创建一个新的结束标签标记,将其标签名称设置为空字符串。在 脚本数据结束标签名称状态重新消耗
任何其他情况
发出一个 U+003C 小于符号字符标记和一个 U+002F 斜杠字符标记。在 脚本数据状态重新消耗
13.2.5.17 脚本数据结束标签名称状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
如果当前结束标签标记是一个 合适的结束标签标记,则切换到 属性名称之前状态。否则,根据下面的“其他情况”条目进行处理。
U+002F 斜杠 (/)
如果当前结束标签标记是一个 合适的结束标签标记,则切换到 自闭合开始标签状态。否则,根据下面的“其他情况”条目进行处理。
U+003E 大于号 (>)
如果当前结束标签标记是一个 合适的结束标签标记,则切换到 数据状态 并发出当前标签标记。否则,根据下面的“其他情况”条目进行处理。
ASCII 大写字母
当前输入字符 的小写版本(将字符的代码点加 0x0020)追加到当前标签标记的标签名称中。将 当前输入字符 追加到 临时缓冲区
ASCII 小写字母
当前输入字符 追加到当前标签标记的标签名称中。将 当前输入字符 追加到 临时缓冲区
任何其他情况
发出一个 U+003C 小于符号字符标记,一个 U+002F 斜杠字符标记,以及 临时缓冲区 中每个字符的字符标记(按照它们添加到缓冲区的顺序)。在 脚本数据状态重新消耗
13.2.5.18 脚本数据转义开始状态

消耗 下一个输入字符

U+002D 连字符 (-)
切换到 脚本数据转义开始连字符状态。发出一个 U+002D 连字符字符标记。
任何其他情况
脚本数据状态重新消耗
13.2.5.19 脚本数据转义开始连字符状态

消耗 下一个输入字符

U+002D 连字符 (-)
切换到 脚本数据转义连字符连字符状态。发出一个 U+002D 连字符字符标记。
任何其他情况
脚本数据状态重新消耗
13.2.5.20 脚本数据转义状态

消耗 下一个输入字符

U+002D 连字符 (-)
切换到 脚本数据转义连字符状态。发出一个 U+002D 连字符字符标记。
U+003C LESS-THAN SIGN (<)
切换到 脚本数据转义小于符号状态
U+0000 NULL
这是一个 意外空字符 解析错误。发出一个 U+FFFD 替换字符字符标记。
EOF
这是一个 脚本 HTML 注释文本中的文件结束符 解析错误。发出一个文件结束符标记。
任何其他情况
当前输入字符 作为字符标记发出。
13.2.5.21 脚本数据转义连字符状态

消耗 下一个输入字符

U+002D 连字符 (-)
切换到 脚本数据转义连字符连字符状态。发出一个 U+002D 连字符字符标记。
U+003C LESS-THAN SIGN (<)
切换到 脚本数据转义小于符号状态
U+0000 NULL
这是一个 意外空字符 解析错误。切换到 脚本数据转义状态。发出一个 U+FFFD 替换字符字符标记。
EOF
这是一个 脚本 HTML 注释文本中的文件结束符 解析错误。发出一个文件结束符标记。
任何其他情况
切换到 脚本数据转义状态。将 当前输入字符 作为字符标记发出。
13.2.5.22 脚本数据转义连字符连字符状态

消耗 下一个输入字符

U+002D 连字符 (-)
发出一个 U+002D 连字符字符标记。
U+003C LESS-THAN SIGN (<)
切换到 脚本数据转义小于符号状态
U+003E 大于号 (>)
切换到 脚本数据状态。发出一个 U+003E 大于符号字符标记。
U+0000 NULL
这是一个 意外空字符 解析错误。切换到 脚本数据转义状态。发出一个 U+FFFD 替换字符字符标记。
EOF
这是一个 脚本 HTML 注释文本中的文件结束符 解析错误。发出一个文件结束符标记。
任何其他情况
切换到 脚本数据转义状态。将 当前输入字符 作为字符标记发出。
13.2.5.23 脚本数据转义小于符号状态

消耗 下一个输入字符

U+002F 斜杠 (/)
临时缓冲区 设置为空字符串。切换到 脚本数据转义结束标签打开状态
ASCII 字母
临时缓冲区 设置为空字符串。发出一个 U+003C 小于符号字符标记。在 脚本数据双重转义开始状态重新消耗
任何其他情况
发出一个 U+003C 小于符号字符标记。在 脚本数据转义状态重新消耗
13.2.5.24 脚本数据转义结束标签打开状态

消耗 下一个输入字符

ASCII 字母
创建一个新的结束标签标记,将其标签名称设置为空字符串。在 脚本数据转义结束标签名称状态重新消耗
任何其他情况
发出一个 U+003C 小于符号字符标记和一个 U+002F 斜杠字符标记。在 脚本数据转义状态重新消耗
13.2.5.25 脚本数据转义结束标签名称状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
如果当前结束标签标记是一个 合适的结束标签标记,则切换到 属性名称之前状态。否则,根据下面的“其他情况”条目进行处理。
U+002F 斜杠 (/)
如果当前结束标签标记是一个 合适的结束标签标记,则切换到 自闭合开始标签状态。否则,根据下面的“其他情况”条目进行处理。
U+003E 大于号 (>)
如果当前结束标签标记是一个 合适的结束标签标记,则切换到 数据状态 并发出当前标签标记。否则,根据下面的“其他情况”条目进行处理。
ASCII 大写字母
当前输入字符 的小写版本(将字符的代码点加 0x0020)追加到当前标签标记的标签名称中。将 当前输入字符 追加到 临时缓冲区
ASCII 小写字母
当前输入字符 追加到当前标签标记的标签名称中。将 当前输入字符 追加到 临时缓冲区
任何其他情况
发出一个 U+003C LESS-THAN SIGN 字符标记,一个 U+002F SOLIDUS 字符标记,以及 临时缓冲区 中每个字符的字符标记(按照它们添加到缓冲区的顺序)。重新消耗脚本数据转义状态 中。
13.2.5.26 脚本数据双重转义开始状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
U+002F 斜杠 (/)
U+003E 大于号 (>)
如果 临时缓冲区 是字符串 "script",则切换到 脚本数据双重转义状态。否则,切换到 脚本数据转义状态。将 当前输入字符 作为字符标记发出。
ASCII 大写字母
当前输入字符 的小写版本(将字符的代码点加 0x0020)追加到 临时缓冲区。将 当前输入字符 作为字符标记发出。
ASCII 小写字母
当前输入字符 追加到 临时缓冲区。将 当前输入字符 作为字符标记发出。
任何其他情况
重新消耗脚本数据转义状态 中。
13.2.5.27 脚本数据双重转义状态

消耗 下一个输入字符

U+002D 连字符 (-)
切换到 脚本数据双重转义连字符状态。发出一个 U+002D HYPHEN-MINUS 字符标记。
U+003C LESS-THAN SIGN (<)
切换到 脚本数据双重转义小于号状态。发出一个 U+003C LESS-THAN SIGN 字符标记。
U+0000 NULL
这是一个 意外空字符 解析错误。发出一个 U+FFFD REPLACEMENT CHARACTER 字符标记。
EOF
这是一个 eof-in-script-html-comment-like-text 解析错误。发出一个文件结束标记。
任何其他情况
当前输入字符 作为字符标记发出。
13.2.5.28 脚本数据双重转义连字符状态

消耗 下一个输入字符

U+002D 连字符 (-)
切换到 脚本数据双重转义连字符连字符状态。发出一个 U+002D HYPHEN-MINUS 字符标记。
U+003C LESS-THAN SIGN (<)
切换到 脚本数据双重转义小于号状态。发出一个 U+003C LESS-THAN SIGN 字符标记。
U+0000 NULL
这是一个 意外空字符 解析错误。切换到 脚本数据双重转义状态。发出一个 U+FFFD REPLACEMENT CHARACTER 字符标记。
EOF
这是一个 eof-in-script-html-comment-like-text 解析错误。发出一个文件结束标记。
任何其他情况
切换到 脚本数据双重转义状态。将 当前输入字符 作为字符标记发出。
13.2.5.29 脚本数据双重转义连字符连字符状态

消耗 下一个输入字符

U+002D 连字符 (-)
发出一个 U+002D 连字符字符标记。
U+003C LESS-THAN SIGN (<)
切换到 脚本数据双重转义小于号状态。发出一个 U+003C LESS-THAN SIGN 字符标记。
U+003E 大于号 (>)
切换到 脚本数据状态。发出一个 U+003E GREATER-THAN SIGN 字符标记。
U+0000 NULL
这是一个 意外空字符 解析错误。切换到 脚本数据双重转义状态。发出一个 U+FFFD REPLACEMENT CHARACTER 字符标记。
EOF
这是一个 eof-in-script-html-comment-like-text 解析错误。发出一个文件结束标记。
任何其他情况
切换到 脚本数据双重转义状态。将 当前输入字符 作为字符标记发出。
13.2.5.30 脚本数据双重转义小于号状态

消耗 下一个输入字符

U+002F 斜杠 (/)
临时缓冲区 设置为空字符串。切换到 脚本数据双重转义结束状态。发出一个 U+002F SOLIDUS 字符标记。
任何其他情况
重新消耗脚本数据双重转义状态 中。
13.2.5.31 脚本数据双重转义结束状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
U+002F 斜杠 (/)
U+003E 大于号 (>)
如果 临时缓冲区 是字符串 "script",则切换到 脚本数据转义状态。否则,切换到 脚本数据双重转义状态。将 当前输入字符 作为字符标记发出。
ASCII 大写字母
当前输入字符 的小写版本(将字符的代码点加 0x0020)追加到 临时缓冲区。将 当前输入字符 作为字符标记发出。
ASCII 小写字母
当前输入字符 追加到 临时缓冲区。将 当前输入字符 作为字符标记发出。
任何其他情况
重新消耗脚本数据双重转义状态 中。
13.2.5.32 属性名称之前状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
忽略该字符。
U+002F 斜杠 (/)
U+003E 大于号 (>)
EOF
重新消耗属性名称之后状态 中。
U+003D EQUALS SIGN (=)
这是一个 意外等于号在属性名称之前 解析错误。在当前标记中开始一个新的属性。将该属性的名称设置为 当前输入字符,并将它的值设置为空字符串。切换到 属性名称状态
任何其他情况
在当前标记中开始一个新的属性。将该属性名称和值设置为空字符串。 重新消耗属性名称状态 中。
13.2.5.33 属性名称状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
U+002F 斜杠 (/)
U+003E 大于号 (>)
EOF
重新消耗属性名称之后状态 中。
U+003D EQUALS SIGN (=)
切换到 属性值之前状态
ASCII 大写字母
当前输入字符 的小写版本(将字符的代码点加 0x0020)追加到当前属性的名称。
U+0000 NULL
这是一个 意外空字符 解析错误。将一个 U+FFFD REPLACEMENT CHARACTER 字符追加到当前属性的名称。
U+0022 QUOTATION MARK (")
U+0027 APOSTROPHE (')
U+003C LESS-THAN SIGN (<)
这是一个 属性名称中意外字符 解析错误。将其视为下面的“其他任何情况”条目。
任何其他情况
当前输入字符 追加到当前属性的名称。

当用户代理离开属性名称状态时(如果合适,在发出标记令牌之前),必须将完整的属性名称与同一令牌上的其他属性进行比较;如果令牌上已经存在一个具有完全相同名称的属性,那么这是一个 重复属性 解析错误,并且必须从令牌中删除新属性。

如果以这种方式从令牌中删除了一个属性,那么它以及与之关联的值(如果有)将永远不会被解析器再次使用,因此实际上会被丢弃。但是,以这种方式删除属性不会改变它作为标记器目的的“当前属性”的状态。

13.2.5.34 属性名称之后状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
忽略该字符。
U+002F 斜杠 (/)
切换到 自闭合开始标记状态
U+003D EQUALS SIGN (=)
切换到 属性值之前状态
U+003E 大于号 (>)
切换到 数据状态。发出当前标签标记。
EOF
这是一个 标签中出现 EOF 解析错误。发出一个文件结束标记。
任何其他情况
在当前标签标记中开始一个新属性。将该属性名称和值设置为空字符串。 重新消费属性名称状态 中。
13.2.5.35 属性值之前状态

消费 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
忽略该字符。
U+0022 QUOTATION MARK (")
切换到 属性值(双引号)状态
U+0027 APOSTROPHE (')
切换到 属性值(单引号)状态
U+003E 大于号 (>)
这是一个 缺少属性值 解析错误。切换到 数据状态。发出当前标签标记。
任何其他情况
重新消费属性值(无引号)状态 中。
13.2.5.36 属性值(双引号)状态

消费 下一个输入字符

U+0022 QUOTATION MARK (")
切换到 属性值之后(引号)状态
U+0026 AMPERSAND (&)
返回状态 设置为 属性值(双引号)状态。切换到 字符引用状态
U+0000 NULL
这是一个 意外的空字符 解析错误。将 U+FFFD 替换字符追加到当前属性的值中。
EOF
这是一个 标签中出现 EOF 解析错误。发出一个文件结束标记。
任何其他情况
当前输入字符 追加到当前属性的值中。
13.2.5.37 属性值(单引号)状态

消费 下一个输入字符

U+0027 APOSTROPHE (')
切换到 属性值之后(引号)状态
U+0026 AMPERSAND (&)
返回状态 设置为 属性值(单引号)状态。切换到 字符引用状态
U+0000 NULL
这是一个 意外的空字符 解析错误。将 U+FFFD 替换字符追加到当前属性的值中。
EOF
这是一个 标签中出现 EOF 解析错误。发出一个文件结束标记。
任何其他情况
当前输入字符 追加到当前属性的值中。
13.2.5.38 属性值(无引号)状态

消费 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
切换到 属性名称之前状态
U+0026 AMPERSAND (&)
返回状态 设置为 属性值(无引号)状态。切换到 字符引用状态
U+003E 大于号 (>)
切换到 数据状态。发出当前标签标记。
U+0000 NULL
这是一个 意外的空字符 解析错误。将 U+FFFD 替换字符追加到当前属性的值中。
U+0022 QUOTATION MARK (")
U+0027 APOSTROPHE (')
U+003C LESS-THAN SIGN (<)
U+003D EQUALS SIGN (=)
U+0060 重音符 (`)
这是一个 无引号属性值中的意外字符 解析错误。按照下面的“其他情况”处理它。
EOF
这是一个 标签中出现 EOF 解析错误。发出一个文件结束标记。
任何其他情况
当前输入字符 追加到当前属性的值中。
13.2.5.39 属性值之后(引号)状态

消费 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
切换到 属性名称之前状态
U+002F 斜杠 (/)
切换到 自闭合开始标签状态
U+003E 大于号 (>)
切换到 数据状态。发出当前标签标记。
EOF
这是一个 标签中出现 EOF 解析错误。发出一个文件结束标记。
任何其他情况
这是一个 缺少属性之间的空白 解析错误重新消费属性名称之前状态 中。
13.2.5.40 自闭合开始标签状态

消费 下一个输入字符

U+003E 大于号 (>)
设置当前标签标记的 自闭合标志。切换到 数据状态。发出当前标签标记。
EOF
这是一个 标签中出现 EOF 解析错误。发出一个文件结束标记。
任何其他情况
这是一个 标签中的意外斜杠 解析错误重新消费属性名称之前状态 中。
13.2.5.41 伪注释状态

消费 下一个输入字符

U+003E 大于号 (>)
切换到 数据状态。发出当前注释标记。
EOF
发出注释。发出一个文件结束标记。
U+0000 NULL
这是一个 意外的空字符 解析错误。将 U+FFFD 替换字符追加到注释标记的数据中。
任何其他情况
当前输入字符 追加到注释标记的数据中。
13.2.5.42 标记声明打开状态

如果接下来的几个字符是

两个 U+002D 连字符 (-)
消费这两个字符,创建一个数据为空字符串的注释标记,并切换到 注释开始状态
ASCII 不区分大小写 匹配单词“DOCTYPE”
消费这些字符并切换到 DOCTYPE 状态
字符串“[CDATA["(五个大写字母“CDATA”,前面和后面分别带有一个 U+005B 左方括号)
消费这些字符。如果有一个 调整后的当前节点 并且它不是 HTML 命名空间 中的元素,则切换到 CDATA 部分状态。否则,这是一个 HTML 内容中的 CDATA 解析错误。创建一个数据为“[CDATA["字符串的注释标记。切换到 伪注释状态
任何其他情况
这是一个 注释打开方式不正确 解析错误。创建一个数据为空字符串的注释标记。切换到 伪注释状态(不要在当前状态中消费任何内容)。
13.2.5.43 注释开始状态

消费 下一个输入字符

U+002D 连字符 (-)
切换到 注释开始连字符状态
U+003E 大于号 (>)
这是一个 空注释的突然关闭 解析错误。切换到 数据状态。发出当前注释标记。
任何其他情况
重新消费注释状态 中。
13.2.5.44 注释开始连字符状态

消费 下一个输入字符

U+002D 连字符 (-)
切换到 注释结束状态
U+003E 大于号 (>)
这是一个 空注释的突然关闭 解析错误。切换到 数据状态。发出当前注释标记。
EOF
这是一个 注释中出现 EOF 解析错误。发出当前注释标记。发出一个文件结束标记。
任何其他情况
将 U+002D 连字符 (-) 追加到注释标记的数据中。 重新消费注释状态 中。
13.2.5.45 注释状态

消费 下一个输入字符

U+003C LESS-THAN SIGN (<)
当前输入字符 追加到注释标记的数据中。切换到 注释小于号状态
U+002D 连字符 (-)
切换到注释结束连字符状态
U+0000 NULL
这是一个意外空字符解析错误。在注释标记的数据中追加一个 U+FFFD 替换字符。
EOF
这是一个注释中的 EOF解析错误。发出当前注释标记。发出一个 EOF 标记。
任何其他情况
在注释标记的数据中追加当前输入字符
13.2.5.46 注释小于号状态

消费下一个输入字符

U+0021 感叹号 (!)
在注释标记的数据中追加当前输入字符。切换到注释小于号感叹号状态
U+003C LESS-THAN SIGN (<)
在注释标记的数据中追加当前输入字符
任何其他情况
重新消费注释状态
13.2.5.47 注释小于号感叹号状态

消费下一个输入字符

U+002D 连字符 (-)
切换到注释小于号感叹号连字符状态
任何其他情况
重新消费注释状态
13.2.5.48 注释小于号感叹号连字符状态

消费下一个输入字符

U+002D 连字符 (-)
切换到注释小于号感叹号双连字符状态
任何其他情况
重新消费注释结束连字符状态
13.2.5.49 注释小于号感叹号双连字符状态

消费下一个输入字符

U+003E 大于号 (>)
EOF
重新消费注释结束状态
任何其他情况
这是一个嵌套注释解析错误重新消费注释结束状态
13.2.5.50 注释结束连字符状态

消费下一个输入字符

U+002D 连字符 (-)
切换到注释结束状态
EOF
这是一个注释中的 EOF解析错误。发出当前注释标记。发出一个 EOF 标记。
任何其他情况
在注释标记的数据中追加一个 U+002D 连字符 (-)。 重新消费注释状态
13.2.5.51 注释结束状态

消费下一个输入字符

U+003E 大于号 (>)
切换到数据状态。发出当前注释标记。
U+0021 感叹号 (!)
切换到注释结束感叹号状态
U+002D 连字符 (-)
在注释标记的数据中追加一个 U+002D 连字符 (-)。
EOF
这是一个注释中的 EOF解析错误。发出当前注释标记。发出一个 EOF 标记。
任何其他情况
在注释标记的数据中追加两个 U+002D 连字符 (-)。 重新消费注释状态
13.2.5.52 注释结束感叹号状态

消费下一个输入字符

U+002D 连字符 (-)
在注释标记的数据中追加两个 U+002D 连字符 (-) 和一个 U+0021 感叹号 (!)。切换到注释结束连字符状态
U+003E 大于号 (>)
这是一个错误关闭注释解析错误。切换到数据状态。发出当前注释标记。
EOF
这是一个注释中的 EOF解析错误。发出当前注释标记。发出一个 EOF 标记。
任何其他情况
在注释标记的数据中追加两个 U+002D 连字符 (-) 和一个 U+0021 感叹号 (!)。 重新消费注释状态
13.2.5.53 DOCTYPE 状态

消费下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
切换到DOCTYPE 名称之前状态
U+003E 大于号 (>)
重新消费DOCTYPE 名称之前状态
EOF
这是一个DOCTYPE 中的 EOF解析错误。创建一个新的 DOCTYPE 标记。将其强制怪异模式标志设置为 on。发出当前标记。发出一个 EOF 标记。
任何其他情况
这是一个DOCTYPE 名称之前的空格缺失解析错误重新消费DOCTYPE 名称之前状态
13.2.5.54 DOCTYPE 名称之前状态

消费下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
忽略该字符。
ASCII 大写字母
创建一个新的 DOCTYPE 标记。将标记的名称设置为当前输入字符的小写版本(在字符的代码点上加 0x0020)。切换到DOCTYPE 名称状态
U+0000 NULL
这是一个意外空字符解析错误。创建一个新的 DOCTYPE 标记。将标记的名称设置为 U+FFFD 替换字符。切换到DOCTYPE 名称状态
U+003E 大于号 (>)
这是一个DOCTYPE 名称缺失解析错误。创建一个新的 DOCTYPE 标记。将其强制怪异模式标志设置为 on。切换到数据状态。发出当前标记。
EOF
这是一个DOCTYPE 中的 EOF解析错误。创建一个新的 DOCTYPE 标记。将其强制怪异模式标志设置为 on。发出当前标记。发出一个 EOF 标记。
任何其他情况
创建一个新的 DOCTYPE 标记。将标记的名称设置为当前输入字符。切换到DOCTYPE 名称状态
13.2.5.55 DOCTYPE 名称状态

消费下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
切换到DOCTYPE 名称之后状态
U+003E 大于号 (>)
切换到数据状态。发出当前 DOCTYPE 标记。
ASCII 大写字母
在当前 DOCTYPE 标记的名称中追加当前输入字符的小写版本(在字符的代码点上加 0x0020)。
U+0000 NULL
这是一个意外空字符解析错误。在当前 DOCTYPE 标记的名称中追加一个 U+FFFD 替换字符。
EOF
这是一个DOCTYPE 中的 EOF解析错误。将当前 DOCTYPE 标记的强制怪异模式标志设置为 on。发出当前 DOCTYPE 标记。发出一个 EOF 标记。
任何其他情况
在当前 DOCTYPE 标记的名称中追加当前输入字符
13.2.5.56 DOCTYPE 名称之后状态

消费下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
忽略该字符。
U+003E 大于号 (>)
切换到数据状态。发出当前 DOCTYPE 标记。
EOF
这是一个DOCTYPE 中的 EOF解析错误。将当前 DOCTYPE 标记的强制怪异模式标志设置为 on。发出当前 DOCTYPE 标记。发出一个 EOF 标记。
任何其他情况

如果从当前输入字符开始的六个字符与单词 "PUBLIC" 的ASCII 不区分大小写匹配,则消费这些字符并切换到DOCTYPE 公共关键字之后状态

否则,如果从当前输入字符开始的六个字符与单词 "SYSTEM" 的ASCII 不区分大小写匹配,则消费这些字符并切换到DOCTYPE 系统关键字之后状态

否则,这是一个DOCTYPE 名称之后的无效字符序列解析错误。将当前 DOCTYPE 标记的强制怪异模式标志设置为 on重新消费虚假 DOCTYPE 状态

13.2.5.57 DOCTYPE 公共关键字之后状态

消费下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
切换到DOCTYPE 公共标识符之前状态
U+0022 QUOTATION MARK (")
这是一个 doctype 公共关键字后缺少空格 解析错误。将当前 DOCTYPE 标记的公共标识符设置为空字符串(不缺少),然后切换到 DOCTYPE 公共标识符(双引号)状态
U+0027 APOSTROPHE (')
这是一个 doctype 公共关键字后缺少空格 解析错误。将当前 DOCTYPE 标记的公共标识符设置为空字符串(不缺少),然后切换到 DOCTYPE 公共标识符(单引号)状态
U+003E 大于号 (>)
这是一个 缺少 doctype 公共标识符 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启。切换到 数据状态。发出当前 DOCTYPE 标记。
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启。发出当前 DOCTYPE 标记。发出一个文件结束标记。
任何其他情况
这是一个 doctype 公共标识符前缺少引号 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启重新消费伪造的 DOCTYPE 状态 中。
13.2.5.58 DOCTYPE 公共标识符之前状态

消费 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
忽略该字符。
U+0022 QUOTATION MARK (")
将当前 DOCTYPE 标记的公共标识符设置为空字符串(不缺少),然后切换到 DOCTYPE 公共标识符(双引号)状态
U+0027 APOSTROPHE (')
将当前 DOCTYPE 标记的公共标识符设置为空字符串(不缺少),然后切换到 DOCTYPE 公共标识符(单引号)状态
U+003E 大于号 (>)
这是一个 缺少 doctype 公共标识符 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启。切换到 数据状态。发出当前 DOCTYPE 标记。
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启。发出当前 DOCTYPE 标记。发出一个文件结束标记。
任何其他情况
这是一个 doctype 公共标识符前缺少引号 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启重新消费伪造的 DOCTYPE 状态 中。
13.2.5.59 DOCTYPE 公共标识符(双引号)状态

消费 下一个输入字符

U+0022 QUOTATION MARK (")
切换到 DOCTYPE 公共标识符之后状态
U+0000 NULL
这是一个 意外的空字符 解析错误。将一个 U+FFFD 替换字符追加到当前 DOCTYPE 标记的公共标识符中。
U+003E 大于号 (>)
这是一个 doctype 公共标识符突然结束 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启。切换到 数据状态。发出当前 DOCTYPE 标记。
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启。发出当前 DOCTYPE 标记。发出一个文件结束标记。
任何其他情况
当前输入字符 追加到当前 DOCTYPE 标记的公共标识符中。
13.2.5.60 DOCTYPE 公共标识符(单引号)状态

消费 下一个输入字符

U+0027 APOSTROPHE (')
切换到 DOCTYPE 公共标识符之后状态
U+0000 NULL
这是一个 意外的空字符 解析错误。将一个 U+FFFD 替换字符追加到当前 DOCTYPE 标记的公共标识符中。
U+003E 大于号 (>)
这是一个 doctype 公共标识符突然结束 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启。切换到 数据状态。发出当前 DOCTYPE 标记。
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启。发出当前 DOCTYPE 标记。发出一个文件结束标记。
任何其他情况
当前输入字符 追加到当前 DOCTYPE 标记的公共标识符中。
13.2.5.61 DOCTYPE 公共标识符之后状态

消费 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
切换到 DOCTYPE 公共标识符和系统标识符之间状态
U+003E 大于号 (>)
切换到 数据状态。发出当前 DOCTYPE 标记。
U+0022 QUOTATION MARK (")
这是一个 doctype 公共标识符和系统标识符之间缺少空格 解析错误。将当前 DOCTYPE 标记的系统标识符设置为空字符串(不缺少),然后切换到 DOCTYPE 系统标识符(双引号)状态
U+0027 APOSTROPHE (')
这是一个 doctype 公共标识符和系统标识符之间缺少空格 解析错误。将当前 DOCTYPE 标记的系统标识符设置为空字符串(不缺少),然后切换到 DOCTYPE 系统标识符(单引号)状态
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启。发出当前 DOCTYPE 标记。发出一个文件结束标记。
任何其他情况
这是一个 doctype 系统标识符前缺少引号 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启重新消费伪造的 DOCTYPE 状态 中。
13.2.5.62 DOCTYPE 公共标识符和系统标识符之间状态

消费 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
忽略该字符。
U+003E 大于号 (>)
切换到 数据状态。发出当前 DOCTYPE 标记。
U+0022 QUOTATION MARK (")
将当前 DOCTYPE 标记的系统标识符设置为空字符串(不缺少),然后切换到 DOCTYPE 系统标识符(双引号)状态
U+0027 APOSTROPHE (')
将当前 DOCTYPE 标记的系统标识符设置为空字符串(不缺少),然后切换到 DOCTYPE 系统标识符(单引号)状态
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启。发出当前 DOCTYPE 标记。发出一个文件结束标记。
任何其他情况
这是一个 doctype 系统标识符前缺少引号 解析错误。将当前 DOCTYPE 标记的 强制怪异模式标志 设置为 开启重新消费伪造的 DOCTYPE 状态 中。
13.2.5.63 DOCTYPE 系统关键字之后状态

消费 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
切换到 DOCTYPE 系统标识符之前状态
U+0022 QUOTATION MARK (")
这是一个 doctype 系统关键字后缺少空格 解析错误。将当前 DOCTYPE 标记的系统标识符设置为空字符串(不缺少),然后切换到 DOCTYPE 系统标识符(双引号)状态
U+0027 APOSTROPHE (')
这是一个 doctype 系统关键字后缺少空格 解析错误。将当前 DOCTYPE 标记的系统标识符设置为空字符串(不缺少),然后切换到 DOCTYPE 系统标识符(单引号)状态
U+003E 大于号 (>)
这是一个 缺少 doctype 系统标识符 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。切换到 数据状态。发出当前 DOCTYPE 令牌。
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。发出当前 DOCTYPE 令牌。发出一个文件结束标记。
任何其他情况
这是一个 doctype 系统标识符前的引号丢失 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。在 伪造的 DOCTYPE 状态重新消耗
13.2.5.64 DOCTYPE 系统标识符之前的状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
忽略该字符。
U+0022 QUOTATION MARK (")
将当前 DOCTYPE 令牌的系统标识符设置为空字符串(不丢失),然后切换到 DOCTYPE 系统标识符(双引号)状态
U+0027 APOSTROPHE (')
将当前 DOCTYPE 令牌的系统标识符设置为空字符串(不丢失),然后切换到 DOCTYPE 系统标识符(单引号)状态
U+003E 大于号 (>)
这是一个 缺少 doctype 系统标识符 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。切换到 数据状态。发出当前 DOCTYPE 令牌。
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。发出当前 DOCTYPE 令牌。发出一个文件结束标记。
任何其他情况
这是一个 doctype 系统标识符前的引号丢失 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。在 伪造的 DOCTYPE 状态重新消耗
13.2.5.65 DOCTYPE 系统标识符(双引号)状态

消耗 下一个输入字符

U+0022 QUOTATION MARK (")
切换到 DOCTYPE 系统标识符之后的状态
U+0000 NULL
这是一个 意外的 null 字符 解析错误。将一个 U+FFFD 替换字符追加到当前 DOCTYPE 令牌的系统标识符。
U+003E 大于号 (>)
这是一个 突然的 doctype 系统标识符 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。切换到 数据状态。发出当前 DOCTYPE 令牌。
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。发出当前 DOCTYPE 令牌。发出一个文件结束标记。
任何其他情况
当前输入字符 追加到当前 DOCTYPE 令牌的系统标识符。
13.2.5.66 DOCTYPE 系统标识符(单引号)状态

消耗 下一个输入字符

U+0027 APOSTROPHE (')
切换到 DOCTYPE 系统标识符之后的状态
U+0000 NULL
这是一个 意外的 null 字符 解析错误。将一个 U+FFFD 替换字符追加到当前 DOCTYPE 令牌的系统标识符。
U+003E 大于号 (>)
这是一个 突然的 doctype 系统标识符 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。切换到 数据状态。发出当前 DOCTYPE 令牌。
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。发出当前 DOCTYPE 令牌。发出一个文件结束标记。
任何其他情况
当前输入字符 追加到当前 DOCTYPE 令牌的系统标识符。
13.2.5.67 DOCTYPE 系统标识符之后的状态

消耗 下一个输入字符

U+0009 字符制表符 (tab)
U+000A 换行符 (LF)
U+000C 换页符 (FF)
U+0020 空格
忽略该字符。
U+003E 大于号 (>)
切换到 数据状态。发出当前 DOCTYPE 令牌。
EOF
这是一个 doctype 中的 eof 解析错误。将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。发出当前 DOCTYPE 令牌。发出一个文件结束标记。
任何其他情况
这是一个 DOCTYPE 系统标识符之后的意外字符 解析错误。在 伪造的 DOCTYPE 状态重新消耗。(这 不会 将当前 DOCTYPE 令牌的 强制 quirks 标志 设置为 on。)
13.2.5.68 伪造的 DOCTYPE 状态

消耗 下一个输入字符

U+003E 大于号 (>)
切换到 数据状态。发出 DOCTYPE 令牌。
U+0000 NULL
这是一个 意外的 null 字符 解析错误。忽略该字符。
EOF
发出 DOCTYPE 令牌。发出一个文件结束标记。
任何其他情况
忽略该字符。
13.2.5.69 CDATA 区段状态

消耗 下一个输入字符

U+005D 右方括号(])
切换到 CDATA 区段括号状态
EOF
这是一个 cdata 中的 eof 解析错误。发出一个文件结束标记。
任何其他情况
发出 当前输入字符 作为字符标记。

U+0000 NULL 字符在树构建阶段处理,作为 在外部内容中 插入模式的一部分,这是 CDATA 区段唯一可能出现的地方。

13.2.5.70 CDATA 区段括号状态

消耗 下一个输入字符

U+005D 右方括号(])
切换到 CDATA 区段结束状态
任何其他情况
发出一个 U+005D 右方括号字符标记。在 CDATA 区段状态重新消耗
13.2.5.71 CDATA 区段结束状态

消耗 下一个输入字符

U+005D 右方括号(])
发出一个 U+005D 右方括号字符标记。
U+003E 大于号字符
切换到 数据状态
任何其他情况
发出两个 U+005D 右方括号字符标记。在 CDATA 区段状态重新消耗
13.2.5.72 字符引用状态

临时缓冲区 设置为空字符串。将一个 U+0026 和号(&)字符追加到 临时缓冲区。消耗 下一个输入字符

ASCII 字母数字
命名字符引用状态重新消耗
U+0023 井号(#)
当前输入字符 追加到 临时缓冲区。切换到 数字字符引用状态
任何其他情况
作为字符引用 刷新消耗的代码点。在 返回状态重新消耗
13.2.5.73 命名字符引用状态

消耗尽可能多的字符,其中消耗的字符是 命名字符引用 表的第一列中的一个标识符。在消耗时将每个字符追加到 临时缓冲区

如果存在匹配项

如果字符引用被用作属性的一部分,并且匹配的最后一个字符不是 U+003B 分号字符 (;),以及下一个输入字符是 U+003D 等号字符 (=) 或ASCII 字母数字字符,那么出于历史原因,将作为字符引用消耗的代码点刷新,并切换到返回状态

否则

  1. 如果匹配的最后一个字符不是 U+003B 分号字符 (;),那么这是一个缺少分号的字符引用解析错误

  2. 临时缓冲区设置为空字符串。将与字符引用名称相对应的 1 或 2 个字符(如命名字符引用表中的第二列所示)追加到临时缓冲区

  3. 将作为字符引用消耗的代码点刷新。切换到返回状态
否则
将作为字符引用消耗的代码点刷新。切换到模棱两可的&符号状态

如果标记包含(不在属性中)字符串 I'm &notit; I tell you,字符引用将被解析为“not”,就像 I'm ¬it; I tell you (这是一个解析错误)。但如果标记是 I'm &notin; I tell you,字符引用将被解析为“notin;”,导致 I'm ∉ I tell you (没有解析错误)。

但是,如果标记包含字符串 I'm &notit; I tell you 在属性中,不会解析任何字符引用,字符串保持不变(并且没有解析错误)。

13.2.5.74 模棱两可的&符号状态

消耗下一个输入字符

ASCII 字母数字
如果字符引用被用作属性的一部分,那么将当前输入字符追加到当前属性的值中。否则,将当前输入字符作为字符标记发出。
U+003B 分号 (;)
这是一个未知的命名字符引用解析错误。在返回状态重新消耗
任何其他情况
返回状态重新消耗
13.2.5.75 数字字符引用状态

字符引用代码设置为零 (0)。

消耗下一个输入字符

U+0078 小写字母 x
U+0058 大写字母 X
当前输入字符追加到临时缓冲区。切换到十六进制字符引用起始状态
任何其他情况
十进制字符引用起始状态重新消耗
13.2.5.76 十六进制字符引用起始状态

消耗下一个输入字符

ASCII 十六进制数字
十六进制字符引用状态重新消耗
任何其他情况
这是一个数字字符引用中缺少数字解析错误将作为字符引用消耗的代码点刷新。在返回状态重新消耗
13.2.5.77 十进制字符引用起始状态

消耗下一个输入字符

ASCII 数字
十进制字符引用状态重新消耗
任何其他情况
这是一个数字字符引用中缺少数字解析错误将作为字符引用消耗的代码点刷新。在返回状态重新消耗
13.2.5.78 十六进制字符引用状态

消耗下一个输入字符

ASCII 数字
字符引用代码乘以 16。将当前输入字符的数字版本(从字符的代码点中减去 0x0030)添加到字符引用代码
ASCII 大写十六进制数字
字符引用代码乘以 16。将当前输入字符的数字版本作为十六进制数字(从字符的代码点中减去 0x0037)添加到字符引用代码
ASCII 小写十六进制数字
字符引用代码乘以 16。将当前输入字符的数字版本作为十六进制数字(从字符的代码点中减去 0x0057)添加到字符引用代码
U+003B 分号
切换到数字字符引用结束状态
任何其他情况
这是一个缺少分号的字符引用解析错误。在数字字符引用结束状态重新消耗
13.2.5.79 十进制字符引用状态

消耗下一个输入字符

ASCII 数字
字符引用代码乘以 10。将当前输入字符的数字版本(从字符的代码点中减去 0x0030)添加到字符引用代码
U+003B 分号
切换到数字字符引用结束状态
任何其他情况
这是一个缺少分号的字符引用解析错误。在数字字符引用结束状态重新消耗
13.2.5.80 数字字符引用结束状态

检查字符引用代码

临时缓冲区 设置为一个空字符串。在 临时缓冲区 中追加一个与 字符引用代码 相等的代码点。 将作为字符引用所消耗的代码点刷新。切换到 返回状态

13.2.6 树构建

树构建阶段的输入是来自 标记化 阶段的一系列标记。当创建解析器时,树构建阶段与一个 DOM Document 对象关联。此阶段的“输出”包括动态修改或扩展该文档的 DOM 树。

本规范没有定义交互式用户代理何时必须呈现 Document 以便用户可以使用它,或者何时必须开始接受用户输入。


当解析器从标记化器中发出每个标记时,用户代理必须按照以下列表中的相应步骤执行,这些步骤被称为 树构建分派器

如果 打开元素堆栈 为空
如果 调整后的当前节点HTML 命名空间 中的元素
如果 调整后的当前节点 是一个 MathML 文本集成点 且该标记是一个开始标记,其标记名称既不是“mglyph”也不是“malignmark”
如果 调整后的当前节点 是一个 MathML 文本集成点 且该标记是字符标记
如果 调整后的当前节点 是一个 MathML annotation-xml 元素且该标记是一个开始标记,其标记名称是“svg”
如果 调整后的当前节点 是一个 HTML 集成点 且该标记是一个开始标记
如果 调整后的当前节点 是一个 HTML 集成点 且该标记是字符标记
如果该标记是文件结束标记
根据 HTML 内容中与当前 插入模式 相对应的部分中给出的规则处理该标记。
否则
根据在 外来内容中解析标记 部分中给出的规则处理该标记。

下一个标记 是将要由 树构建分派器 处理的标记(即使该标记随后被忽略)。

如果节点是以下元素之一,则它是一个 MathML 文本集成点

如果节点是以下元素之一,则它是一个 HTML 集成点

如果所讨论的节点是传递给 HTML 片段解析算法上下文 元素,则该元素的开始标记标记是在 HTML 片段解析算法 中创建的“假”标记。


下面提到的并非所有标记名称在本规范中都是符合规范的标记名称;其中许多标记名称是为了处理遗留内容而包含的。它们仍然是实现需要实现以声明符合规范的算法的一部分。

下面描述的算法对生成的 DOM 树的深度或标记名称、属性名称、属性值、Text 节点等的长度没有限制。虽然鼓励实现者 避免任意限制,但认识到实际问题可能会迫使用户代理强加嵌套深度约束。

13.2.6.1 创建和插入节点

当解析器正在处理标记时,它可以启用或禁用 养父模式。这会影响以下算法。

插入节点的适当位置(可选地使用特定覆盖目标)是在运行以下步骤后返回的元素中的位置

  1. 如果指定了覆盖目标,则令 target覆盖目标

    否则,令 target当前节点

  2. 使用以下列表中的第一个匹配步骤确定 调整后的插入位置

    如果 养父模式 已启用且 targettabletbodytfoottheadtr 元素

    当内容在表格中错误嵌套时,就会发生养父模式。

    运行以下子步骤

    1. 最后一个模板打开元素堆栈 中的最后一个 template 元素(如果有)。

    2. 最后一个表格打开元素堆栈 中的最后一个 table 元素(如果有)。

    3. 如果有 最后一个模板 并且要么没有 最后一个表格,要么有一个,但是 最后一个模板打开元素堆栈 中比 最后一个表格 更低(最近添加),则:令 调整后的插入位置最后一个模板模板内容 中,在其最后一个子节点(如果有)之后,并中止这些步骤。

    4. 如果没有 最后一个表格,则令 调整后的插入位置打开元素堆栈 中的第一个元素(html 元素)中,在其最后一个子节点(如果有)之后,并中止这些步骤。 (片段情况)

    5. 如果 最后一个表格 有一个父节点,则令 调整后的插入位置最后一个表格 的父节点中,在 最后一个表格 之前,并中止这些步骤。

    6. 前一个元素打开元素堆栈 中在 最后一个表格 上面的元素。

    7. 调整后的插入位置前一个元素 中,在其最后一个子节点(如果有)之后。

    这些步骤涉及的部分原因是,元素(尤其是这种情况下的 table 元素)可能在解析器插入元素之后,被脚本在 DOM 中移动,甚至完全从 DOM 中删除。

    否则

    调整后的插入位置target 中,在其最后一个子节点(如果有)之后。

  3. 如果 调整后的插入位置template 元素中,则改为将其放在 template 元素的 模板内容 中,在其最后一个子节点(如果有)之后。

  4. 返回 调整后的插入位置


当以下步骤要求 UA 为标记创建元素 时,在特定 给定命名空间 中,并且具有特定 预期父节点,UA 必须运行以下步骤

  1. 如果 活动推测 HTML 解析器 不为空,则返回 创建推测性模拟元素 的结果,给定 给定命名空间、给定标记的标记名称以及给定标记的属性。

  2. 否则,可以选择性地 创建假设的模拟元素,给定 给定命名空间,给定标记的标签名称,以及给定标记的属性。

    结果不用。此步骤允许从非假设解析开始发起 假设获取。获取在此阶段仍然是假设的,因为例如,到元素插入时,预期父级可能已从文档中删除。

  3. 文档预期父级节点文档

  4. 本地名称 为标记的标签名称。

  5. is 为给定标记中 “is” 属性的值,如果存在这样的属性,否则为 null。

  6. 定义 为给定 文档给定命名空间本地名称is 时,查找自定义元素定义 的结果。

  7. 如果 定义 非空且解析器不是作为 HTML 片段解析算法 的一部分创建的,则设 将执行脚本 为 true。否则,设其为 false。

  8. 如果 将执行脚本 为 true,则

    1. 增加 文档抛出动态标记插入计数器

    2. 如果 JavaScript 执行上下文堆栈 为空,则 执行微任务检查点

    3. 将一个新的 元素队列 推入 文档相关代理自定义元素反应堆栈 中。

  9. 元素 为给定 文档localName给定命名空间、null 和 is 时,创建元素 的结果。如果 将执行脚本 为 true,则设置 同步自定义元素标志;否则,保留其未设置状态。

    这将导致 自定义元素构造函数 运行,如果 将执行脚本 为 true。然而,由于我们增加了 抛出动态标记插入计数器,这不会导致 新的字符插入到标记器中,或 文档被清除

  10. 追加 给定标记中的每个属性到 元素

    这可以 将自定义元素回调反应排队 用于 attributeChangedCallback,这可能会立即运行(在下一步中)。

    即使 is 属性控制 创建 自定义内置元素,但在执行相关 自定义元素构造函数 时,它不存在;它将在这一步中与所有其他属性一起追加。

  11. 如果 将执行脚本 为 true,则

    1. 队列 为从 文档相关代理自定义元素反应堆栈 中弹出的结果。(这将与上面推入的 元素队列 相同。)

    2. 调用自定义元素反应队列 中。

    3. 减少 文档抛出动态标记插入计数器

  12. 如果 元素 具有一个 xmlns 属性 *在 XMLNS 命名空间 中*,其值不完全与元素的命名空间相同,则这是一个 解析错误。类似地,如果 元素 具有一个 xmlns:xlink 属性在 XMLNS 命名空间 中,其值不是 XLink 命名空间,则这是一个 解析错误

  13. 如果 元素 是一个 可重置元素,则调用其 重置算法。(这根据元素的属性初始化元素的 选中状态。)

  14. 如果 元素 是一个 与表单关联的元素 且不是一个 与表单关联的自定义元素form 元素指针 非空,打开元素堆栈 上没有 template 元素,元素 既不是 列出的,也没有 form 属性,且 预期父级form 元素指针 指向的元素位于同一 中,则 关联 元素form 元素指针 指向的 form 元素,并设置 元素解析器插入标志

  15. 返回 元素


在调整后的插入位置插入元素,带有元素 元素

  1. 调整后的插入位置插入节点的适当位置

  2. 如果无法在 调整后的插入位置 插入 元素,则中止这些步骤。

  3. 如果解析器不是作为 HTML 片段解析算法 的一部分创建的,则将一个新的 元素队列 推入 元素相关代理自定义元素反应堆栈 中。

  4. 调整后的插入位置 插入 元素

  5. 如果解析器不是作为 HTML 片段解析算法 的一部分创建的,则从 元素相关代理自定义元素反应堆栈 中弹出 元素队列,并在该队列中 调用自定义元素反应

如果 调整后的插入位置 无法接受更多元素,例如,因为它是一个 Document 且已具有元素子级,则 元素 被丢弃在地板上。

当以下步骤要求用户代理 插入一个外部元素 用于给定命名空间中的标记,并带有布尔值 onlyAddToElementStack 时,用户代理必须运行以下步骤

  1. 调整后的插入位置插入节点的适当位置

  2. 元素 为在给定命名空间中 为标记创建元素 的结果,其中预期父级为 调整后的插入位置 所在的元素。

  3. 如果 onlyAddToElementStack 为 false,则运行 在调整后的插入位置插入元素,带有 元素

  4. 元素 推入 打开元素堆栈 中,使其成为新的 当前节点

  5. 返回 元素

当以下步骤要求用户代理 插入一个 HTML 元素 用于标记时,用户代理必须 插入一个外部元素 用于标记,带有 HTML 命名空间 和 false。


当以下步骤要求用户代理 调整 MathML 属性 用于标记时,如果标记具有一个名为 definitionurl 的属性,则将其名称更改为 definitionURL(注意大小写差异)。

当以下步骤要求用户代理 调整 SVG 属性 用于标记时,对于标记上的每个属性,其属性名称是以下表格第一列中的名称之一,则将属性的名称更改为第二列对应单元格中的名称。(这修复了并非全部小写的 SVG 属性的大小写。)

标记上的属性名称元素上的属性名称
attributename attributeName
attributetype attributeType
basefrequency baseFrequency
baseprofile baseProfile
calcmode calcMode
clippathunits clipPathUnits
diffuseconstant diffuseConstant
edgemode edgeMode
filterunits filterUnits
glyphref glyphRef
gradienttransform gradientTransform
gradientunits gradientUnits
kernelmatrix kernelMatrix
kernelunitlength kernelUnitLength
keypoints keyPoints
keysplines keySplines
keytimes keyTimes
lengthadjust lengthAdjust
limitingconeangle limitingConeAngle
markerheight markerHeight
markerunits markerUnits
markerwidth markerWidth
maskcontentunits maskContentUnits
maskunits maskUnits
numoctaves numOctaves
pathlength pathLength
patterncontentunits patternContentUnits
patterntransform patternTransform
patternunits patternUnits
pointsatx pointsAtX
pointsaty pointsAtY
pointsatz pointsAtZ
preservealpha preserveAlpha
preserveaspectratio preserveAspectRatio
primitiveunits primitiveUnits
refx refX
refy refY
repeatcount repeatCount
repeatdur repeatDur
requiredextensions requiredExtensions
requiredfeatures requiredFeatures
specularconstant specularConstant
specularexponent specularExponent
spreadmethod spreadMethod
startoffset startOffset
stddeviation stdDeviation
stitchtiles stitchTiles
surfacescale surfaceScale
systemlanguage systemLanguage
tablevalues tableValues
targetx targetX
targety targetY
textlength textLength
viewbox viewBox
viewtarget viewTarget
xchannelselector xChannelSelector
ychannelselector yChannelSelector
zoomandpan zoomAndPan

当以下步骤要求用户代理为令牌调整外部属性时,如果令牌上的任何属性与下表第一列中给出的字符串匹配,则让该属性成为命名空间属性,前缀为第二列中对应单元格中给出的字符串,本地名为第三列中对应单元格中给出的字符串,命名空间为第四列中对应单元格中给出的命名空间。(这修复了命名空间属性的使用,特别是lang 属性在XML 命名空间中)。

属性名称前缀本地名称命名空间
xlink:actuate xlink actuate XLink 命名空间
xlink:arcrole xlink arcrole XLink 命名空间
xlink:href xlink href XLink 命名空间
xlink:role xlink role XLink 命名空间
xlink:show xlink show XLink 命名空间
xlink:title xlink title XLink 命名空间
xlink:type xlink type XLink 命名空间
xml:lang xml lang XML 命名空间
xml:space xml space XML 命名空间
xmlns (无) xmlns XMLNS 命名空间
xmlns:xlink xmlns xlink XMLNS 命名空间

当以下步骤要求用户代理在处理令牌时插入字符时,用户代理必须运行以下步骤

  1. data 为传递给算法的字符,或者,如果没有明确指定字符,则为正在处理的字符令牌的字符。

  2. 调整后的插入位置插入节点的适当位置

  3. 如果 调整后的插入位置 位于 Document 节点中,则返回。

    DOM 不会让 Document 节点具有 Text 节点子节点,因此它们被丢弃。

  4. 如果在 调整后的插入位置 之前有一个 Text 节点,则将 data 附加到该 Text 节点的 data

    否则,创建一个新的 Text 节点,其 datadata,其 node document调整后的插入位置 所在的元素相同,并将新创建的节点插入 调整后的插入位置

以下是一些解析器的示例输入及其导致的 Text 节点数量,假设用户代理会执行脚本。

输入Text 节点数量
A<script>
var script = document.getElementsByTagName('script')[0];
document.body.removeChild(script);
</script>B
文档中一个 Text 节点,包含 "AB"。
A<script>
var text = document.createTextNode('B');
document.body.appendChild(text);
</script>C
三个 Text 节点;脚本前的 "A"、脚本的内容以及脚本后的 "BC"(解析器将附加到脚本创建的 Text 节点)。
A<script>
var text = document.getElementsByTagName('script')[0].firstChild;
text.data = 'B';
document.body.appendChild(text);
</script>C
文档中两个相邻的 Text 节点,包含 "A" 和 "BC"。
A<table>B<tr>C</tr>D</table>
表格前一个 Text 节点,包含 "ABCD"。(这是由寄养父节点引起的。)
A<table><tr> B</tr> C</table>
表格前一个 Text 节点,包含 "A B C"(A-空格-B-空格-C)。(这是由寄养父节点引起的。)
A<table><tr> B</tr> </em>C</table>
表格前一个 Text 节点,包含 "A BC"(A-空格-B-C),表格内一个 Text 节点(作为 tbody 的子节点),包含单个空格字符。(即使其他令牌随后被忽略,由非字符令牌分隔的空格字符也不会受到寄养父节点的影响。)

当以下步骤要求用户代理在处理注释令牌时插入注释时,可以选择带有显式插入位置 position,用户代理必须运行以下步骤

  1. data 为正在处理的注释令牌中给出的数据。

  2. 如果指定了 position,则令 调整后的插入位置position。否则,令 调整后的插入位置插入节点的适当位置

  3. 创建一个 Comment 节点,其 data 属性设置为 data,其 node document调整后的插入位置 所在的节点相同。

  4. 将新创建的节点插入 调整后的插入位置

13.2.6.2 解析仅包含文本的元素

通用原始文本元素解析算法通用 RCDATA 元素解析算法 包括以下步骤。这些算法总是响应开始标签令牌被调用。

  1. 插入 HTML 元素 用于该令牌。

  2. 如果调用了 通用原始文本元素解析算法,则将标记器切换到 RAWTEXT 状态;否则,调用了 通用 RCDATA 元素解析算法,则将标记器切换到 RCDATA 状态

  3. 原始插入模式 为当前 插入模式

  4. 然后,将 插入模式 切换到 "text"。

13.2.6.3 关闭具有隐式结束标签的元素

当以下步骤要求 UA 生成隐式结束标签 时,只要 当前节点dd 元素、dt 元素、li 元素、optgroup 元素、option 元素、p 元素、rb 元素、rp 元素、rt 元素或 rtc 元素,UA 必须将 当前节点打开元素堆栈 中弹出。

如果某个步骤要求 UA 生成隐式结束标签,但列出了要从该过程中排除的元素,则 UA 必须像该元素不在上述列表中一样执行上述步骤。

当以下步骤要求 UA 彻底生成所有隐式结束标签 时,只要 当前节点caption 元素、colgroup 元素、dd 元素、dt 元素、li 元素、optgroup 元素、option 元素、p 元素、rb 元素、rp 元素、rt 元素、rtc 元素、tbody 元素、td 元素、tfoot 元素、th 元素、thead 元素或 tr 元素,UA 必须将 当前节点打开元素堆栈 中弹出。

13.2.6.4 HTML 内容中解析令牌的规则
13.2.6.4.1 "initial" 插入模式

Document 对象具有关联的解析器无法更改模式标志(布尔值)。它最初为 false。

当用户代理要应用 "initial" 插入模式 的规则时,用户代理必须按如下方式处理令牌

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

忽略该标记。

一个注释标记

插入注释 作为 Document 对象的最后一个子节点。

一个 DOCTYPE 标记

如果 DOCTYPE 标记的名称不是 "html",或者标记的公共标识符不缺失,或者标记的系统标识符既不缺失也不为 "about:legacy-compat",那么存在一个 解析错误

将一个 DocumentType 节点附加到 Document 节点,其 名称 设置为 DOCTYPE 标记中给出的名称,或者如果名称缺失则为空字符串;其 公共标识符 设置为 DOCTYPE 标记中给出的公共标识符,或者如果公共标识符缺失则为空字符串;其 系统标识符 设置为 DOCTYPE 标记中给出的系统标识符,或者如果系统标识符缺失则为空字符串。

这也确保了 DocumentType 节点被返回作为 doctype 属性的 Document 对象的值。

然后,如果文档不是 一个 iframe srcdoc 文档,并且 解析器不能更改模式标志 为 false,并且 DOCTYPE 标记匹配以下列表中的一个条件,那么将 Document 设置为 怪癖模式

否则,如果文档不是 一个 iframe srcdoc 文档,并且 解析器不能更改模式标志 为 false,并且 DOCTYPE 标记匹配以下列表中的一个条件,那么将 Document 设置为 有限怪癖模式

系统标识符和公共标识符字符串必须以 ASCII 不区分大小写 的方式与上面列表中给出的值进行比较。系统标识符的值为空字符串,在上述条件中不被视为缺失。

然后,将 插入模式 切换为 "before html"。

任何其他情况

如果文档不是 一个 iframe srcdoc 文档,那么这是一个 解析错误;如果 解析器不能更改模式标志 为 false,那么将 Document 设置为 怪癖模式

在任何情况下,将 插入模式 切换为 "before html",然后重新处理该标记。

13.2.6.4.2 "before html" 插入模式

当用户代理要应用 "before html" 插入模式 的规则时,用户代理必须按如下方式处理该标记

一个 DOCTYPE 标记

解析错误。忽略该标记。

一个注释标记

插入注释 作为 Document 对象的最后一个子节点。

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

忽略该标记。

一个起始标签,其标签名称为 "html"

为该标记创建一个元素,在 HTML 命名空间 中,以 Document 作为预期的父节点。将其附加到 Document 对象。将此元素放入 打开元素堆栈 中。

插入模式 切换为 "before head"。

一个结束标签,其标签名称为以下之一:"head","body","html","br"

按如下面的 "其他任何内容" 条目中所述进行操作。

任何其他结束标签

解析错误。忽略该标记。

任何其他情况

创建一个 html 元素,其 节点文档Document 对象。将其附加到 Document 对象。将此元素放入 打开元素堆栈 中。

插入模式切换到“头部之前”,然后重新处理标记。

文档元素最终可能会从文档对象中移除,例如,通过脚本移除;在这种情况下,不会发生任何特殊的事情,内容会继续按照下一节中描述的顺序追加到节点。

13.2.6.4.3头部之前” 插入模式

当用户代理需要应用“头部之前插入模式的规则时,用户代理必须按照以下方式处理标记

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

忽略该标记。

一个注释标记

插入一个注释.

一个 DOCTYPE 标记

解析错误。忽略该标记。

一个起始标签,其标签名称为 "html"

按照“正文内插入模式的规则处理该标记.

一个其标记名称为“head”的开始标记

为该标记插入一个 HTML 元素.

head 元素指针设置为新创建的head元素。

插入模式切换到“头部内”。

一个结束标签,其标签名称为以下之一:"head","body","html","br"

按如下面的 "其他任何内容" 条目中所述进行操作。

任何其他结束标签

解析错误。忽略该标记。

任何其他情况

为一个没有属性的“head”开始标记插入一个 HTML 元素.

head 元素指针设置为新创建的head元素。

插入模式切换到“头部内”。

重新处理当前标记。

13.2.6.4.4头部内” 插入模式

当用户代理需要应用“头部内插入模式的规则时,用户代理必须按照以下方式处理标记

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

插入字符.

一个注释标记

插入一个注释.

一个 DOCTYPE 标记

解析错误。忽略该标记。

一个起始标签,其标签名称为 "html"

按照“正文内插入模式的规则处理该标记.

一个其标记名称为以下之一的开始标记:“base”、“basefont”、“bgsound”、“link”

为该标记插入一个 HTML 元素。立即从打开元素栈中弹出当前节点

确认标记的自闭合标志,如果它被设置。

一个其标记名称为“meta”的开始标记

为该标记插入一个 HTML 元素。立即从打开元素栈中弹出当前节点

确认标记的自闭合标志,如果它被设置。

如果活动的推测性 HTML 解析器为空,那么

  1. 如果该元素有一个charset属性,并且从其值获取编码的结果是编码,并且置信度当前为暂定,那么将编码更改为结果编码。

  2. 否则,如果该元素有一个http-equiv属性,其值为ASCII 忽略大小写匹配字符串“Content-Type”,并且该元素有一个content属性,并且将meta 元素中提取字符编码的算法应用于该属性的值返回一个编码,并且置信度当前为暂定,那么将编码更改为提取的编码。

推测性 HTML 解析器不会推测性地应用字符编码声明,以降低实现复杂度。

一个其标记名称为“title”的开始标记

遵循通用 RCDATA 元素解析算法

如果脚本标志已启用,则其标记名称为“noscript”的开始标记
一个其标记名称为以下之一的开始标记:“noframes”、“style”

遵循通用原始文本元素解析算法

如果脚本标志已禁用,则其标记名称为“noscript”的开始标记

为该标记插入一个 HTML 元素.

插入模式切换到“头部 noscript 内”。

一个其标记名称为“script”的开始标记

运行以下步骤

  1. 调整后的插入位置设置为插入节点的合适位置

  2. 为该标记创建一个元素,该元素位于HTML 命名空间中,其预期父元素为调整后的插入位置所在的元素。

  3. 将该元素的解析器文档设置为文档,并将该元素的强制异步设置为 false。

    这确保了,如果该脚本是外部的,则该脚本中的任何document.write()调用将在内联执行,而不是破坏文档,正如在大多数其他情况下那样。它还阻止该脚本在看到结束标记之前执行。

  4. 如果该解析器是作为HTML 片段解析算法的一部分创建的,则将script元素的已开始设置为 true。(片段情况

  5. 如果该解析器是通过document.write()document.writeln()方法调用的,则可以选择将script元素的已开始设置为 true。(例如,用户代理可以使用此子句来阻止通过document.write()插入的跨域脚本在网络速度慢的情况下或页面加载时间过长的情况下执行。)

  6. 将新创建的元素插入到调整后的插入位置

  7. 将该元素推送到打开元素栈中,使其成为新的当前节点

  8. 将标记器切换到脚本数据状态

  9. 原始插入模式设置为当前插入模式

  10. 插入模式切换到“文本”。

一个其标记名称为“head”的结束标记

打开元素栈中弹出当前节点(它将是head元素)。

插入模式切换到“头部之后”。

一个其标记名称为以下之一的结束标记:“body”、“html”、“br”

按如下面的 "其他任何内容" 条目中所述进行操作。

一个其标记名称为“template”的开始标记

模板开始标记设置为开始标记。

活动格式化元素列表的末尾插入一个标记

框架集允许标志设置为“不允许”。

插入模式切换到“模板内”。

将“模板内”推送到模板插入模式栈中,使其成为新的当前模板插入模式

调整后的插入位置设置为插入节点的合适位置

预期父元素设置为调整后的插入位置所在的元素。

文档设置为预期父元素节点文档

如果以下任何一项为 false

插入一个 HTML 元素 用于该标记。

否则

  1. 声明式影子宿主元素调整后的当前节点

  2. 模板插入一个外部元素 用于 模板开始标记 的结果,其 HTML 命名空间 为真。

  3. 模式模板开始标记shadowrootmode 属性的值。

  4. 可克隆 为真,如果 模板开始标记 有一个 shadowrootclonable 属性;否则为假。

  5. 可序列化 为真,如果 模板开始标记 有一个 shadowrootserializable 属性;否则为假。

  6. 委托焦点 为真,如果 模板开始标记 有一个 shadowrootdelegatesfocus 属性;否则为假。

  7. 如果 声明式影子宿主元素 是一个 影子宿主,则 在调整后的插入位置插入一个元素,该元素的模板为 模板

  8. 否则

    1. 附加一个影子根,其 声明式影子宿主元素模式可克隆可序列化委托焦点 和 "named"。

      如果抛出异常,则捕获它并

      1. 在调整后的插入位置插入一个元素,该元素的模板为 模板

      2. 用户代理可能会向开发者控制台报告错误。

      3. 返回。

    2. 影子声明式影子宿主元素影子根

    3. 影子声明式 设置为真。

    4. 模板模板内容 属性设置为 影子

    5. 影子可用于元素内部 设置为真。

一个结束标记,其标记名为 "template"

如果 打开元素栈 中没有 模板 元素,则这是一个 解析错误;忽略该标记。

否则,运行以下步骤

  1. 彻底生成所有隐式结束标记.

  2. 如果 当前节点 不是一个 模板 元素,则这是一个 解析错误

  3. 打开元素栈 中弹出元素,直到一个 模板 元素从栈中弹出。

  4. 清除活动格式化元素列表,直到最后一个标记。.
  5. 模板插入模式栈 中弹出 当前模板插入模式

  6. 适当地重置插入模式.

一个其标记名称为“head”的开始标记
任何其他结束标签

解析错误。忽略该标记。

任何其他情况

打开元素栈 中弹出 当前节点(它将是 head 元素)。

插入模式 切换到 " after head" 。

重新处理该标记。

13.2.6.4.5 " in head noscript" 插入模式

当用户代理要应用 " in head noscript" 插入模式 的规则时,用户代理必须按如下方式处理该标记

一个 DOCTYPE 标记

解析错误。忽略该标记。

一个起始标签,其标签名称为 "html"

使用 " in body" 插入模式 的规则 处理该标记。

一个结束标记,其标记名为 "noscript"

打开元素栈 中弹出 当前节点 (它将是一个 noscript 元素);新的 当前节点 将是一个 head 元素。

插入模式 切换到 " in head" 。

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE
一个注释标记
一个开始标记,其标记名为以下之一:"basefont"、"bgsound"、"link"、"meta"、"noframes"、"style"

使用 " in head" 插入模式 的规则 处理该标记。

一个结束标记,其标记名为 "br"

按如下面的 "其他任何内容" 条目中所述进行操作。

一个开始标记,其标记名为以下之一:"head"、"noscript"
任何其他结束标签

解析错误。忽略该标记。

任何其他情况

解析错误.

打开元素栈 中弹出 当前节点 (它将是一个 noscript 元素);新的 当前节点 将是一个 head 元素。

插入模式 切换到 " in head" 。

重新处理该标记。

13.2.6.4.6 " after head" 插入模式

当用户代理要应用 " after head" 插入模式 的规则时,用户代理必须按如下方式处理该标记

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

插入字符.

一个注释标记

插入一个注释.

一个 DOCTYPE 标记

解析错误。忽略该标记。

一个起始标签,其标签名称为 "html"

使用 " in body" 插入模式 的规则 处理该标记。

一个开始标记,其标记名为 "body"

插入一个 HTML 元素 用于该标记。

frameset-ok 标记 设置为 "not ok"。

插入模式 切换到 " in body" 。

一个开始标记,其标记名为 "frameset"

插入一个 HTML 元素 用于该标记。

插入模式 切换到 " in frameset" 。

一个开始标记,其标记名为以下之一:"base"、"basefont"、"bgsound"、"link"、"meta"、"noframes"、"script"、"style"、"template"、"title"

解析错误.

head 元素指针 指向的节点推送到 打开元素栈 中。

使用 " in head" 插入模式 的规则 处理该标记。

打开元素栈 中删除 head 元素指针 指向的节点。(它可能此时不是 当前节点)。

head 元素指针 此时不能为 null。

一个结束标记,其标记名为 "template"

使用 " in head" 插入模式 的规则 处理该标记。

一个其标记名称为以下之一的结束标记:“body”、“html”、“br”

按如下面的 "其他任何内容" 条目中所述进行操作。

一个其标记名称为“head”的开始标记
任何其他结束标签

解析错误。忽略该标记。

任何其他情况

插入一个 HTML 元素,用于一个没有属性的 "body" 开始标记标记。

插入模式 切换到 " in body" 。

重新处理当前标记。

13.2.6.4.7 " in body" 插入模式

当用户代理要应用 " in body" 插入模式 的规则时,用户代理必须按如下方式处理该标记

一个字符标记,其为 U+0000 NULL

解析错误。忽略该标记。

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

重建活动格式化元素,如果有。

插入该标记的字符.

任何其他字符标记

重建活动格式化元素,如果有。

插入该标记的字符.

frameset-ok 标记 设置为 "not ok"。

一个注释标记

插入一个注释.

一个 DOCTYPE 标记

解析错误。忽略该标记。

一个起始标签,其标签名称为 "html"

解析错误.

如果 打开元素栈 中有一个 模板 元素,则忽略该标记。

否则,对于该标记上的每个属性,检查该属性是否已经存在于 打开元素栈 的顶层元素上。如果没有,则将该属性及其对应值添加到该元素中。

一个开始标记,其标记名为以下之一:"base"、"basefont"、"bgsound"、"link"、"meta"、"noframes"、"script"、"style"、"template"、"title"
一个结束标记,其标记名为 "template"

使用“头部插入模式 的规则来处理此标记。

一个开始标记,其标记名为 "body"

解析错误.

如果打开元素堆栈 只有一个节点,如果打开元素堆栈 上的第二个元素不是一个body 元素,或者如果打开元素堆栈 上有一个template 元素,则忽略此标记。(片段情况 或者堆栈上有一个template 元素)

否则,将frameset-ok 标记 设置为“不ok”;然后,对于标记上的每个属性,检查该属性是否已存在于打开元素堆栈 上的第二个元素(body 元素)上,如果没有,则将该属性及其对应的值添加到该元素。

一个开始标记,其标记名为 "frameset"

解析错误.

如果打开元素堆栈 只有一个节点,或者如果打开元素堆栈 上的第二个元素不是一个body 元素,则忽略此标记。(片段情况 或者堆栈上有一个template 元素)

如果frameset-ok 标记 设置为“不ok”,则忽略此标记。

否则,执行以下步骤

  1. 从其父节点(如果有)中删除打开元素堆栈 上的第二个元素。

  2. 打开元素堆栈 的底部弹出所有节点,从当前节点 弹出到但不包括根html 元素。

  3. 为该标记插入一个 HTML 元素

  4. 插入模式 切换到“frameset 中”。

文件结束标记

如果模板插入模式堆栈 不为空,则使用“模板中插入模式 的规则来处理该标记。

否则,执行以下步骤

  1. 如果打开元素堆栈 中有一个节点既不是一个dd 元素,也不是一个dt 元素,也不是一个li 元素,也不是一个optgroup 元素,也不是一个option 元素,也不是一个p 元素,也不是一个rb 元素,也不是一个rp 元素,也不是一个rt 元素,也不是一个rtc 元素,也不是一个tbody 元素,也不是一个td 元素,也不是一个tfoot 元素,也不是一个th 元素,也不是一个thead 元素,也不是一个tr 元素,也不是body 元素,也不是html 元素,则这是一个解析错误

  2. 停止解析.

一个结束标记,其标记名称为“body”

如果打开元素堆栈 没有一个body 元素在范围内,则这是一个解析错误;忽略此标记。

否则,如果打开元素堆栈 中有一个节点既不是一个dd 元素,也不是一个dt 元素,也不是一个li 元素,也不是一个optgroup 元素,也不是一个option 元素,也不是一个p 元素,也不是一个rb 元素,也不是一个rp 元素,也不是一个rt 元素,也不是一个rtc 元素,也不是一个tbody 元素,也不是一个td 元素,也不是一个tfoot 元素,也不是一个th 元素,也不是一个thead 元素,也不是一个tr 元素,也不是body 元素,也不是html 元素,则这是一个解析错误

插入模式 切换到“body 之后”。

一个结束标记,其标记名称为“html”

如果打开元素堆栈 没有一个body 元素在范围内,则这是一个解析错误;忽略此标记。

否则,如果打开元素堆栈 中有一个节点既不是一个dd 元素,也不是一个dt 元素,也不是一个li 元素,也不是一个optgroup 元素,也不是一个option 元素,也不是一个p 元素,也不是一个rb 元素,也不是一个rp 元素,也不是一个rt 元素,也不是一个rtc 元素,也不是一个tbody 元素,也不是一个td 元素,也不是一个tfoot 元素,也不是一个th 元素,也不是一个thead 元素,也不是一个tr 元素,也不是body 元素,也不是html 元素,则这是一个解析错误

插入模式 切换到“body 之后”。

重新处理该标记。

一个开始标记,其标记名称为以下之一:“address”,"article","aside","blockquote","center","details","dialog","dir","div","dl","fieldset","figcaption","figure","footer","header","hgroup","main","menu","nav","ol","p","search","section","summary","ul"

如果打开元素堆栈 有一个p 元素在按钮范围内,则关闭一个p 元素

为该标记插入一个 HTML 元素

一个开始标记,其标记名称为以下之一:“h1”,"h2","h3","h4","h5","h6"

如果打开元素堆栈 有一个p 元素在按钮范围内,则关闭一个p 元素

如果当前节点 是一个HTML 元素,其标记名称为以下之一:“h1”,"h2","h3","h4","h5","h6",则这是一个解析错误;将当前节点打开元素堆栈 中弹出。

为该标记插入一个 HTML 元素

一个开始标记,其标记名称为以下之一:“pre”,"listing"

如果打开元素堆栈 有一个p 元素在按钮范围内,则关闭一个p 元素

为该标记插入一个 HTML 元素

如果下一个标记 是一个 U+000A LINE FEED (LF) 字符标记,则忽略该标记并继续处理下一个标记。(pre 块开头的换行符被忽略,作为一种作者便利。)

frameset-ok 标记 设置为“不ok”。

一个开始标记,其标记名称为“form”

如果form 元素指针 不为空,并且打开元素堆栈 上没有template 元素,则这是一个解析错误;忽略此标记。

否则

如果打开元素堆栈 有一个p 元素在按钮范围内,则关闭一个p 元素

插入 HTML 元素 用于该标记,并且如果 打开元素栈 上没有 模板 元素,则将 form 元素指针 设置为指向创建的元素。

开始标记,其标记名称为“li”。

运行以下步骤

  1. frameset-ok 标志 设置为“不 ok”。

  2. node 初始化为 当前节点(栈中最底部的节点)。

  3. 循环:如果 node 是一个 li 元素,则执行以下子步骤

    1. 生成隐式结束标记,除了 li 元素。

    2. 如果 当前节点 不是一个 li 元素,则这是一个 解析错误

    3. 打开元素栈 弹出元素,直到从栈中弹出一个 li 元素。

    4. 跳转到下面标记为完成的步骤。

  4. 如果 node 属于 特殊 类别,但不是 addressdivp 元素,则跳转到下面标记为完成的步骤。

  5. 否则,将 node 设置为 打开元素栈 中的前一个条目,并返回到标记为循环的步骤。

  6. 完成:如果 打开元素栈 在按钮作用域中包含一个p 元素,则 关闭一个p 元素

  7. 最后,插入 HTML 元素 用于该标记。

开始标记,其标记名称是以下之一:“dd”、"dt"

运行以下步骤

  1. frameset-ok 标志 设置为“不 ok”。

  2. node 初始化为 当前节点(栈中最底部的节点)。

  3. 循环:如果 node 是一个 dd 元素,则执行以下子步骤

    1. 生成隐式结束标记,除了 dd 元素。

    2. 如果 当前节点 不是一个 dd 元素,则这是一个 解析错误

    3. 打开元素栈 弹出元素,直到从栈中弹出一个 dd 元素。

    4. 跳转到下面标记为完成的步骤。

  4. 如果 node 是一个 dt 元素,则执行以下子步骤

    1. 生成隐式结束标记,除了 dt 元素。

    2. 如果 当前节点 不是一个 dt 元素,则这是一个 解析错误

    3. 打开元素栈 弹出元素,直到从栈中弹出一个 dt 元素。

    4. 跳转到下面标记为完成的步骤。

  5. 如果 node 属于 特殊 类别,但不是 addressdivp 元素,则跳转到下面标记为完成的步骤。

  6. 否则,将 node 设置为 打开元素栈 中的前一个条目,并返回到标记为循环的步骤。

  7. 完成:如果 打开元素栈 在按钮作用域中包含一个p 元素,则 关闭一个p 元素

  8. 最后,插入 HTML 元素 用于该标记。

开始标记,其标记名称为“plaintext”。

如果 打开元素栈 在按钮作用域中包含一个p 元素,则 关闭一个p 元素

插入 HTML 元素 用于该标记。

将标记器切换到 纯文本状态

一旦看到了标记名称为“plaintext”的开始标记,所有剩余的标记将是字符标记(以及最终的文件结束标记),因为无法将标记器从 纯文本状态 切换出去。但是,由于树构建器仍然处于其现有的插入模式,它可能会 重建活动格式化元素,同时处理这些字符标记。这意味着解析器可以将其他元素插入到 plaintext 元素中。

开始标记,其标记名称为“button”。
  1. 如果 打开元素栈 在作用域中包含一个button 元素,则执行以下子步骤

    1. 解析错误.

    2. 生成隐式结束标记.

    3. 打开元素栈 弹出元素,直到从栈中弹出一个 button 元素。

  2. 重建活动格式化元素,如果有的话。

  3. 插入 HTML 元素 用于该标记。

  4. frameset-ok 标志 设置为“不 ok”。

结束标记,其标记名称是以下之一:“address”、"article"、"aside"、"blockquote"、"button"、"center"、"details"、"dialog"、"dir"、"div"、"dl"、"fieldset"、"figcaption"、"figure"、"footer"、"header"、"hgroup"、"listing"、"main"、"menu"、"nav"、"ol"、"pre"、"search"、"section"、"summary"、"ul"

如果 打开元素栈在作用域中包含 一个与标记相同标记名称的 HTML 元素,则这是一个 解析错误;忽略该标记。

否则,运行以下步骤

  1. 生成隐式结束标记.

  2. 如果 当前节点 不是一个与标记相同标记名称的 HTML 元素,则这是一个 解析错误

  3. 打开元素栈 弹出元素,直到从栈中弹出一个与标记相同标记名称的 HTML 元素

结束标记,其标记名称为“form”。

如果 打开元素栈 上没有 模板 元素,则执行以下子步骤

  1. nodeform 元素指针 设置的元素,如果未设置为元素,则为 null。

  2. form 元素指针 设置为 null。

  3. 如果 node 为 null 或 打开元素栈在作用域中包含 node,则这是一个 解析错误;返回并忽略该标记。

  4. 生成隐式结束标记.

  5. 如果 当前节点 不是 node,则这是一个 解析错误

  6. 打开元素栈 中删除 node

如果 打开元素栈 模板 元素,则改为执行以下子步骤

  1. 如果 打开元素栈在作用域中包含一个form 元素,则这是一个 解析错误;返回并忽略该标记。

  2. 生成隐式结束标记.

  3. 如果 当前节点 不是一个 form 元素,则这是一个 解析错误

  4. 打开元素栈 弹出元素,直到从栈中弹出一个 form 元素。

结束标记,其标记名称为“p”。

如果 打开元素栈在按钮作用域中包含一个p 元素,则这是一个 解析错误插入 HTML 元素 用于没有属性的“p”开始标记标记。

关闭一个p 元素.

结束标记,其标记名称为“li”。

如果 打开元素栈在列表项作用域中包含一个li 元素,则这是一个 解析错误;忽略该标记。

否则,运行以下步骤

  1. 生成隐式结束标记,除了 li 元素。

  2. 如果 当前节点 不是一个 li 元素,则这是一个 解析错误

  3. 打开元素栈中弹出元素,直到一个li元素从栈中弹出。

结束标签,其标签名称为以下之一:"dd"、"dt"

如果打开元素栈包含作用域内的元素,该元素是与标记具有相同标签名称的HTML 元素,则这是一个解析错误;忽略标记。

否则,运行以下步骤

  1. 生成隐式结束标签,除了与标记具有相同标签名称的HTML 元素

  2. 如果当前节点不是与标记具有相同标签名称的HTML 元素,则这是一个解析错误

  3. 打开元素栈中弹出元素,直到一个与标记具有相同标签名称的HTML 元素从栈中弹出。

结束标签,其标签名称为以下之一:"h1"、"h2"、"h3"、"h4"、"h5"、"h6"

如果打开元素栈包含作用域内的元素,该元素是HTML 元素,其标签名称为 "h1"、"h2"、"h3"、"h4"、"h5" 或 "h6" 中的其中之一,则这是一个解析错误;忽略标记。

否则,运行以下步骤

  1. 生成隐式结束标记.

  2. 如果当前节点不是与标记具有相同标签名称的HTML 元素,则这是一个解析错误

  3. 打开元素栈中弹出元素,直到一个标签名称为 "h1"、"h2"、"h3"、"h4"、"h5" 或 "h6" 的HTML 元素从栈中弹出。

结束标签,其标签名称为 "sarcasm"

深呼吸,然后按照下面 "其他结束标签" 条目中描述的操作进行。

起始标签,其标签名称为 "a"

如果活动格式化元素列表在列表末尾和列表上的最后一个标记(或如果列表上没有标记,则为列表开头)之间包含一个a元素,则这是一个解析错误;针对标记运行收养机构算法,然后从活动格式化元素列表打开元素栈中删除该元素(如果收养机构算法尚未删除它,则可能不会删除它(如果元素不在表格作用域中)。

在非标准流<a href="a">a<table><a href="b">b</table>x中,第一个a元素将在看到第二个元素时关闭,而 "x" 字符将位于指向 "b" 的链接内,而不是指向 "a" 的链接内。这是因为外部a元素不在表格作用域中(这意味着表格开头的常规</a>结束标签不会关闭外部a元素)。结果是,两个a元素间接地彼此嵌套 — 非标准标记在解析时通常会产生非标准 DOM。

重建活动格式化元素(如果有)。

插入 HTML 元素,用于标记。将该元素推送到活动格式化元素列表中。

起始标签,其标签名称为以下之一:"b"、"big"、"code"、"em"、"font"、"i"、"s"、"small"、"strike"、"strong"、"tt"、"u"

重建活动格式化元素(如果有)。

插入 HTML 元素,用于标记。将该元素推送到活动格式化元素列表中。

起始标签,其标签名称为 "nobr"

重建活动格式化元素(如果有)。

如果打开元素栈包含作用域内的 nobr 元素,则这是一个解析错误;针对标记运行收养机构算法,然后再次重建活动格式化元素(如果有)。

插入 HTML 元素,用于标记。将该元素推送到活动格式化元素列表中。

结束标签,其标签名称为以下之一:"a"、"b"、"big"、"code"、"em"、"font"、"i"、"nobr"、"s"、"small"、"strike"、"strong"、"tt"、"u"

针对标记运行收养机构算法

起始标签,其标签名称为以下之一:"applet"、"marquee"、"object"

重建活动格式化元素(如果有)。

插入 HTML 元素,用于标记。

活动格式化元素列表的末尾插入一个标记

frameset-ok 标志设置为 "not ok"。

结束标签标记,其标签名称为以下之一:"applet"、"marquee"、"object"

如果打开元素栈包含作用域内的元素,该元素是与标记具有相同标签名称的HTML 元素,则这是一个解析错误;忽略标记。

否则,运行以下步骤

  1. 生成隐式结束标记.

  2. 如果当前节点不是与标记具有相同标签名称的HTML 元素,则这是一个解析错误

  3. 打开元素栈中弹出元素,直到一个与标记具有相同标签名称的HTML 元素从栈中弹出。

  4. 清除活动格式化元素列表,直到最后一个标记。.
起始标签,其标签名称为 "table"

如果文档设置为怪异模式,并且打开元素栈包含按钮作用域内的 p 元素,则关闭 p 元素

插入 HTML 元素,用于标记。

frameset-ok 标志设置为 "not ok"。

插入模式切换到 "表格内"。

一个结束标记,其标记名为 "br"

解析错误。从标记中删除属性,并按照下一条目的描述进行操作;即,假设这是一个没有属性的 "br" 起始标签标记,而不是它实际的结束标签标记。

起始标签,其标签名称为以下之一:"area"、"br"、"embed"、"img"、"keygen"、"wbr"

重建活动格式化元素(如果有)。

插入 HTML 元素,用于标记。立即从打开元素栈中弹出当前节点

确认标记的自闭合标志(如果设置)。

frameset-ok 标志设置为 "not ok"。

起始标签,其标签名称为 "input"

重建活动格式化元素(如果有)。

插入 HTML 元素,用于标记。立即从打开元素栈中弹出当前节点

确认标记的自闭合标志(如果设置)。

如果标记没有名为 "type" 的属性,或者有,但该属性的值与字符串 "hidden" 的ASCII 不区分大小写匹配,则:将frameset-ok 标志设置为 "not ok"。

起始标签,其标签名称为以下之一:"param"、"source"、"track"

插入 HTML 元素,用于标记。立即从打开元素栈中弹出当前节点

确认标记的自闭合标志(如果设置)。

起始标签,其标签名称为 "hr"

如果打开元素栈包含按钮作用域内的 p 元素,则关闭 p 元素

插入 HTML 元素,用于标记。立即从打开元素栈中弹出当前节点

确认标记的自闭合标志,如果已设置。

frameset-ok 标志设置为“不正常”。

一个标签名为“image”的开始标签

解析错误。将标记的标签名更改为“img”并重新处理它。(别问。)

一个标签名为“textarea”的开始标签

运行以下步骤

  1. 插入一个 HTML 元素 用于该标记。

  2. 如果下一个标记是 U+000A LINE FEED (LF) 字符标记,则忽略该标记并继续处理下一个标记。(在textarea 元素开头的新行被忽略,作为作者的便利。)

  3. 将标记器切换到RCDATA 状态

  4. 原始插入模式成为当前的插入模式

  5. frameset-ok 标志设置为“不正常”。

  6. 插入模式切换到“文本”。

一个标签名为“xmp”的开始标签

如果打开元素栈在按钮范围内包含一个p 元素,则关闭一个p 元素

重建活动格式化元素,如果有。

frameset-ok 标志设置为“不正常”。

遵循通用原始文本元素解析算法

一个标签名为“iframe”的开始标签

frameset-ok 标志设置为“不正常”。

遵循通用原始文本元素解析算法

一个标签名为“noembed”的开始标签
一个标签名为“noscript”的开始标签,如果脚本标志已启用

遵循通用原始文本元素解析算法

一个标签名为“select”的开始标签

重建活动格式化元素,如果有。

插入一个 HTML 元素 用于该标记。

frameset-ok 标志设置为“不正常”。

如果插入模式是“在表格中”,“在标题中”,“在表格主体中”,“在行中”或“在单元格中”之一,则将插入模式切换到“在表格中的 select 中”。否则,将插入模式切换到“在 select 中”。

一个标签名是“optgroup”或“option”之一的开始标签

如果当前节点是一个option 元素,则从打开元素栈中弹出当前节点

重建活动格式化元素,如果有。

插入一个 HTML 元素 用于该标记。

一个标签名是“rb”或“rtc”之一的开始标签

如果打开元素栈在范围内包含一个ruby 元素,则生成隐式结束标签。如果当前节点现在不是一个ruby 元素,则这是一个解析错误

插入一个 HTML 元素 用于该标记。

一个标签名是“rp”或“rt”之一的开始标签

如果打开元素栈在范围内包含一个ruby 元素,则生成隐式结束标签,除了rtc 元素。如果当前节点现在不是一个rtc 元素或一个ruby 元素,则这是一个解析错误

插入一个 HTML 元素 用于该标记。

一个标签名为“math”的开始标签

重建活动格式化元素,如果有。

调整 MathML 属性 用于该标记。(这修复了不是全部小写的 MathML 属性的情况。)

调整外来属性 用于该标记。(这修复了命名空间属性的使用,尤其是 XLink。)

插入一个外来元素 用于该标记,带有MathML 命名空间 和 false。

如果标记的自闭合标志 已设置,则从打开元素栈中弹出当前节点,并确认标记的自闭合标志

一个标签名为“svg”的开始标签

重建活动格式化元素,如果有。

调整 SVG 属性 用于该标记。(这修复了不是全部小写的 SVG 属性的情况。)

调整外来属性 用于该标记。(这修复了命名空间属性的使用,尤其是 SVG 中的 XLink。)

插入一个外来元素 用于该标记,带有SVG 命名空间 和 false。

如果标记的自闭合标志 已设置,则从打开元素栈中弹出当前节点,并确认标记的自闭合标志

一个标签名是“caption”,“col”,“colgroup”,“frame”,“head”,“tbody”,“td”,“tfoot”,“th”,“thead”,“tr”之一的开始标签

解析错误。忽略该标记。

任何其他开始标签

重建活动格式化元素,如果有。

插入一个 HTML 元素 用于该标记。

此元素将是一个普通 元素。有一个例外:如果脚本标志已禁用,它也可以是一个noscript 元素。

任何其他结束标签

运行以下步骤

  1. node 初始化为当前节点(栈的最底部节点)。

  2. 循环:如果node 是一个HTML 元素,其标签名与标记相同,则

    1. 生成隐式结束标签,除了HTML 元素,其标签名与标记相同。

    2. 如果node 不是当前节点,则这是一个解析错误

    3. 当前节点一直弹出到node,包括node,然后停止这些步骤。

  3. 否则,如果node 位于特殊 类别中,则这是一个解析错误;忽略该标记,并返回。

  4. node 设置为打开元素栈 中的上一项。

  5. 返回到标记为 loop 的步骤。

当上面的步骤说用户代理要关闭一个p 元素 时,这意味着用户代理必须执行以下步骤

  1. 生成隐式结束标签,除了p 元素。

  2. 如果当前节点不是一个p 元素,则这是一个解析错误

  3. 打开元素栈 中弹出元素,直到从栈中弹出一个p 元素。

收养机构算法,它以一个标记token 作为其唯一参数,该算法正在运行,它包含以下步骤

  1. subjecttoken 的标签名。

  2. 如果当前节点 是一个HTML 元素,其标签名是subject,并且当前节点 不在活动格式化元素列表 中,则从打开元素栈 中弹出当前节点 并返回。

  3. outerLoopCounter 为 0。

  4. 当真时

    1. 如果outerLoopCounter 大于或等于 8,则返回。

    2. outerLoopCounter 增加 1。

    3. formattingElement活动格式化元素列表 中的最后一个元素,它

      • 位于列表末尾和列表中最后一个标记 之间,如果有,否则位于列表开头,并且
      • 具有标签名subject

      如果没有这样的元素,则返回,并改为按照上面“任何其他结束标签”条目中所述进行操作。

    4. 如果formattingElement 不在打开元素栈 中,则这是一个解析错误;从列表中删除该元素,并返回。

    5. 如果 `formattingElement` 在 `已打开元素堆栈` 中,但元素不在 `作用域中`,那么这是一个 `解析错误`;返回。

    6. 如果 `formattingElement` 不是 `当前节点`,那么这是一个 `解析错误`。(但不要返回。)

    7. 设 `furthestBlock` 为 `已打开元素堆栈` 中最顶层的节点,该节点在堆栈中比 `formattingElement` 低,并且是 `特殊` 类别中的元素。可能不存在。

    8. 如果没有 `furthestBlock`,那么 UA 必须首先从 `已打开元素堆栈` 的底部弹出所有节点,从 `当前节点` 开始,直到并包括 `formattingElement`,然后从 `活动格式化元素列表` 中删除 `formattingElement`,最后返回。

    9. 设 `commonAncestor` 为 `已打开元素堆栈` 中 `formattingElement` 上方的元素。

    10. 设一个书签标记 `formattingElement` 在 `活动格式化元素列表` 中的位置,相对于列表中它两侧的元素。

    11. 设 `node` 和 `lastNode` 为 `furthestBlock`。

    12. 设 `innerLoopCounter` 为 0。

    13. 当真时

      1. 将 `innerLoopCounter` 加 1。

      2. 设 `node` 为 `已打开元素堆栈` 中 `node` 上方的元素,或者如果 `node` 不再在 `已打开元素堆栈` 中(例如,因为它被此算法删除),则在 `node` 被删除之前,`已打开元素堆栈` 中 `node` 上方的元素。

      3. 如果 `node` 是 `formattingElement`,那么 `中断`。

      4. 如果 `innerLoopCounter` 大于 3 且 `node` 在 `活动格式化元素列表` 中,那么从 `活动格式化元素列表` 中删除 `node`。

      5. 如果 `node` 不在 `活动格式化元素列表` 中,那么从 `已打开元素堆栈` 中删除 `node` 并 `继续`。

      6. 为创建元素 `node` 的标记 `创建元素`,在 `HTML 命名空间` 中,使用 `commonAncestor` 作为预期父级;用新元素的条目替换 `活动格式化元素列表` 中 `node` 的条目,用新元素的条目替换 `已打开元素堆栈` 中 `node` 的条目,并设 `node` 为新元素。

      7. 如果 `last node` 是 `furthestBlock`,那么将上述书签移动到 `活动格式化元素列表` 中新 `node` 的紧后面。

      8. 将 `lastNode` `追加` 到 `node`。

      9. 将 `lastNode` 设为 `node`。

    14. 将上一步骤中 `lastNode` 最终成为的元素插入 `插入节点的适当位置`,但使用 `commonAncestor` 作为 _覆盖目标_。

    15. 为创建 `formattingElement` 的标记 `创建元素`,在 `HTML 命名空间` 中,使用 `furthestBlock` 作为预期父级。

    16. 获取 `furthestBlock` 的所有子节点,并将它们追加到上一步骤中创建的元素。

    17. 将该新元素追加到 `furthestBlock`。

    18. 从 `活动格式化元素列表` 中删除 `formattingElement`,并将新元素插入 `活动格式化元素列表` 中上述书签的位置。

    19. 从 `已打开元素堆栈` 中删除 `formattingElement`,并将新元素插入 `已打开元素堆栈` 中 `furthestBlock` 在该堆栈中的位置的紧下方。

此算法的名称“收养机构算法”源于它导致元素更改父级的方式,并且与 `其他可能的算法` 对处理嵌套错误的内容形成对比。

13.2.6.4.8文本”插入模式

当用户代理要应用“`文本`”`插入模式` 的规则时,用户代理必须按如下方式处理标记

字符标记

插入该标记的字符.

这永远不可能是 U+0000 NULL 字符;标记器将这些字符转换为 U+FFFD REPLACEMENT CHARACTER 字符。

文件结束标记

解析错误.

如果 `当前节点` 是 `script 元素,那么将它的 `已经开始` 设为 true。

从 `已打开元素堆栈` 中弹出 `当前节点`。

将 `插入模式` 切换到 `原始插入模式`,并重新处理标记。

结束标记,其标记名称为“script”

如果 `活动推测性 HTML 解析器` 为 null,且 `JavaScript 执行上下文堆栈` 为空,那么 `执行微任务检查点`。

设 `script` 为 `当前节点`(它将是 `script 元素)。

从 `已打开元素堆栈` 中弹出 `当前节点`。

将 `插入模式` 切换到 `原始插入模式`。

设 `旧插入点` 的值与当前 `插入点` 的值相同。设 `插入点` 为 `下一个输入字符` 的正前方。

将解析器的 `脚本嵌套级别` 加 1。

如果 `活动推测性 HTML 解析器` 为 null,那么 `准备脚本元素` `script`。这可能会导致某些脚本执行,这可能会导致 `将新字符插入标记器`,并且可能会导致标记器输出更多标记,从而导致 `解析器重新进入调用`。

将解析器的 `脚本嵌套级别` 减 1。如果解析器的 `脚本嵌套级别` 为零,那么将 `解析器暂停标志` 设为 false。

设 `插入点` 的值为 `旧插入点`。(换句话说,将 `插入点` 恢复为它的先前值。此值可能是“undefined”值。)

在此阶段,如果 `挂起的解析阻塞脚本` 不为 null,那么

如果 `脚本嵌套级别` 不为零

将 `解析器暂停标志` 设为 true,并中止对标记器任何嵌套调用的处理,将控制权交回调用者。(当调用者返回到“外部”树构建阶段时,标记将恢复。)

此特定解析器的树构建阶段 `正在被重新进入调用`,例如,从对 `document.write() 的调用进行调用。

否则

当 `挂起的解析阻塞脚本` 不为 null 时

  1. 设 `脚本` 为 `挂起的解析阻塞脚本`。

  2. 将 `挂起的解析阻塞脚本` 设为 null。

  3. 为 HTML 解析器的此实例 `启动推测性 HTML 解析器`。

  4. 阻塞 HTML 解析器的此实例的 `标记器`,以便 `事件循环` 不会运行调用 `标记器` 的 `任务`。

  5. 如果解析器的 `Document `有阻止脚本的样式表` 或 `脚本` 的 `准备好被解析器执行` 为 false:`循环运行事件循环`,直到解析器的 `Document `没有阻止脚本的样式表`,且 `脚本` 的 `准备好被解析器执行` 变成 true。

  6. 如果此 `解析器已被中止`,那么返回。

    这可能会发生,例如,当 `循环运行事件循环` 算法正在运行时,`Document 被 `销毁`,或者在 `Document 上调用了 `document.open() 方法。

  7. 为 HTML 解析器的此实例 `停止推测性 HTML 解析器`。

  8. 解除对标记器的阻止,该标记器用于此HTML解析器实例,以便可以再次运行调用标记器任务

  9. 插入点位于下一个输入字符之前。

  10. 将解析器的脚本嵌套级别增加一(在这一步之前,它应该为零,因此这将其设置为一)。

  11. 执行脚本元素the script执行脚本元素

  12. 将解析器的脚本嵌套级别减少一。如果解析器的脚本嵌套级别为零(此时始终应该为零),则将解析器暂停标志设置为 false。

  13. 插入点再次变为未定义。

任何其他结束标签

打开元素堆栈中弹出当前节点

插入模式切换到原始插入模式

13.2.6.4.9in table” 插入模式

当用户代理需要应用“in table插入模式的规则时,用户代理必须按如下方式处理标记

字符标记,如果当前节点tabletbodytemplatetfoottheadtr元素

pending table character tokens成为一个空的标记列表。

原始插入模式成为当前的插入模式

插入模式切换到“in table text”并重新处理标记。

一个注释标记

插入一个注释.

一个 DOCTYPE 标记

解析错误。忽略标记。

一个开始标记,其标记名称为“caption”。

将堆栈清除到表格上下文。(见下文。)

活动格式化元素列表的末尾插入一个标记

为标记插入一个 HTML 元素,然后将插入模式切换到“in caption”。

一个开始标记,其标记名称为“colgroup”。

将堆栈清除到表格上下文。(见下文。)

为标记插入一个 HTML 元素,然后将插入模式切换到“in column group”。

一个开始标记,其标记名称为“col”。

将堆栈清除到表格上下文。(见下文。)

为一个没有属性的“colgroup”开始标记标记插入一个 HTML 元素,然后将插入模式切换到“in column group”。

重新处理当前标记。

一个开始标记,其标记名称为以下之一:“tbody”、“tfoot”、“thead”。

将堆栈清除到表格上下文。(见下文。)

为标记插入一个 HTML 元素,然后将插入模式切换到“in table body”。

一个开始标记,其标记名称为以下之一:“td”、“th”、“tr”。

将堆栈清除到表格上下文。(见下文。)

为一个没有属性的“tbody”开始标记标记插入一个 HTML 元素,然后将插入模式切换到“in table body”。

重新处理当前标记。

起始标签,其标签名称为 "table"

解析错误.

如果打开元素堆栈在表格范围内没有table元素,则忽略标记。

否则

从该堆栈中弹出元素,直到从堆栈中弹出一个table元素为止。

适当地重置插入模式.

重新处理该标记。

一个结束标记,其标记名称为“table”。

如果打开元素堆栈在表格范围内没有table元素,则这是一个解析错误;忽略标记。

否则

从该堆栈中弹出元素,直到从堆栈中弹出一个table元素为止。

适当地重置插入模式.

一个结束标记,其标记名称为以下之一:“body”、“caption”、“col”、“colgroup”、“html”、“tbody”、“td”、“tfoot”、“th”、“thead”、“tr”。

解析错误。忽略标记。

一个开始标记,其标记名称为以下之一:“style”、“script”、“template”。
一个结束标记,其标记名为 "template"

使用in head 插入模式的规则处理标记

起始标签,其标签名称为 "input"

如果标记没有名为“type”的属性,或者有,但该属性的值与字符串“hidden不区分大小写匹配,则:按照下面“其他任何情况”条目中描述的进行操作。

否则

解析错误.

为标记插入一个 HTML 元素

打开元素堆栈中弹出input元素。

如果设置了标记的自闭合标志,则确认标记的自闭合标志

一个开始标记,其标记名称为“form”

解析错误.

如果打开元素堆栈上有template元素,或者form元素指针不为空,则忽略标记。

否则

为标记插入一个 HTML 元素,并将form元素指针设置为指向创建的元素。

打开元素堆栈中弹出form元素。

文件结束标记

使用in body 插入模式的规则处理标记

任何其他情况

解析错误。启用寄养父级,使用in body 插入模式的规则处理标记,然后禁用寄养父级

当上面的步骤要求 UA 将堆栈清除到表格上下文时,这意味着 UA 必须在当前节点不是tabletemplatehtml元素时,从打开元素堆栈中弹出元素。

这与在表格范围内存在元素步骤中使用的元素列表相同。

在这个过程之后,当前节点成为一个html元素,这是一个片段情况

13.2.6.4.10in table text” 插入模式

当用户代理需要应用“in table text插入模式的规则时,用户代理必须按如下方式处理标记

一个字符标记,其为 U+0000 NULL

解析错误。忽略标记。

任何其他字符标记

将字符标记追加到pending table character tokens列表。

任何其他情况

如果pending table character tokens列表中的任何标记是字符标记,且这些字符标记不是ASCII 空格,则这是一个解析错误:使用“in table”插入模式中的“其他任何情况”条目中给出的规则重新处理pending table character tokens列表中的字符标记。

否则,插入pending table character tokens列表给出的字符。

插入模式切换到原始插入模式并重新处理标记。

13.2.6.4.11in caption” 插入模式

当用户代理需要应用“in caption插入模式的规则时,用户代理必须按如下方式处理标记

一个结束标记,其标记名称为“caption”。

如果打开元素堆栈在表格范围内没有caption元素,则这是一个解析错误;忽略标记。(片段情况

否则

生成隐式结束标记.

现在,如果当前节点不是一个caption元素,则这是一个解析错误

从该栈中弹出元素,直到从栈中弹出 caption 元素。

清除活动格式化元素列表,直到最后一个标记。.

插入模式 切换为 "in table"。

标签名称为以下之一的开始标签:"caption"、"col"、"colgroup"、"tbody"、"td"、"tfoot"、"th"、"thead"、"tr"
一个结束标记,其标记名称为“table”。

如果 打开元素栈 中没有 在表格作用域中包含 caption 元素,则这是一个 解析错误;忽略此标记。(片段情况

否则

生成隐式结束标记.

现在,如果 当前节点 不是 caption 元素,则这是一个 解析错误

从该栈中弹出元素,直到从栈中弹出 caption 元素。

清除活动格式化元素列表,直到最后一个标记。.

插入模式 切换为 "in table"。

重新处理该标记。

标签名称为以下之一的结束标签:"body"、"col"、"colgroup"、"html"、"tbody"、"td"、"tfoot"、"th"、"thead"、"tr"

解析错误。忽略此标记。

任何其他情况

使用 "in body" 插入模式 的规则处理此标记。 使用该规则

13.2.6.4.12 "in column group" 插入模式

当用户代理要应用 "in column group" 插入模式 的规则时,用户代理必须按如下方式处理此标记。

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

插入字符.

一个注释标记

插入一个注释.

一个 DOCTYPE 标记

解析错误。忽略此标记。

一个起始标签,其标签名称为 "html"

使用 "in body" 插入模式 的规则处理此标记。 使用该规则

一个开始标记,其标记名称为“col”。

插入 HTML 元素 用于此标记。立即从 打开元素栈 中弹出 当前节点

确认此标记的 自闭合标志,如果它已设置。

标签名称为 "colgroup" 的结束标签

如果 当前节点 不是 colgroup 元素,则这是一个 解析错误;忽略此标记。

否则,从 打开元素栈 中弹出 当前节点。将 插入模式 切换为 "in table"。

标签名称为 "col" 的结束标签

解析错误。忽略此标记。

一个其标记名称为“template”的开始标记
一个结束标记,其标记名为 "template"

使用 "in head" 插入模式 的规则处理此标记。 使用该规则

文件结束标记

使用 "in body" 插入模式 的规则处理此标记。 使用该规则

任何其他情况

如果 当前节点 不是 colgroup 元素,则这是一个 解析错误;忽略此标记。

否则,从 打开元素栈 中弹出 当前节点

插入模式 切换为 "in table"。

重新处理该标记。

13.2.6.4.13 "in table body" 插入模式

当用户代理要应用 "in table body" 插入模式 的规则时,用户代理必须按如下方式处理此标记。

标签名称为 "tr" 的开始标签

将栈清除回表格正文上下文。(参见下文。)

插入 HTML 元素 用于此标记,然后将 插入模式 切换为 "in row"。

标签名称为以下之一的开始标签:"th"、"td"

解析错误.

将栈清除回表格正文上下文。(参见下文。)

插入 HTML 元素 用于一个没有属性的 "tr" 开始标签标记,然后将 插入模式 切换为 "in row"。

重新处理当前标记。

标签名称为以下之一的结束标签:"tbody"、"tfoot"、"thead"

如果 打开元素栈 中没有 在表格作用域中包含 与此标记标签名称相同的 HTML 元素,则这是一个 解析错误;忽略此标记。

否则

将栈清除回表格正文上下文。(参见下文。)

打开元素栈 中弹出 当前节点。将 插入模式 切换为 "in table"。

标签名称为以下之一的开始标签:"caption"、"col"、"colgroup"、"tbody"、"tfoot"、"thead"
一个结束标记,其标记名称为“table”。

如果 打开元素栈 中没有 在表格作用域中包含 tbodytheadtfoot 元素,则这是一个 解析错误;忽略此标记。

否则

将栈清除回表格正文上下文。(参见下文。)

打开元素栈 中弹出 当前节点。将 插入模式 切换为 "in table"。

重新处理该标记。

标签名称为以下之一的结束标签:"body"、"caption"、"col"、"colgroup"、"html"、"td"、"th"、"tr"

解析错误。忽略此标记。

任何其他情况

使用 "in table" 插入模式 的规则处理此标记。 使用该规则

当上述步骤要求 UA 将栈清除回表格正文上下文 时,意味着 UA 必须,当 当前节点 不是 tbodytfoottheadtemplatehtml 元素时,从 打开元素栈 中弹出元素。

此过程后,当前节点html 元素是一个 片段情况

13.2.6.4.14 "in row" 插入模式

当用户代理要应用 "in row" 插入模式 的规则时,用户代理必须按如下方式处理此标记。

标签名称为以下之一的开始标签:"th"、"td"

将栈清除回表格行上下文。(参见下文。)

插入 HTML 元素 用于此标记,然后将 插入模式 切换为 "in cell"。

活动格式化元素列表 的末尾插入一个 标记

标签名称为 "tr" 的结束标签

如果 打开元素栈 中没有 在表格作用域中包含 tr 元素,则这是一个 解析错误;忽略此标记。

否则

将栈清除回表格行上下文。(参见下文。)

打开元素栈 中弹出 当前节点(它将是一个 tr 元素)。将 插入模式 切换为 "in table body"。

标签名称为以下之一的开始标签:"caption"、"col"、"colgroup"、"tbody"、"tfoot"、"thead"、"tr"
一个结束标记,其标记名称为“table”。

如果 打开元素栈 中没有 在表格作用域中包含 tr 元素,则这是一个 解析错误;忽略此标记。

否则

将栈清除回表格行上下文。(参见下文。)

打开元素栈 中弹出 当前节点(它将是一个 tr 元素)。将 插入模式 切换为 "in table body"。

重新处理该标记。

标签名称为以下之一的结束标签:"tbody"、"tfoot"、"thead"

如果打开元素栈没有在表格作用域中包含元素,该元素是一个与标记名称相同的HTML 元素,则这是一个解析错误;忽略此标记。

如果打开元素栈没有在表格作用域中包含一个tr元素,则忽略此标记。

否则

清除栈回到表格行上下文。(见下文)

打开元素栈中弹出当前节点(它将是一个tr元素)。将插入模式切换到“表格主体中”。

重新处理该标记。

结束标记的标记名称是以下之一:“body”、“caption”、“col”、“colgroup”、“html”、“td”、“th”

解析错误。忽略此标记。

任何其他情况

使用表格中插入模式的规则处理此标记。

当上述步骤要求UA清除栈回到表格行上下文时,这意味着UA必须在当前节点不是trtemplatehtml元素的情况下,从打开元素栈中弹出元素。

此过程完成后,当前节点是一个html元素,这是一个片段情况

13.2.6.4.15单元格中”插入模式

当用户代理需要应用“单元格中插入模式的规则时,用户代理必须按以下方式处理此标记

结束标记的标记名称是以下之一:“td”、“th”

如果打开元素栈没有在表格作用域中包含元素,该元素是一个与标记名称相同的HTML 元素,则这是一个解析错误;忽略此标记。

否则

生成隐式结束标记.

现在,如果当前节点不是一个与标记名称相同的HTML 元素,则这是一个解析错误

打开元素栈中弹出元素,直到弹出一个与标记名称相同的HTML 元素

清除活动格式化元素列表,直到最后一个标记。.

插入模式切换到“行中”。

标签名称为以下之一的开始标签:"caption"、"col"、"colgroup"、"tbody"、"td"、"tfoot"、"th"、"thead"、"tr"

断言打开元素栈在表格作用域中包含一个tdth元素

关闭单元格(见下文)并重新处理此标记。

结束标记的标记名称是以下之一:“body”、“caption”、“col”、“colgroup”、“html”

解析错误。忽略此标记。

结束标记的标记名称是以下之一:“table”、“tbody”、“tfoot”、“thead”、“tr”

如果打开元素栈没有在表格作用域中包含元素,该元素是一个与标记名称相同的HTML 元素,则这是一个解析错误;忽略此标记。

否则,关闭单元格(见下文)并重新处理此标记。

任何其他情况

使用主体中插入模式的规则处理此标记。

当上述步骤说要关闭单元格时,它们意味着要运行以下算法

  1. 生成隐式结束标记.

  2. 如果当前节点现在不是一个td元素或一个th元素,则这是一个解析错误

  3. 打开元素栈中弹出元素,直到弹出一个td元素或一个th元素。

  4. 清除活动格式化元素列表,直到最后一个标记。.

  5. 插入模式切换到“行中”。

打开元素栈不能同时在表格作用域中包含一个td和一个th元素,也不能在调用关闭单元格算法时同时包含两者。

13.2.6.4.16选择中”插入模式

当用户代理需要应用“选择中插入模式的规则时,用户代理必须按以下方式处理此标记

一个字符标记,其为 U+0000 NULL

解析错误。忽略此标记。

任何其他字符标记

插入该标记的字符.

一个注释标记

插入一个注释.

一个 DOCTYPE 标记

解析错误。忽略此标记。

一个起始标签,其标签名称为 "html"

使用主体中插入模式的规则处理此标记。

开始标记的标记名称是“option”

如果当前节点是一个option元素,则从打开元素栈中弹出该节点。

插入HTML 元素,以表示此标记。

开始标记的标记名称是“optgroup”

如果当前节点是一个option元素,则从打开元素栈中弹出该节点。

如果当前节点是一个optgroup元素,则从打开元素栈中弹出该节点。

插入HTML 元素,以表示此标记。

起始标签,其标签名称为 "hr"

如果当前节点是一个option元素,则从打开元素栈中弹出该节点。

如果当前节点是一个optgroup元素,则从打开元素栈中弹出该节点。

插入HTML 元素,以表示此标记。立即从打开元素栈中弹出当前节点

确认此标记的自闭合标记,如果已设置。

结束标记的标记名称是“optgroup”

首先,如果当前节点是一个option元素,并且打开元素栈中紧接其前的节点是一个optgroup元素,则从打开元素栈中弹出当前节点

如果当前节点是一个optgroup元素,则从打开元素栈中弹出该节点。否则,这是一个解析错误;忽略此标记。

结束标记的标记名称是“option”

如果当前节点是一个option元素,则从打开元素栈中弹出该节点。否则,这是一个解析错误;忽略此标记。

结束标记的标记名称是“select”

如果打开元素栈没有在选择作用域中包含一个select元素,则这是一个解析错误;忽略此标记。(片段情况

否则

打开元素栈中弹出元素,直到弹出一个select元素。

适当地重置插入模式.

一个标签名为“select”的开始标签

解析错误.

如果打开元素栈没有在选择作用域中包含一个select元素,则忽略此标记。(片段情况

否则

打开元素栈中弹出元素,直到弹出一个select元素。

适当地重置插入模式.

它将像结束标记一样被处理。

开始标记的标记名称是以下之一:“input”、“keygen”、“textarea”

解析错误.

如果 打开元素栈 没有 在选择范围中包含一个 select 元素,则忽略该标记。 (片段情况)

否则

打开元素栈 中弹出元素,直到一个 select 元素被弹出栈。

适当地重置插入模式.

重新处理该标记。

开始标签的标签名称为以下之一:"script","template"
一个结束标记,其标记名为 "template"

使用 针对 "在头部" 插入模式 的规则处理该标记。

文件结束标记

使用 针对 "在主体" 插入模式 的规则处理该标记。

任何其他情况

解析错误。忽略该标记。

13.2.6.4.17 "在表格中的选择" 插入模式

当用户代理要应用 "在表格中的选择" 插入模式 的规则时,用户代理必须按如下方式处理该标记。

开始标签的标签名称为以下之一:"caption","table","tbody","tfoot","thead","tr","td","th"

解析错误.

打开元素栈 中弹出元素,直到一个 select 元素被弹出栈。

适当地重置插入模式.

重新处理该标记。

结束标签的标签名称为以下之一:"caption","table","tbody","tfoot","thead","tr","td","th"

解析错误.

如果 打开元素栈 没有 在表格范围中包含一个 具有与该标记相同标签名称的 HTML 元素,则忽略该标记。

否则

打开元素栈 中弹出元素,直到一个 select 元素被弹出栈。

适当地重置插入模式.

重新处理该标记。

任何其他情况

使用 针对 "在选择" 插入模式 的规则处理该标记。

13.2.6.4.18 "在模板" 插入模式

当用户代理要应用 "在模板" 插入模式 的规则时,用户代理必须按如下方式处理该标记。

字符标记
一个注释标记
一个 DOCTYPE 标记

使用 针对 "在主体" 插入模式 的规则处理该标记。

一个开始标记,其标记名为以下之一:"base"、"basefont"、"bgsound"、"link"、"meta"、"noframes"、"script"、"style"、"template"、"title"
一个结束标记,其标记名为 "template"

使用 针对 "在头部" 插入模式 的规则处理该标记。

开始标签的标签名称为以下之一:"caption","colgroup","tbody","tfoot","thead"

模板插入模式栈 中弹出 当前模板插入模式

将 "在表格" 推入 模板插入模式栈,使其成为新的 当前模板插入模式

插入模式 切换为 "在表格",并重新处理该标记。

一个开始标记,其标记名称为“col”。

模板插入模式栈 中弹出 当前模板插入模式

将 "在列组" 推入 模板插入模式栈,使其成为新的 当前模板插入模式

插入模式 切换为 "在列组",并重新处理该标记。

标签名称为 "tr" 的开始标签

模板插入模式栈 中弹出 当前模板插入模式

将 "在表格主体" 推入 模板插入模式栈,使其成为新的 当前模板插入模式

插入模式 切换为 "在表格主体",并重新处理该标记。

开始标签的标签名称为以下之一:"td","th"

模板插入模式栈 中弹出 当前模板插入模式

将 "在行" 推入 模板插入模式栈,使其成为新的 当前模板插入模式

插入模式 切换为 "在行",并重新处理该标记。

任何其他开始标签

模板插入模式栈 中弹出 当前模板插入模式

将 "在主体" 推入 模板插入模式栈,使其成为新的 当前模板插入模式

插入模式 切换为 "在主体",并重新处理该标记。

任何其他结束标签

解析错误。忽略该标记。

文件结束标记

如果 打开元素栈 上没有 template 元素,则 停止解析。 (片段情况)

否则,这是一个 解析错误

打开元素栈 中弹出元素,直到一个 template 元素被弹出栈。

清除活动格式化元素列表,直到最后一个标记。.

模板插入模式栈 中弹出 当前模板插入模式

适当地重置插入模式.

重新处理该标记。

13.2.6.4.19 "主体之后" 插入模式

当用户代理要应用 "主体之后" 插入模式 的规则时,用户代理必须按如下方式处理该标记。

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

使用 针对 "在主体" 插入模式 的规则处理该标记。

一个注释标记

插入注释 作为 打开元素栈 中第一个元素(html 元素)的最后一个子元素。

一个 DOCTYPE 标记

解析错误。忽略该标记。

一个起始标签,其标签名称为 "html"

使用 针对 "在主体" 插入模式 的规则处理该标记。

一个结束标记,其标记名称为“html”

如果解析器是作为 HTML 片段解析算法 的一部分创建的,则这是一个 解析错误;忽略该标记。 (片段情况)

否则,将 插入模式 切换为 "主体之后"。

文件结束标记

停止解析.

任何其他情况

解析错误。将 插入模式 切换为 "在主体",并重新处理该标记。

13.2.6.4.20 "在框架集" 插入模式

当用户代理要应用 "在框架集" 插入模式 的规则时,用户代理必须按如下方式处理该标记。

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

插入字符.

一个注释标记

插入一个注释.

一个 DOCTYPE 标记

解析错误。忽略该标记。

一个起始标签,其标签名称为 "html"

使用 针对 "在主体" 插入模式 的规则处理该标记。

一个开始标记,其标记名为 "frameset"

插入 HTML 元素 用于该标记。

结束标签的标签名称为 "frameset"

如果 当前节点 是根 html 元素,则这是一个 解析错误;忽略该标记。 (片段情况)

否则,从 打开元素栈 中弹出 当前节点

如果解析器不是作为 HTML 片段解析算法 的一部分创建的 (片段情况),并且 当前节点 不再是 frameset 元素,则将 插入模式 切换为 "框架集之后"。

开始标签的标签名称为 "frame"

插入 HTML 元素 用于该标记。立即从 打开元素栈 中弹出 当前节点

确认该标记的 自闭合标志,如果已设置。

开始标签的标签名称为 "noframes"

使用"针对“头部插入模式"的规则处理标记。

文件结束标记

如果当前节点不是根html元素,则这是一个解析错误

当前节点只能在片段情况下是根html元素。

停止解析.

任何其他情况

解析错误。忽略标记。

13.2.6.4.21 "帧集之后"插入模式

当用户代理要应用"帧集之后"插入模式的规则时,用户代理必须按如下方式处理标记。

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

插入字符.

一个注释标记

插入一个注释.

一个 DOCTYPE 标记

解析错误。忽略标记。

一个起始标签,其标签名称为 "html"

使用"针对“主体插入模式"的规则处理标记。

一个结束标记,其标记名称为“html”

插入模式切换到"帧集之后之后"。

开始标签的标签名称为 "noframes"

使用"针对“头部插入模式"的规则处理标记。

文件结束标记

停止解析.

任何其他情况

解析错误。忽略标记。

13.2.6.4.22 "主体之后之后"插入模式

当用户代理要应用"主体之后之后"插入模式的规则时,用户代理必须按如下方式处理标记。

一个注释标记

文档对象的最后一个子节点处插入注释

一个 DOCTYPE 标记
字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE
一个起始标签,其标签名称为 "html"

使用"针对“主体插入模式"的规则处理标记。

文件结束标记

停止解析.

任何其他情况

解析错误。将插入模式切换到"主体",并重新处理标记。

13.2.6.4.23 "帧集之后之后"插入模式

当用户代理要应用"帧集之后之后"插入模式的规则时,用户代理必须按如下方式处理标记。

一个注释标记

文档对象的最后一个子节点处插入注释

一个 DOCTYPE 标记
字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE
一个起始标签,其标签名称为 "html"

使用"针对“主体插入模式"的规则处理标记。

文件结束标记

停止解析.

开始标签的标签名称为 "noframes"

使用"针对“头部插入模式"的规则处理标记。

任何其他情况

解析错误。忽略标记。

13.2.6.5 解析外国内容中标记的规则

当用户代理要应用解析外国内容中标记的规则时,用户代理必须按如下方式处理标记。

一个字符标记,其为 U+0000 NULL

解析错误插入一个 U+FFFD 替换字符

字符令牌是以下字符之一:U+0009 CHARACTER TABULATION、U+000A LINE FEED (LF)、U+000C FORM FEED (FF)、U+000D CARRIAGE RETURN (CR) 或 U+0020 SPACE

插入该标记的字符.

任何其他字符标记

插入该标记的字符.

帧集-确定标志设置为“不确定”。

一个注释标记

插入一个注释.

一个 DOCTYPE 标记

解析错误。忽略标记。

开始标记,其标记名称是以下之一:"b","big","blockquote","body","br","center","code","dd","div","dl","dt","em","embed","h1","h2","h3","h4","h5","h6","head","hr","i","img","li","listing","menu","meta","nobr","ol","p","pre","ruby","s","small","span","strong","strike","sub","sup","table","tt","u","ul","var"
开始标记,其标记名称是“font”,如果标记具有名为“color”,“face”或“size”的任何属性
结束标记,其标记名称是“br”,“p”

解析错误.

当前节点不是MathML 文本集成点HTML 集成点HTML 命名空间中的元素时,从打开元素堆栈中弹出元素。

根据 HTML 内容中对应于当前插入模式部分给出的规则重新处理标记。

任何其他开始标签

如果调整后的当前节点MathML 命名空间中的元素,则调整标记的 MathML 属性。(这修复了并非所有都为小写的 MathML 属性的情况。)

如果调整后的当前节点SVG 命名空间中的元素,并且标记的标记名称是下表第一列中的名称之一,则将标记名称更改为第二列中对应单元格中给出的名称。(这修复了并非所有都为小写的 SVG 元素的情况。)

标记名称元素名称
altglyph altGlyph
altglyphdef altGlyphDef
altglyphitem altGlyphItem
animatecolor animateColor
animatemotion animateMotion
animatetransform animateTransform
clippath clipPath
feblend feBlend
fecolormatrix feColorMatrix
fecomponenttransfer feComponentTransfer
fecomposite feComposite
feconvolvematrix feConvolveMatrix
fediffuselighting feDiffuseLighting
fedisplacementmap feDisplacementMap
fedistantlight feDistantLight
fedropshadow feDropShadow
feflood feFlood
fefunca feFuncA
fefuncb feFuncB
fefuncg feFuncG
fefuncr feFuncR
fegaussianblur feGaussianBlur
feimage feImage
femerge feMerge
femergenode feMergeNode
femorphology feMorphology
feoffset feOffset
fepointlight fePointLight
fespecularlighting feSpecularLighting
fespotlight feSpotLight
fetile feTile
feturbulence feTurbulence
foreignobject foreignObject
glyphref glyphRef
lineargradient linearGradient
radialgradient radialGradient
textpath textPath

如果调整后的当前节点SVG 命名空间中的元素,则调整标记的 SVG 属性。(这修复了并非所有都为小写的 SVG 属性的情况。)

调整标记的外国属性。(这修复了命名空间属性的使用,特别是 SVG 中的 XLink。)

对于标记插入一个外国元素,其调整后的当前节点的命名空间为真,false。

如果标记的自闭合标志已设置,则运行以下列表中的相应步骤。

如果标记的标记名称是“script”,并且新的当前节点位于SVG 命名空间

确认标记的自闭合标志,然后按照下面描述的“script”结束标记的步骤进行操作。

否则

打开元素堆栈中弹出当前节点,并确认标记的自闭合标志

结束标记,其标记名称是“script”,如果当前节点SVG script元素

打开元素堆栈中弹出当前节点

旧插入点的值与当前插入点的值相同。让插入点位于下一个输入字符之前。

将解析器的脚本嵌套级别加一。将解析器暂停标志设置为真。

如果活动推测性 HTML 解析器为空,并且用户代理支持 SVG,则根据 SVG 规则处理 SVG script 元素[SVG]

即使这导致将新字符插入标记器,解析器也不会重新递归执行,因为解析器暂停标志为真。

将解析器的脚本嵌套级别减一。如果解析器的脚本嵌套级别为零,则将解析器暂停标志设置为假。

插入点的值为旧插入点的值。(换句话说,将插入点恢复为其先前值。该值可能是“未定义”值。)

任何其他结束标签

运行以下步骤

  1. 节点初始化为当前节点(堆栈的最底层节点)。

  2. 如果节点的标记名称转换为 ASCII 小写与标记的标记名称不相同,则这是一个解析错误

  3. 循环:如果节点打开元素堆栈中最顶层的元素,则返回。(片段情况

  4. 如果 node 的标签名 转换为 ASCII 小写 后与该标记的标签名相同,则从 打开元素栈 中弹出元素,直到 node 被弹出栈,然后返回。

  5. node 设置为 打开元素栈 中的上一项。

  6. 如果 node 不是 HTML 命名空间 中的元素,则返回到标记为 loop 的步骤。

  7. 否则,根据与当前 插入模式 相对应的 HTML 内容部分中给出的规则处理该标记。

13.2.7 结尾

Document/DOMContentLoaded_event

所有当前引擎都支持。

Firefox1+Safari3.1+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android10.1+

一旦用户代理 停止解析 文档,用户代理必须执行以下步骤

Window/load_event

所有当前引擎都支持。

Firefox1+Safari1.3+Chrome1+
Opera4+Edge79+
Edge (Legacy)12+Internet Explorer4+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android10.1+
  1. 如果 活动推测 HTML 解析器 不为空,则 停止推测 HTML 解析器 并返回。

  2. 插入点 设置为 undefined。

  3. 更新当前文档就绪状态 为 "interactive"。

  4. 打开元素栈 中弹出 所有 节点。

  5. 文档解析完成后将执行的脚本列表 不为空时

    1. 循环事件循环,直到 文档解析完成后将执行的脚本列表 中的第一个 script准备解析执行 设置为 true 并且 解析器的 Document 没有阻止脚本的样式表

    2. 执行脚本元素,该元素由 文档解析完成后将执行的脚本列表 中的第一个 script 给出。

    3. 文档解析完成后将执行的脚本列表 中移除第一个 script 元素(即,从列表中移出第一个条目)。

  6. DOM 操作任务源 上排队一个全局任务,该任务由 Document相关全局对象 给出,以运行以下子步骤

    1. Document加载时间信息DOM 内容加载事件开始时间 设置为由 Document相关全局对象 给出的 当前高分辨率时间

    2. 触发一个事件,名为 DOMContentLoaded,在 Document 对象上,其 bubbles 属性初始化为 true。

    3. Document加载时间信息DOM 内容加载事件结束时间 设置为由 Document相关全局对象 给出的 当前高分辨率时间

    4. 启用 客户端消息队列,该队列属于 ServiceWorkerContainer 对象,该对象的关联 服务工作者客户端Document 对象的 相关设置对象

    5. 调用 WebDriver BiDi DOM 内容已加载,并使用 Document浏览上下文 和一个新的 WebDriver BiDi 导航状态,该状态的 idDocument 对象的 用于 WebDriver BiDi 的加载期间导航 IDstatus 是 "pending",并且 urlDocument 对象的 URL

  7. 循环事件循环,直到 尽快执行的脚本集尽快按顺序执行的脚本列表 为空。

  8. 循环事件循环,直到 Document 中没有 延迟加载事件 的内容。

  9. DOM 操作任务源 上排队一个全局任务,该任务由 Document相关全局对象 给出,以运行以下步骤

    1. 更新当前文档就绪状态 为 "complete"。

    2. 如果 Document 对象的 浏览上下文 为 null,则中止这些步骤。

    3. windowDocument相关全局对象

    4. Document加载时间信息加载事件开始时间 设置为由 window 给出的 当前高分辨率时间

    5. 触发一个事件,名为 load,在 window 上,并设置 遗留目标覆盖标志

    6. 调用 WebDriver BiDi 加载完成,并使用 Document浏览上下文 和一个新的 WebDriver BiDi 导航状态,该状态的 idDocument 对象的 用于 WebDriver BiDi 的加载期间导航 IDstatus 是 "complete",并且 urlDocument 对象的 URL

    7. Document 对象的 用于 WebDriver BiDi 的加载期间导航 ID 设置为 null。

    8. Document加载时间信息加载事件结束时间 设置为由 window 给出的 当前高分辨率时间

    9. 断言Document页面显示 为 false。

    10. 文档页面显示 标志设置为 true。

    11. window 上触发一个名为 pageshow页面转换事件,参数为 false。

    12. 完全完成 文档 的加载。

    13. 文档 排队导航计时条目

  10. 如果 文档加载时打印 标志已设置,则执行 打印步骤

  11. 现在 文档 已准备好执行加载后任务

当用户代理需要 中止解析器 时,它必须执行以下步骤。

  1. 丢弃 输入流 中所有挂起的內容,并丢弃将要添加到其中的任何未来内容。

  2. 停止 此 HTML 解析器的 推测性 HTML 解析器

  3. 更新当前文档就绪状态 为 "interactive"。

  4. 打开元素堆栈 中弹出所有节点。

  5. 更新当前文档就绪状态 为 "complete"。

13.2.8 推测性 HTML 解析

用户代理可以实现本节中描述的优化,以推测性地获取在 HTML 标记中声明的资源,而 HTML 解析器则等待 挂起的解析阻塞脚本 被获取并执行,或者在正常解析期间,在 为令牌创建元素 的时候。虽然此优化没有明确定义,但有一些规则需要考虑以确保互操作性。

每个 HTML 解析器 可以有一个 活动推测性 HTML 解析器。它最初为 null。

推测性 HTML 解析器 必须像普通 HTML 解析器一样工作(例如,树构建器规则适用),但有一些例外情况。

推测性模拟元素 element推测性获取 必须遵循以下规则。

这些内容是否应该应用于文档“真正”,即使它们是推测性地找到的?

每个 文档 都有一个 推测性获取 URL 列表,它是一个 列表,其中包含 URL,最初为空。

要为 HTML 解析器实例 parser 启动推测性 HTML 解析器

  1. 可选地,返回。

    此步骤允许用户代理选择不进行推测性 HTML 解析。

  2. 如果 parser活动推测性 HTML 解析器 不为 null,则为 parser 停止推测性 HTML 解析器

    这可能发生在 document.write() 写入另一个解析阻塞脚本时。为简单起见,此规范始终重新启动推测性解析,但用户代理可以实现更有效的策略,只要最终结果等效即可。

  3. speculativeParser 为一个新的 推测性 HTML 解析器,其状态与 parser 相同。

  4. speculativeDocparser文档 的一个新的同构表示,其中所有元素都替换为 推测性模拟元素。设 speculativeParser 解析到 speculativeDoc 中。

  5. parser活动推测性 HTML 解析器 设置为 speculativeParser

  6. 并行,运行 speculativeParser 直到它被停止或直到它到达其 输入流 的末尾。

要为 HTML 解析器实例 parser 停止推测性 HTML 解析器

  1. speculativeParserparser活动推测性 HTML 解析器

  2. 如果 speculativeParser 为 null,则返回。

  3. 丢弃 speculativeParser输入流 中所有挂起的內容,并丢弃将要添加到其中的任何未来内容。

  4. parser活动推测性 HTML 解析器 设置为 null。

推测性 HTML 解析器 将创建 推测性模拟元素,而不是普通元素。树构建器通常对元素执行的 DOM 操作预计将在推测性模拟元素上正常工作。

一个 推测性模拟元素 是一个 结构体,它包含以下

要给定 namespacetagNameattributes 创建推测性模拟元素

  1. element 为一个新的 推测性模拟元素

  2. element命名空间 设置为 namespace

  3. element本地名称 设置为 tagName

  4. element属性列表 设置为 attributes

  5. element子节点 设置为一个新的空 列表

  6. 可选地,为 element 执行 推测性获取

  7. 返回 元素

当树构建器说要将元素插入到 template 元素的 模板内容 中时,如果这是一个 推测性模拟元素,并且 template 元素的 模板内容 不是一个 ShadowRoot 节点,则什么也不做。在非声明式阴影根 template 元素中推测性地找到的 URL 本身可能也是模板,并且不得推测性地获取。

13.2.9 将 HTML DOM 转换为信息集

当应用程序将 HTML 解析器 与 XML 管道结合使用时,可能会出现构建的 DOM 在某些细微方面与 XML 工具链不兼容。例如,XML 工具链可能无法表示名为 xmlns 的属性,因为它们与 XML 语法中的命名空间冲突。 HTML 解析器 生成的某些数据未包含在 DOM 本身中。本节指定了一些处理这些问题的规则。

如果使用的 XML API 不支持 DOCTYPE,则工具可能会完全删除 DOCTYPE。

如果 XML API 不支持名称为 "xmlns" 的无命名空间属性、名称以 "xmlns:" 开头的属性或 XMLNS 命名空间 中的属性,则工具可能会删除此类属性。

该工具可能会使用任何用于正常操作所需的命名空间声明来注释输出。

如果使用的 XML API 限制元素和属性本地名称中允许的字符,则该工具可能会将 API 不支持的所有元素和属性本地名称映射到一组允许的名称,方法是将任何不受支持的字符替换为大写字母 U 和字符代码点的六位十六进制表示形式(使用数字 0-9 和大写字母 A-F 作为符号),按数字顺序递增。

例如,元素名称 foo<bar(虽然它既不是合法的 HTML 元素名称也不是格式良好的 XML 元素名称,但可以由 HTML 解析器 输出),将转换为 fooU00003Cbar,它是一个格式良好的 XML 元素名称(尽管它仍然不是 HTML 中的合法名称)。

再举一个例子,考虑属性 xlink:href。在 MathML 元素上使用时,它在经过 调整 后,变成了一个带有前缀 "xlink" 和本地名称 "href" 的属性。但是,在 HTML 元素上使用时,它变成了一个没有前缀并且本地名称为 "xlink:href" 的属性,这不是有效的 NCName,因此 XML API 可能会拒绝它。因此,它可能会被转换,变成 "xlinkU00003Ahref"。

此转换产生的名称方便地不会与 HTML 解析器 生成的任何属性发生冲突,因为这些属性要么全部是小写,要么就是 调整外部属性 算法表格中列出的那些。

如果 XML API 限制注释中出现两个连续的 U+002D HYPHEN-MINUS 字符 (--),则该工具可能会在任何此类违规字符之间插入一个 U+0020 SPACE 字符。

如果 XML API 限制注释以 U+002D HYPHEN-MINUS 字符 (-) 结尾,则该工具可能会在注释结尾处插入一个 U+0020 SPACE 字符。

如果 XML API 限制字符数据、属性值或注释中允许的字符,则该工具可能会将任何 U+000C FORM FEED (FF) 字符替换为 U+0020 SPACE 字符,并将任何其他文字非 XML 字符替换为 U+FFFD REPLACEMENT CHARACTER。

如果该工具无法以任何方式传达带外信息,则该工具可能会删除以下信息

本节中允许的变动在 HTML 解析器 的规则应用之后才应用。例如,<a::> 开始标签将由 </a::> 结束标签关闭,而不是由 </aU00003AU00003A> 结束标签关闭,即使用户代理使用上述规则为该开始标签在 DOM 中生成一个实际的元素,其名称为 aU00003AU00003A

13.2.10 解析器中错误处理和奇特情况的简介

本节是非规范性的。

本节检查了一些错误标记,并讨论了 HTML 解析器 如何处理这些情况。

13.2.10.1 嵌套错误标签:<b><i></b></i>

本节是非规范性的。

最常讨论的错误标记示例如下

<p>1<b>2<i>3</b>4</i>5</p>

对该标记的解析直到 "3" 都是直观的。此时,DOM 看起来像这样

这里,打开元素栈 上有五个元素:htmlbodypbi活动格式化元素列表 只有两个:bi插入模式 是 "正文内"。

接收到标签名称为 "b" 的结束标签标记后,将调用 "收养机构算法"。这是一个简单的情况,因为 格式化元素b 元素,并且没有 最远块。因此,打开元素栈 最终只有三个元素:htmlbodyp,而 活动格式化元素列表 只有一个:i。此时,DOM 树没有修改。

下一个标记是字符 ("4"),它会触发 活动格式化元素的重建,在本例中只有 i 元素。因此,为 "4" Text 节点创建了一个新的 i 元素。在接收 "i" 的结束标签标记以及插入 "5" Text 节点之后,DOM 看起来如下

13.2.10.2 嵌套错误标签:<b><p></b></p>

本节是非规范性的。

与前一个示例类似的情况如下

<b>1<p>2</b>3</p>

直到 "2",这里的解析都是直观的

有趣的部分是解析标签名称为 "b" 的结束标签标记时。

在看到该标记之前,打开元素栈 上有四个元素:htmlbodybp活动格式化元素列表 只有一个:b插入模式 是 "正文内"。

接收到标签名称为 "b" 的结束标签标记后,将调用 "收养机构算法",如前一个示例所示。但是,在本例中,存在 最远块,即 p 元素。因此,这次不会跳过收养机构算法。

共同祖先body 元素。一个概念上的 "书签" 标记了 活动格式化元素列表b 的位置,但由于该列表中只有一个元素,因此书签的影响不大。

随着算法的进展,节点 最终设置为格式化元素 (b),而 最后一个节点 最终设置为 最远块 (p)。

最后一个节点 被追加(移动)到 共同祖先,因此 DOM 看起来像这样

创建了一个新的 b 元素,并将 p 元素的子节点移动到该元素中

最后,新的 b 元素被附加到 p 元素,使得 DOM 看起来像

活动格式化元素列表打开元素栈 中移除 b 元素,因此在解析 "3" 时,它被附加到 p 元素

13.2.10.3 表格中的意外标记

本节是非规范性的。

出于历史原因,表格中的错误处理特别奇怪。例如,考虑以下标记

<table><b><tr><td>aaa</td></tr>bbb</table>ccc

突出显示的 b 元素开始标签不允许直接放在这样的表格中,解析器通过将元素放在表格之前来处理这种情况。(这被称为寄养父母。)可以通过检查 DOM 树在 table 元素的开始标签被看到之后的情况来观察

…然后在 b 元素开始标签被看到之后

此时,打开元素栈 上面包含元素 htmlbodytableb(按此顺序,尽管结果 DOM 树是如此);活动格式化元素列表 只包含 b 元素;插入模式 是 "in table"。

tr 开始标签导致 b 元素从栈中弹出,并隐式地创建一个 tbody 开始标签;然后,tbodytr 元素以相当直接的方式进行处理,使解析器通过 "in table body" 和 "in row" 插入模式,之后 DOM 看起来如下

这里,打开元素栈 上面包含元素 htmlbodytabletbodytr活动格式化元素列表 仍然包含 b 元素;插入模式 是 "in row"。

td 元素开始标签令牌,在将 td 元素放在树上之后,在 活动格式化元素列表 上放置一个 标记(它还切换到 "in cell" 插入模式)。

标记 意味着当看到 "aaa" 字符令牌时,不会创建 b 元素来保存结果 Text 节点

结束标签以直接的方式进行处理;在处理它们之后,打开元素栈 上面包含元素 htmlbodytabletbody活动格式化元素列表 仍然包含 b 元素(标记 已被 "td" 结束标签令牌移除);插入模式 是 "in table body"。

因此,发现 "bbb" 字符令牌。这些触发 "in table text" 插入模式(原始插入模式 设置为 "in table body"). 收集字符令牌,当看到下一个令牌(table 元素结束标签)时,将它们作为一个组进行处理。因为它们不是空格,所以它们根据 "in table" 插入模式中的 "其他任何内容" 规则进行处理,该规则委托给 "in body" 插入模式,但使用 寄养父母

重建活动格式化元素 时,会创建一个 b 元素并进行 寄养父母,然后将 "bbb" Text 节点附加到它

打开元素栈 上面包含元素 htmlbodytabletbody 和 新的 b(再次注意,这与结果树不匹配!);活动格式化元素列表 包含新的 b 元素;插入模式 仍然是 "in table body"。

如果字符令牌仅仅是 ASCII 空格 而不是 "bbb",那么这些 ASCII 空格 就会被附加到 tbody 元素。

最后,table 通过一个 "table" 结束标签关闭。这会将所有节点从 打开元素栈 中弹出,直到并包括 table 元素,但它不会影响 活动格式化元素列表,因此表格之后的 "ccc" 字符令牌会导致创建另一个 b 元素,这次是在表格之后

13.2.10.4 在解析时修改页面的脚本

本节是非规范性的。

考虑以下标记,在这个例子中,我们假设它是具有 URL https://example.com/inner 的文档,被渲染为另一个具有 URL https://example.com/outer 的文档中的 iframe 的内容

<div id=a>
 <script>
  var div = document.getElementById('a');
  parent.document.body.appendChild(div);
 </script>
 <script>
  alert(document.URL);
 </script>
</div>
<script>
 alert(document.URL);
</script>

直到第一个 "script" 结束标签,在解析脚本之前,结果相对直接

但是,在解析脚本之后,div 元素及其子元素 script 元素不见了

它们现在位于上述外部 浏览上下文Document 中。但是,打开元素栈 仍然包含 div 元素

因此,当解析第二个 script 元素时,它被插入到外部 Document 对象中

那些解析到与解析器创建时不同的Document中的脚本不会执行,因此第一个警报不会显示。

一旦解析了div元素的结束标签,div元素就会从堆栈中弹出,因此下一个script元素位于内部Document中。

此脚本确实执行,导致弹出一个显示“https://example.com/inner”的警报。

13.2.10.5 跨多个文档执行脚本

本节是非规范性的。

详细说明上一节中的示例,考虑第二个script元素是外部脚本(即具有src属性的脚本)的情况。由于该元素在创建时不在解析器的Document中,因此该外部脚本甚至不会被下载。

script元素(具有src属性)正常解析到解析器的Document中,但在下载外部脚本期间,该元素被移动到另一个文档,该脚本继续下载,但不执行。

一般来说,在Document之间移动script元素被认为是一种不好的做法。

13.2.10.6 未关闭的格式化元素

本节是非规范性的。

以下标记显示了嵌套的格式化元素(如b)如何被收集,并继续被应用,即使它们所包含的元素被关闭,但过多的重复元素会被丢弃。

<!DOCTYPE html>
<p><b class=x><b class=x><b><b class=x><b class=x><b>X
<p>X
<p><b><b class=x><b>X
<p></b></b></b></b></b></b>X

生成的 DOM 树如下所示

请注意,标记中的第二个p元素没有显式的b元素,但在生成的 DOM 中,在元素的“X”之前,最多会重建每种格式化元素的三种(在本例中,三种具有类属性的b元素,以及两个未修饰的b元素)。

还要注意,这意味着在最后一段中,只需要六个b结束标签就可以完全清除活动格式化元素列表,即使到目前为止已经看到了九个b开始标签。

13.3 序列化 HTML 片段

为了以下算法的目的,如果元素类型是空元素之一,或为basefontbgsoundframekeygenparam,则元素序列化为空

以下步骤构成了HTML 片段序列化算法。该算法将 DOM ElementDocumentDocumentFragment(称为该节点)作为输入,以及布尔值serializableShadowRoots和一个sequence<ShadowRoot> shadowRoots,并返回一个字符串。

该算法序列化正在序列化的节点的子节点,而不是节点本身。

  1. 如果该节点序列化为空,则返回空字符串。

  2. s为一个字符串,并将其初始化为空字符串。

  3. 如果该节点template元素,则令该节点改为template元素的模板内容(一个DocumentFragment节点)。

  4. 如果当前节点影子宿主,则

    1. shadow当前节点影子根

    2. 如果以下情况之一为真

      • serializableShadowRoots 为真,且 shadow可序列化 为真;或

      • shadowRoots 包含 shadow

      1. 追加“<template shadowrootmode="”。

      2. 如果 shadow模式 为“open”,则追加“open”。否则,追加“closed”。

      3. 追加“"”。

      4. 如果 shadow委托焦点 设置,则追加“ shadowrootdelegatesfocus=""”。

      5. 如果 shadow可序列化 设置,则追加“ shadowrootserializable=""”。

      6. 如果 shadow可克隆 设置,则追加“ shadowrootclonable=""”。

      7. 追加“>”。

      8. 追加使用 shadowserializableShadowRootsshadowRoots 运行 HTML 片段序列化算法 的结果值(因此对该元素递归调用此算法)。

      9. 追加“</template>”。

  5. 对于 该节点 的每个子节点,按树状顺序执行以下步骤

    1. 当前节点 为正在处理的子节点。

    2. 将以下列表中的适当字符串追加到 s

      如果 当前节点 是一个 Element

      如果 当前节点HTML 命名空间MathML 命名空间SVG 命名空间 中的元素,则令 tagname当前节点 的本地名称。否则,令 tagname当前节点 的限定名称。

      追加一个 U+003C LESS-THAN SIGN 字符 (<),后跟 tagname

      对于由HTML 解析器createElement()创建的HTML 元素tagname 将为小写。

      如果 当前节点is 不为空,且该元素在属性列表中没有is 属性,则追加字符串“ is="”,后跟 当前节点is按以下描述的属性模式进行转义,后跟一个 U+0022 QUOTATION MARK 字符 (")。

      对于元素拥有的每个属性,追加一个 U+0020 SPACE 字符,属性的序列化名称(如以下所述)、一个 U+003D EQUALS SIGN 字符 (=)、一个 U+0022 QUOTATION MARK 字符 (")、属性的值、按以下描述的属性模式进行转义,以及第二个 U+0022 QUOTATION MARK 字符 (")。

      为了上一段的目的,属性的序列化名称 必须按以下方式确定

      如果属性没有命名空间

      属性的序列化名称是属性的本地名称。

      对于 HTML 元素 上由 HTML 解析器setAttribute() 设置的属性,本地名称将为小写。

      如果属性在 XML 命名空间

      属性的序列化名称是字符串“xml:”后跟属性的本地名称。

      如果属性在 XMLNS 命名空间 中,并且属性的本地名称是 xmlns

      属性的序列化名称是字符串“xmlns”。

      如果属性在 XMLNS 命名空间 中,并且属性的本地名称不是 xmlns

      属性的序列化名称是字符串“xmlns:”后跟属性的本地名称。

      如果属性在 XLink 命名空间

      属性的序列化名称是字符串“xlink:”后跟属性的本地名称。

      如果属性在其他命名空间中

      属性的序列化名称是属性的限定名称。

      虽然属性的精确顺序是 实现定义的,并且可能取决于诸如属性在原始标记中给出的顺序之类的因素,但排序顺序必须是稳定的,这样连续调用此算法将以相同的顺序序列化元素的属性。

      追加 U+003E 大于号字符 (>)。

      如果 当前节点 序列化为空,则在此时 继续 到下一个子节点。

      追加使用 当前节点可序列化影子根影子根 运行 HTML 片段序列化算法 的值(因此为该节点递归进入此算法),后跟 U+003C 小于号字符 (<)、U+002F 斜杠字符 (/)、标签名 再次出现,最后是 U+003E 大于号字符 (>)。

      如果 当前节点 是一个 文本 节点

      如果 当前节点 的父节点是 stylescriptxmpiframenoembednoframesplaintext 元素,或者如果 当前节点 的父节点是 noscript 元素,并且 脚本已启用,则追加 当前节点数据 的值。

      否则,追加 当前节点数据 的值,如以下所述进行转义

      如果 当前节点 是一个 注释

      追加“<!--”(U+003C 小于号、U+0021 感叹号、U+002D 连字符、U+002D 连字符),后跟 当前节点数据 的值,后跟文字字符串“-->”(U+002D 连字符、U+002D 连字符、U+003E 大于号)。

      如果 当前节点 是一个 处理指令

      追加“<?”(U+003C 小于号、U+003F 问号),后跟 当前节点target IDL 属性的值,后跟单个 U+0020 空格字符,后跟 当前节点数据 的值,后跟单个 U+003E 大于号字符 (>)。

      如果 当前节点 是一个 文档类型

      追加“<!DOCTYPE”(U+003C 小于号、U+0021 感叹号、U+0044 拉丁大写字母 D、U+004F 拉丁大写字母 O、U+0043 拉丁大写字母 C、U+0054 拉丁大写字母 T、U+0059 拉丁大写字母 Y、U+0050 拉丁大写字母 P、U+0045 拉丁大写字母 E),后跟一个空格 (U+0020 空格),后跟 当前节点名称,后跟“>”(U+003E 大于号)。

  6. 返回 s

如果使用 HTML 解析器 解析此算法的输出,则可能不会返回原始的树结构。使用 HTML 解析器 本身也可以生成不能对序列化和重新解析步骤进行往返的树结构,尽管此类情况通常是非符合标准的。

例如,如果将 textarea 元素序列化,并且该元素已附加了 注释 节点,然后对输出进行重新解析,则注释将最终显示在文本控件中。同样,如果由于 DOM 操作,元素包含包含“-->”的注释,则当解析序列化元素的结果时,注释将在该点被截断,并且注释的其余部分将被解释为标记。更多示例包括让 script 元素包含具有文本字符串“</script>”的 文本 节点,或者让 p 元素包含 ul 元素(因为 ul 元素的 开始标记 将暗示 p 的结束标记)。

这可以使跨站点脚本攻击成为可能。一个例子是页面允许用户输入一些字体系列名称,这些名称随后会通过 DOM 插入到 CSS style 块中,然后使用 innerHTML IDL 属性来获取该 style 元素的 HTML 序列化:如果用户输入“</style><script>attack</script>”作为字体系列名称,则 innerHTML 将返回标记,如果在不同的上下文中解析,该标记将包含 script 节点,即使在原始 DOM 中没有 script 节点。

例如,考虑以下标记

<form id="outer"><div></form><form id="inner"><input>

这将被解析为

input 元素将与内部 form 元素相关联。现在,如果序列化此树结构并进行重新解析,则将忽略 <form id="inner"> 开始标记,因此 input 元素将与外部 form 元素相关联。

<html><head></head><body><form id="outer"><div><form id="inner"><input></form></div></form></body></html>

作为另一个示例,请考虑以下标记

<a><table><a>

这将被解析为

也就是说,a 元素是嵌套的,因为第二个 a 元素是 养育的。在序列化和重新解析往返后,a 元素和 table 元素将全部成为兄弟姐妹,因为第二个 <a> 开始标记隐式地关闭了第一个 a 元素。

<html><head></head><body><a><a></a><table></table></a></body></html>

出于历史原因,此算法不会对 pretextarealisting 元素中的初始 U+000A 换行符 (LF) 字符进行往返,即使(在前两种情况下)要进行往返的标记可能是符合标准的。 HTML 解析器 在解析期间将删除此类字符,但此算法不会序列化额外的 U+000A 换行符 (LF) 字符。

例如,考虑以下标记

<pre>

Hello.</pre>

当首次解析此文档时,pre 元素的 子文本内容 以单个换行符开头。在序列化和重新解析往返后,pre 元素的 子文本内容 只是“Hello.”。

由于 is 属性在发出 自定义内置元素 创建信号方面所扮演的特殊角色,因为它提供了一种机制来让已解析的 HTML 设置元素的 is,因此我们对它在序列化期间的处理进行了特殊处理。这确保了元素的 is 在序列化和解析往返过程中得到保留。

使用解析器创建 自定义内置元素 时,开发人员直接使用 is 属性;在这种情况下,序列化和解析往返可以正常工作。

<script>
window.SuperP = class extends HTMLParagraphElement {};
customElements.define("super-p", SuperP, { extends: "p" });
</script>

<div id="container"><p is="super-p">Superb!</p></div>

<script>
console.log(container.innerHTML); // <p is="super-p">
container.innerHTML = container.innerHTML;
console.log(container.innerHTML); // <p is="super-p">
console.assert(container.firstChild instanceof SuperP);
</script>

但是,使用其 构造函数 或通过 createElement() 创建自定义内置元素时,不会添加 is 属性。相反,is(自定义元素机制使用的是它)将在没有通过属性进行中介的情况下设置。

<script>
container.innerHTML = "";
const p = document.createElement("p", { is: "super-p" });
container.appendChild(p);

// The is attribute is not present in the DOM:
console.assert(!p.hasAttribute("is"));

// But the element is still a super-p:
console.assert(p instanceof SuperP);
</script>

为了确保序列化-解析往返依然有效,序列化过程会显式地将元素的 is 写入为一个 is 属性。

<script>
console.log(container.innerHTML); // <p is="super-p">
container.innerHTML = container.innerHTML;
console.log(container.innerHTML); // <p is="super-p">
console.assert(container.firstChild instanceof SuperP);
</script>

转义字符串(在上述算法的范围内)包括执行以下步骤。

  1. 用字符串 "&amp;" 替换任何出现的 "&" 字符。

  2. 用字符串 "&nbsp;" 替换任何出现的 U+00A0 不间断空格字符。

  3. 如果算法是在 *属性模式* 中调用的,用字符串 "&quot;" 替换任何出现的 """ 字符。

  4. 如果算法 *未* 在 *属性模式* 中调用,用字符串 "&lt;" 替换任何出现的 "<" 字符,用字符串 "&gt;" 替换任何出现的 ">" 字符。

13.4 解析 HTML 片段

以下步骤构成 HTML 片段解析算法。该算法以 Element 节点作为输入,称为 context 元素,用于提供解析器的上下文,input,要解析的字符串,以及一个可选的布尔值 allowDeclarativeShadowRoots(默认值为 false)。它返回一个包含零个或多个节点的列表。

在解析器部分的算法中标记为 片段情况 的部分是仅在解析器为该算法的目的创建时才出现的部分。为了便于信息获取,算法用此类标记进行了注释;此类标记没有规范性权重。如果即使解析器不是为了处理该算法而创建的,也可能出现描述为 片段情况 的条件,那么这则是规范中的错误。

  1. 创建一个新的 Document 节点,并将其标记为 HTML 文档

  2. 如果 context 元素的 节点文档 处于 怪癖模式,则让 Document 也处于 怪癖模式。否则,如果 context 元素的 节点文档 处于 有限怪癖模式,则让 Document 也处于 有限怪癖模式。否则,让 Document 处于 非怪癖模式

  3. 如果 allowDeclarativeShadowRoots 为 true,则将 Document允许声明式影子根 设置为 true。

  4. 创建一个新的 HTML 解析器,并将其与刚刚创建的 Document 节点关联。

  5. 根据 context 元素,如下设置 HTML 解析器标记化 阶段的状态。

    title
    textarea
    将标记器切换到 RCDATA 状态
    style
    xmp
    iframe
    noembed
    noframes
    将标记器切换到 RAWTEXT 状态
    script
    将标记器切换到 脚本数据状态
    noscript
    如果 脚本标志 已启用,则将标记器切换到 RAWTEXT 状态。否则,让标记器保持在 数据状态
    plaintext
    将标记器切换到 PLAINTEXT 状态
    任何其他元素
    让标记器保持在 数据状态

    为了提高性能,不报告错误并直接使用本规范中描述的实际状态机的实现,可以在上述列表中提到 RAWTEXT 和脚本数据状态的地方,使用 PLAINTEXT 状态代替它们。除了关于解析错误的规则外,它们是等效的,因为在片段情况中没有 合适的结束标签标记,但它们涉及更少的状态转换。

  6. root 是一个新的 html 元素,没有属性。

  7. 将元素 root 附加到上面创建的 Document 节点。

  8. 设置解析器的 打开元素堆栈,使其仅包含单个元素 root

  9. 如果 context 元素是 template 元素,则将 "在模板中" 推入 模板插入模式堆栈,使其成为新的 当前模板插入模式

  10. 创建一个开始标签标记,其名称为 context 的本地名称,其属性为 context 的属性。

    让此开始标签标记成为 context 节点的开始标签标记,例如,为了确定它是否为 HTML 集成点

  11. 适当地重置解析器的插入模式。.

    解析器将引用 context 元素作为该算法的一部分。

  12. 将解析器的 form 元素指针 设置为最接近 context 元素的 form 元素节点(沿着祖先链向上,如果该元素本身是 form 元素,则包括该元素),如果有的话。(如果没有这样的 form 元素,则 form 元素指针 保持其初始值,null。)

  13. input 放入刚刚创建的 HTML 解析器输入流 中。编码 置信度 是 *无关紧要的*。

  14. 启动解析器,并让它运行,直到它消耗了刚刚插入输入流中的所有字符。

  15. 返回 root 的子节点,按 树序 排列。