动态标准 — 最后更新于 2024 年 9 月 12 日
本节仅适用于用户代理、数据挖掘工具和一致性检查器。
将 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
的元素。在可能的情况下,对这类元素的引用都超链接到其定义。
HTML 解析过程的输入包括一个 代码点 流,该流将通过 标记化 阶段,然后是 树构建 阶段。输出是一个 Document
对象。
不支持脚本的实现不必实际创建 DOM Document
对象,但在这种情况下,DOM 树仍然用作规范中其他部分的模型。
在常见情况下,标记化阶段处理的数据来自网络,但 它也可以来自用户代理中运行的脚本,例如使用 document.write()
API。
标记器阶段和树构建阶段只有一组状态,但树构建阶段是可重入的,这意味着当树构建阶段处理一个标记时,标记器可能会恢复,导致在第一个标记处理完成之前发出和处理更多标记。
在以下示例中,树构建阶段将在处理“script”结束标记时被调用来处理“p”开始标记。
...
< script >
document. write( '<p>' );
</ script >
...
为了处理这些情况,解析器有一个 脚本嵌套级别,它必须最初设置为零,以及一个 解析器暂停标志,它必须最初设置为 false。
本规范定义了 HTML 文档的解析规则,无论它们是语法上正确还是不正确。解析算法中的某些点被称为 解析错误。解析错误的错误处理是明确定义的(即本规范中描述的处理规则),但用户代理在解析 HTML 文档时,可能会在遇到第一个 中止解析器 的 解析错误 时中止,他们不希望应用本规范中描述的规则。
一致性检查器必须向用户报告至少一个解析错误条件,如果文档中存在一个或多个解析错误条件,并且如果文档中不存在解析错误条件,则必须不报告解析错误条件。如果文档中存在多个解析错误条件,一致性检查器可能会报告多个解析错误条件。
解析错误只是 HTML 语法 中的错误。除了检查解析错误之外,一致性检查器还将验证文档是否遵守本规范中描述的所有其他一致性要求。
一些解析错误在下面的表格中概述了专用代码,这些代码应由一致性检查器在报告中使用。
下面表格中的错误描述是非规范性的。
代码 | 描述 |
---|---|
abrupt-closing-of-empty-comment | 如果解析器遇到一个空 注释,该注释被 U+003E (>) 代码点(即, |
abrupt-doctype-public-identifier | 如果解析器在 DOCTYPE 公开标识符中遇到 U+003E (>) 代码点(例如, |
abrupt-doctype-system-identifier | 如果解析器在 DOCTYPE 系统标识符中遇到 U+003E (>) 代码点(例如, |
absence-of-digits-in-numeric-character-reference | 如果解析器遇到一个数字 字符引用,该引用不包含任何数字(例如, |
cdata-in-html-content | 如果解析器在外部内容(SVG 或 MathML)之外遇到 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 | |
end-tag-with-trailing-solidus | 如果解析器遇到一个 结束标记,该标记在关闭的 U+003E (>) 代码点之前有一个 U+002F (/) 代码点(例如, |
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 注释 的文本中遇到 输入流 的结尾,该文本位于 类似于 HTML 注释的语法结构在 |
eof-in-tag | 如果解析器在 开始标记 或 结束标记 中遇到 输入流 的结尾(例如, |
incorrectly-closed-comment | 如果解析器遇到一个 注释,该注释被“ |
incorrectly-opened-comment |
如果解析器遇到“ 此错误的一个可能原因是在 HTML 中使用 XML 标记声明(例如, |
invalid-character-sequence-after-doctype-name | 如果解析器在 DOCTYPE 名称之后遇到任何不是“ |
invalid-first-character-of-tag-name |
如果解析器在预期 开始标记 名称或 结束标记 名称的第一个代码点的地方遇到一个不是 ASCII 字母 的 代码点,则会发生此错误。如果预期开始标记,则此类代码点和前面的 U+003C (<) 被视为文本内容,并且所有后续内容被视为标记。而如果预期结束标记,则此类代码点和所有后续内容(直到 U+003E (>) 代码点(如果存在)或直到 输入流 的结尾)都被视为注释。 |
missing-attribute-value | 如果解析器在预期属性值的地方遇到 U+003E (>) 代码点(例如, |
missing-doctype-name | 如果解析器遇到缺少名称的 DOCTYPE(例如, |
missing-doctype-public-identifier | 如果解析器在预期 DOCTYPE 公共标识符的开头处遇到 U+003E (>) 代码点(例如, |
missing-doctype-system-identifier | 如果解析器在预期 DOCTYPE 系统标识符的开头处遇到 U+003E (>) 代码点(例如, |
missing-end-tag-name | 如果解析器在预期结束标签名称的地方遇到 U+003E (>) 代码点,即 |
missing-quote-before-doctype-public-identifier | 如果解析器遇到没有被引号引起来的 DOCTYPE 公共标识符(例如, |
missing-quote-before-doctype-system-identifier | 如果解析器遇到没有被引号引起来的 DOCTYPE 系统标识符(例如, |
missing-semicolon-after-character-reference |
如果解析器遇到没有以 U+003B (;) 代码点 结束的 字符引用,则会发生此错误。通常,解析器会像字符引用以 U+003B (;) 代码点结束一样进行处理;但是,在某些情况下,解析器会将后续代码点包含在字符引用中。 例如, |
missing-whitespace-after-doctype-public-keyword | 如果解析器遇到 DOCTYPE,其“ |
missing-whitespace-after-doctype-system-keyword | 如果解析器遇到 DOCTYPE,其“ |
missing-whitespace-before-doctype-name | 如果解析器遇到 DOCTYPE,其“ |
missing-whitespace-between-attributes | 如果解析器遇到没有以 ASCII 空格 分隔的 属性(例如, |
missing-whitespace-between-doctype-public-and-system-identifiers | 如果解析器遇到 DOCTYPE,其公共标识符和系统标识符没有以 ASCII 空格 分隔,则会发生此错误。在这种情况下,解析器会像存在 ASCII 空格一样进行处理。 |
nested-comment | 如果解析器遇到嵌套的 注释(例如, |
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 (/) 不存在一样进行处理。 开始标签名称中尾部的 U+002F (/) 只能在外国内容中用于指定自闭合标签。(自闭合标签在 HTML 中不存在。)对于空元素也允许使用它,但在这种情况下没有任何影响。 |
null-character-reference | 如果解析器遇到引用 U+0000 NULL 代码点 的数字 字符引用,则会发生此错误。解析器会将这些字符引用解析为 U+FFFD 替换字符。 |
surrogate-character-reference | |
surrogate-in-input-stream |
如果 输入流 包含 代理,则会发生此错误。这些 代码点 会被按原样解析,通常,在解析规则没有应用任何其他限制的情况下,会进入 DOM。 代理只能通过脚本 API(如 |
unexpected-character-after-doctype-system-identifier | 如果解析器遇到除 ASCII 空格 或闭合 U+003E (>) 之外的任何 代码点,这些代码点位于 DOCTYPE 系统标识符之后,则会发生此错误。解析器会忽略这些代码点。 |
unexpected-character-in-attribute-name |
如果解析器在 属性名称 中遇到 U+0022 (")、U+0027 (') 或 U+003C (<) 代码点,则会发生此错误。解析器会将这些代码点包含在属性名称中。 触发此错误的代码点通常是另一个语法结构的一部分,并且可能是属性名称周围出现错误的标志。 |
unexpected-character-in-unquoted-attribute-value |
如果解析器在没有引号引起来的 属性值 中遇到 U+0022 (")、U+0027 (')、U+003C (<)、U+003D (=) 或 U+0060 (`) 代码点,则会发生此错误。解析器会将这些代码点包含在属性值中。 触发此错误的代码点通常是另一个语法结构的一部分,并且可能是属性值周围出现错误的标志。 U+0060 (`) 位于触发此错误的代码点列表中,因为某些旧版用户代理将其视为引号。 例如,考虑以下标记
由于 U+0027 (') 代码点放置错误,解析器将“ |
unexpected-equals-sign-before-attribute-name |
如果解析器在属性名称之前遇到 U+003D (=) 代码点,则会发生此错误。在这种情况下,解析器会将 U+003D (=) 视为属性名称的第一个代码点。 此错误的常见原因是忘记了属性名称。 例如,考虑以下标记
由于忘记了属性名称,解析器将此标记视为一个具有两个属性的 |
unexpected-null-character | 如果解析器在某些位置的 输入流 中遇到 U+0000 NULL 代码点,则会发生此错误。一般情况下,这些代码点会被忽略,或者出于安全原因,会被替换为 U+FFFD 替换字符。 |
unexpected-question-mark-instead-of-tag-name |
如果解析器遇到 U+003F (?) 代码点,而此处应为开始标签名称的第一个代码点,则会发生此错误。U+003F (?) 及其后的所有内容,直至遇到 U+003E (>) 代码点(如果存在)或输入流结束,都会被视为注释。 例如,考虑以下标记
这将被解析为 此错误的常见原因是,在 HTML 中使用了 XML 处理指令(例如, |
unexpected-solidus-in-tag | 如果解析器遇到 U+002F (/) 代码点,而该代码点既不属于引用的 属性 值,也不紧跟在标签中的 U+003E (>) 代码点之后(例如, |
unknown-named-character-reference |
构成标记化阶段输入的代码点流,最初会被用户代理视为字节流(通常来自网络或本地文件系统)。字节根据特定的字符编码对实际字符进行编码,用户代理使用该编码将字节解码为字符。
对于 XML 文档,用户代理必须使用 XML 中给出的算法来确定字符编码。本节不适用于 XML 文档。 [XML]
通常,使用下面定义的 编码嗅探算法 来确定字符编码。
给定字符编码,必须将 输入字节流 中的字节转换为标记器的 输入流 中的字符,方法是将 输入字节流 和字符编码传递给 decode。
前导字节顺序标记 (BOM) 会导致忽略字符编码参数,并且它本身也会被跳过。
原始字节流中不符合编码标准的字节或字节序列(例如,UTF-8 输入字节流中的无效 UTF-8 字节序列)是符合性检查器应报告的错误。 [ENCODING]
解码器算法描述了如何处理无效输入;出于安全原因,务必严格遵循这些规则。处理无效字节序列方式的差异会导致脚本注入漏洞(“XSS”)等问题。
当 HTML 解析器解码输入字节流时,它会使用字符编码和 置信度。置信度可以是初步、确定或无关紧要。使用的编码以及对该编码的置信度是初步还是确定,将 在解析期间使用 来确定是否要 更改编码。如果不需要编码(例如,因为解析器正在操作 Unicode 流,并且根本不需要使用字符编码),那么 置信度 为无关紧要。
一些算法通过直接将字符添加到 输入流 来为解析器提供数据,而不是将字节添加到 输入字节流。
当 HTML 解析器要操作具有 已知确定编码 的输入字节流时,字符编码即为该编码,而 置信度 为确定。
在某些情况下,在解析文档之前明确确定编码可能不切实际。因此,本规范提供了一种包含可选预扫描的双遍机制。如下所述,实现允许在开始解析文档之前,对可用的字节应用简化的解析算法。然后,使用从该预解析和其他带外元数据得出的初步编码,启动真正的解析器。如果在加载文档时,用户代理发现与该信息冲突的字符编码声明,那么解析器可以重新调用以使用真正的编码执行文档解析。
用户代理必须使用以下算法(称为 编码嗅探算法)来确定解码文档时在第一遍中要使用的字符编码。该算法将用户代理可用的任何带外元数据(例如,文档的 Content-Type 元数据)和到目前为止可用的所有字节作为输入,并返回字符编码和一个 置信度,该置信度可以是初步或确定。
如果 BOM 嗅探 的结果是编码,则返回该编码,其 置信度 为确定。
虽然 decode 算法本身会根据字节顺序标记的存在来更改要使用的编码,但该算法还会嗅探 BOM 以设置正确的 文档的字符编码 和 置信度。
如果用户已明确指示用户代理使用特定编码覆盖文档的字符编码,则可以选择返回该编码,其 置信度 为确定。
通常,用户代理会在各个会话之间记住此类用户请求,并在某些情况下将其应用于 iframe
中的文档。
用户代理可以等待资源的更多字节变得可用,无论是在此步骤还是在该算法中的任何后续步骤。例如,用户代理可以等待 500 毫秒或 1024 字节,以先到者为准。通常,预解析源代码以查找编码可以提高性能,因为它减少了在找到编码信息时丢弃解析时使用的數據结构的需要。但是,如果用户代理延迟过久以获取数据来确定编码,那么延迟成本可能会超过预解析带来的任何性能改进。
字符编码声明的作者符合性要求将其限制为仅出现在 前 1024 个字节中。因此,鼓励用户代理对前 1024 个字节使用下面的预扫描算法(如这些步骤调用),但不要超过该限制。
如果传输层指定字符编码,并且该编码受支持,则返回该编码,其 置信度 为确定。
可选地 预扫描字节流以确定其编码,其结束条件 是用户代理决定扫描更多字节将效率低下时。鼓励用户代理仅预扫描前 1024 个字节。用户代理可以决定扫描任何字节都效率低下,在这种情况下,这些子步骤将完全跳过。
上述算法将返回字符编码或失败。如果它返回字符编码,那么返回相同的编码,其 置信度 为初步。
否则,如果用户代理有关于该页面可能编码的信息(例如,基于上次访问该页面时的编码),那么返回该编码,其 置信度 为初步。
用户代理可以尝试通过对数据流应用频率分析或其他算法来自动检测字符编码。此类算法可以使用关于资源的信息,而不是资源的内容,包括资源的地址。如果自动检测成功确定字符编码,并且该编码是受支持的编码,那么返回该编码,其 置信度 为初步。 [UNIVCHARDET]
通常不鼓励用户代理尝试自动检测通过网络获取的资源的编码,因为这样做涉及本质上不可互操作的启发式方法。尝试根据 HTML 文档的序言检测编码尤其棘手,因为 HTML 标记通常仅使用 ASCII 字符,并且 HTML 文档往往以大量标记而不是文本内容开头。
UTF-8 编码具有高度可检测的位模式。来自本地文件系统的文件,如果包含大于 0x7F 的字节且与 UTF-8 模式匹配,则很可能为 UTF-8,而字节序列不匹配的文档很可能不是。当用户代理可以检查整个文件,而不是仅仅检查前导字节时,专门检测 UTF-8 会特别有效。 [PPUTF8] [UTF8DET]
否则,返回一个 实现定义的 或用户指定的默认字符编码,并将其 置信度 设置为 暂定。
在受控环境或文档编码可以预定义的环境中(例如,专用于新网络的专用用户代理),建议使用全面的 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 编码,这些字节是 预扫描字节流以确定其编码 算法应用到的字节。否则,这些步骤将返回一个字符编码。
令 回退编码 为 null。
令 位置 为指向输入字节流中一个字节的指针,最初指向第一个字节。
预扫描 UTF-16 XML 声明:如果 位置 指向:
返回 UTF-16LE。
返回 UTF-16BE。
出于历史原因,前缀比 XML 中的 附录 F 长两个字节,并且不检查编码名称。
循环:如果 位置 指向:
<!--
`)将 位置 指针向前移动,使其指向紧接在找到的 0x3C 字节之后、且前面有两个 0x2D 字节(即 ASCII“-->”序列的末尾)的第一个 0x3E 字节。(两个 0x2D 字节可以与“<!--”序列中的字节相同。)
将 位置 指针向前移动,使其指向下一个 0x09、0x0A、0x0C、0x0D、0x20 或 0x2F 字节(上述字符序列中的字节)。
令 属性列表 为一个空的字符串列表。
令 已获取 pragma 为 false。
令 需要 pragma 为 null。
令 字符集 为 null 值(出于此算法的目的,它与无法识别的编码或空字符串不同)。
属性:获取属性 及其值。如果没有嗅探到属性,则跳到下面的 处理 步骤。
如果属性名称已存在于 属性列表 中,则返回到标记为 属性 的步骤。
将属性名称添加到 属性列表 中。
如果适用,则从以下列表中运行适当的步骤。
http-equiv
”如果属性值为“content-type
”,则将 已获取 pragma 设置为 true。
content
”应用 从 meta
元素中提取字符编码的算法,将属性值作为要解析的字符串提供。如果返回了字符编码,且 字符集 仍然设置为 null,则令 字符集 为返回的编码,并将 需要 pragma 设置为 true。
charset
”令 字符集 为从属性值 获取编码 的结果,并将 需要 pragma 设置为 false。
返回到标记为 属性 的步骤。
处理:如果 需要 pragma 为 null,则跳到下面标记为 下一个字节 的步骤。
如果 需要 pragma 为 true 但 已获取 pragma 为 false,则跳到下面标记为 下一个字节 的步骤。
如果 字符集 为失败,则跳到下面标记为 下一个字节 的步骤。
如果 字符集 为 UTF-16BE/LE,则将 字符集 设置为 UTF-8。
如果 字符集 为 x-user-defined,则将 字符集 设置为 windows-1252。
返回 字符集。
将 位置 指针向前移动,使其指向下一个 0x09 (HT)、0x0A (LF)、0x0C (FF)、0x0D (CR)、0x20 (SP) 或 0x3E (>) 字节。
重复 获取属性,直到无法找到更多属性,然后跳到下面标记为 下一个字节 的步骤。
<!
`)</
`)<?
`)将 位置 指针向前移动,使其指向紧接在找到的 0x3C 字节之后、第一个 0x3E 字节 (>)。
对该字节不做任何操作。
当 预扫描字节流以确定其编码 算法指示 获取属性 时,这意味着执行以下操作。
如果 位置 处的字节是 0x09 (HT)、0x0A (LF)、0x0C (FF)、0x0D (CR)、0x20 (SP) 或 0x2F (/) 之一,则将 位置 向前移动到下一个字节,并重新执行此步骤。
如果 位置 处的字节是 0x3E (>),则中止 获取属性 算法。没有属性。
否则,位置 处的字节是属性名称的开头。令 属性名称 和 属性值 为空字符串。
对 位置 处的字节进行以下处理。
将 位置 向前移动到下一个字节,并返回到上一步。
空格:如果 位置 处的字节是 0x09 (HT)、0x0A (LF)、0x0C (FF)、0x0D (CR) 或 0x20 (SP) 之一,则将 位置 向前移动到下一个字节,然后重复此步骤。
如果在位置 position 处的字节不为 0x3D (=),则中止获取属性算法。属性的名称为 attribute name 的值,其值为空字符串。
将 position 递进到 0x3D (=) 字节之后。
值: 如果在 position 处的字节为 0x09 (HT),0x0A (LF),0x0C (FF),0x0D (CR) 或 0x20 (SP) 之一,则将 position 递进到下一个字节,然后重复此步骤。
对 位置 处的字节进行以下处理。
对 位置 处的字节进行以下处理。
将 位置 向前移动到下一个字节,并返回到上一步。
当预扫描字节流以确定其编码算法中止而没有返回编码时,获取 XML 编码意味着执行此操作。
即使在text/html
中,也需要查找类似于 XML 声明的语法,以确保与现有内容的兼容性。
令 encodingPosition 为指向流开头的指针。
如果 encodingPosition 不指向字节序列 0x3C,0x3F,0x78,0x6D,0x6C (`<?xml
`) 的开头,则返回失败。
令 xmlDeclarationEnd 为指向输入字节流中下一个为 0x3E (>) 的字节的指针。如果没有这样的字节,则返回失败。
将 encodingPosition 设置为在当前 encodingPosition 处或之后出现的字节子序列 0x65,0x6E,0x63,0x6F,0x64,0x69,0x6E,0x67 (`encoding
`) 的第一个位置。如果没有这样的序列,则返回失败。
将 encodingPosition 递进到 0x67 (g) 字节之后。
当在 encodingPosition 处的字节小于或等于 0x20(即,它是 ASCII 空格或控制字符)时,将 encodingPosition 递进到下一个字节。
如果在 encodingPosition 处的字节不为 0x3D (=),则返回失败。
将 encodingPosition 递进到下一个字节。
当在 encodingPosition 处的字节小于或等于 0x20(即,它是 ASCII 空格或控制字符)时,将 encodingPosition 递进到下一个字节。
令 quoteMark 为在 encodingPosition 处的字节。
如果 quoteMark 不为 0x22 (") 或 0x27 (') 之一,则返回失败。
将 encodingPosition 递进到下一个字节。
令 encodingEndPosition 为在 encodingPosition 处或之后出现的下一个 quoteMark 的位置。如果 quoteMark 没有再次出现,则返回失败。
令 potentialEncoding 为在 encodingPosition(包含)和 encodingEndPosition(不包含)之间的字节序列。
如果 potentialEncoding 包含一个或多个字节值小于或等于 0x20 的字节,则返回失败。
如果 encoding 为UTF-16BE/LE,则将其更改为UTF-8。
返回 encoding。
为了互操作性,用户代理不应该使用与上面描述的算法返回不同结果的预扫描算法。(但是,如果你确实使用了,请至少让我们知道,这样我们就可以改进这个算法,让每个人都受益......)
用户代理必须支持在编码中定义的编码,包括但不限于,UTF-8,ISO-8859-2,ISO-8859-7,ISO-8859-8,windows-874,windows-1250,windows-1251,windows-1252,windows-1254,windows-1255,windows-1256,windows-1257,windows-1258,GBK,Big5,ISO-2022-JP,Shift_JIS,EUC-KR,UTF-16BE,UTF-16LE,UTF-16BE/LE 和 x-user-defined。用户代理不得支持其他编码。
以上禁止支持例如 CESU-8,UTF-7,BOCU-1,SCSU,EBCDIC 和 UTF-32。本规范没有尝试在其算法中支持禁止的编码;因此,支持和使用禁止的编码会导致意外行为。[CESU8] [UTF7] [BOCU1] [SCSU]
当解析器要求用户代理更改编码时,它必须执行以下步骤。如果上面描述的编码嗅探算法无法找到字符编码,或者如果它找到了与文件实际编码不匹配的字符编码,则可能会发生这种情况。
如果用于解释输入流的编码为UTF-16BE/LE,则将置信度设置为确定并返回。新的编码将被忽略;如果它不是相同的编码,那么它显然是错误的。
如果新的编码为UTF-16BE/LE,则将其更改为UTF-8。
如果新的编码为x-user-defined,则将其更改为windows-1252。
如果新的编码与用于解释输入流的编码相同或等效,则将置信度设置为确定并返回。当文件中找到的编码信息与编码嗅探算法确定的编码相匹配时,以及在解析器第二次遍历时,如果第一次遍历发现前面部分中描述的编码嗅探算法未能找到正确的编码时,就会发生这种情况。
如果当前解码器转换的最后一个字节之前的所有字节在当前编码和新编码中都具有相同的 Unicode 解释,并且如果用户代理支持在运行时更改转换器,那么用户代理可以在运行时更改为新编码的转换器。将文档的字符编码和用于转换输入流的编码设置为新的编码,将置信度设置为确定,并返回。
否则,重新启动导航算法,并将historyHandling 设置为 "replace
",其他输入保持不变,但这次跳过编码嗅探算法,而是直接将编码设置为新编码,并将置信度设置为确定。只要有可能,应该在不实际联系网络层的情况下完成此操作(字节应该从内存中重新解析),即使例如,文档被标记为不可缓存。如果这不可能,并且联系网络层将涉及重复使用非“GET
”方法的请求,那么改为将置信度设置为确定,并忽略新编码。资源将被错误地解释。用户代理可能会通知用户这种情况,以帮助应用程序开发。
此算法仅在 meta
元素上发现新的编码声明时被调用。
输入流 由当输入字节流被解码或来自直接操作输入流的各种 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" 字符不是流中的真实字符,而是表示没有更多字符。
插入模式 是一个状态变量,用于控制树构建阶段的主要操作。
最初,插入模式 为 "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 必须遵循以下步骤
将 last 设置为 false。
将 node 设置为 打开元素堆栈 中的最后一个节点。
循环:如果 node 是打开元素堆栈中的第一个节点,则将 last 设置为 true,并且如果解析器是在 HTML 片段解析算法(片段情况)中创建的,则将 node 设置为传递给该算法的 上下文 元素。
如果 node 是一个 select
元素,请运行以下子步骤
如果 node 是一个 td
或 th
元素,并且 last 为 false,则将 插入模式 切换到 "in cell" 并返回。
如果 node 是一个 tbody
、thead
或 tfoot
元素,则将 插入模式 切换到 "in table body" 并返回。
如果 node 是一个 caption
元素,则将 插入模式 切换到 "in caption" 并返回。
如果 node 是一个 colgroup
元素,则将 插入模式 切换到 "in column group" 并返回。
如果 node 是一个 head
元素,并且 last 为 false,则将 插入模式 切换到 "in head" 并返回。
如果 node 是一个 frameset
元素,则将 插入模式 切换到 "in frameset" 并返回。(片段情况)
如果 node 是一个 html
元素,则运行以下子步骤
如果 head
元素指针 为 null,则将 插入模式 切换到 "before head" 并返回。(片段情况)
否则,head
元素指针 不为 null,将 插入模式 切换到 "after head" 并返回。
现在让 node 成为 node 在 打开元素栈 中的前一个节点。
返回到标记为 loop 的步骤。
最初,打开元素栈 是空的。栈向下增长;栈顶部的节点是最先添加到栈的节点,栈底部的节点是最近添加到栈的节点(尽管当栈在随机访问方式下被操作时,作为 处理错误嵌套标签 的一部分)。
"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 元素最终会出现在 活动格式化元素列表 中:a
、b
、big
、code
、em
、font
、i
、nobr
、s
、small
、strike
、strong
、tt
和 u
。
在解析 HTML 文档时找到的所有其他元素。
通常,特殊 元素的开始和结束标签令牌会得到专门处理,而 普通 元素的令牌则属于“任何其他开始标签”和“任何其他结束标签”子句,树构建器的某些部分会检查 打开元素堆栈 中的特定元素是否属于 特殊 类别。但是,某些元素(例如,option
元素)的开始或结束标签令牌会得到专门处理,但仍不属于 特殊 类别,因此在其他地方会得到 普通 处理。
当以下算法在匹配状态下终止时,据说 打开元素堆栈 在由元素类型列表 list 组成的特定范围内包含元素 target node
将 node 初始化为 当前节点(堆栈中最底部的节点)。
如果 node 是目标节点,则在匹配状态下终止。
否则,如果 node 是 list 中的元素类型之一,则在失败状态下终止。
否则,将 node 设置为 打开元素堆栈 中的上一项,并返回步骤 2。(这永远不会失败,因为如果堆栈顶部(html
元素)被访问,循环将始终在上一步骤中终止。)
当 打开元素堆栈 在范围内包含特定元素 时,它 在由以下元素类型组成的特定范围内包含该元素
applet
caption
html
table
td
th
marquee
object
template
mi
mo
mn
ms
mtext
annotation-xml
foreignObject
desc
title
当 打开元素堆栈 在列表项范围内包含特定元素 时,它 在由以下元素类型组成的特定范围内包含该元素
当 打开元素堆栈 在按钮范围内包含特定元素 时,它 在由以下元素类型组成的特定范围内包含该元素
当 打开元素堆栈 在表格范围内包含特定元素 时,它 在由以下元素类型组成的特定范围内包含该元素
当 打开元素堆栈 在选择范围内包含特定元素 时,它 在由所有元素类型组成的特定范围内包含该元素,但以下类型除外
如果在任何时候 打开元素堆栈 中的任何元素被移至 Document
树中的新位置或从该树中移除,则不会发生任何情况。特别是,堆栈在这种情况下不会发生改变。这可能会导致(除其他奇怪的效果外)内容被追加到不再位于 DOM 中的节点。
在某些情况下(即,当 关闭嵌套错误的格式化元素 时),堆栈会以随机访问方式进行操作。
最初,活动格式化元素列表 是空的。它用于处理嵌套错误的 格式化元素标签。
该列表包含 格式化 类别中的元素和 标记。当进入 applet
、object
、marquee
、template
、td
、th
和 caption
元素时,会插入 标记,它们用于防止格式化“泄漏”至 applet
、object
、marquee
、template
、td
、th
和 caption
元素中。
此外,活动格式化元素列表 中的每个元素都与其创建的令牌相关联,以便在需要时可以为此令牌创建更多元素。
当以下步骤要求 UA 将元素 element 推入活动格式化元素列表 时,UA 必须执行以下步骤
如果在最后一个 标记(如果有)之后或列表中没有任何 标记 的情况下,活动格式化元素列表 中已经存在三个元素,它们与 element 具有相同的标签名称、命名空间和属性,那么从 活动格式化元素列表 中移除最早的此类元素。出于这些目的,属性必须按解析器创建元素时的状态进行比较;如果两个元素的所有解析属性都可以配对,并且每对中的两个属性具有相同的名称、命名空间和值(属性的顺序无关紧要),那么这两个元素具有相同的属性。
这是诺亚方舟条款。但每个家庭要三个人而不是两个人。
将 element 添加到 活动格式化元素列表 中。
当以下步骤要求 UA 重建活动格式化元素 时,UA 必须执行以下步骤
如果 活动格式化元素列表 中没有条目,则无需重建;停止此算法。
如果 活动格式化元素列表 中的最后一个(最近添加的)条目是 标记,或者它是在 打开元素堆栈 中的元素,则无需重建;停止此算法。
让 entry 是 活动格式化元素列表 中的最后一个(最近添加的)元素。
倒带:如果 活动格式化元素列表 中没有条目位于 entry 之前,则跳至标记为创建的步骤。
让 entry 是 活动格式化元素列表 中比 entry 早一个条目的条目。
Advance:令 entry 为 活动格式化元素列表 中比 entry 晚一个的元素。
Create:插入 用于创建元素 entry 的标记的 HTML 元素,以获得 new element。
用 new element 的条目替换列表中 entry 的条目。
如果 活动格式化元素列表 中 new element 的条目不是列表中的最后一个条目,则返回到标记为 advance 的步骤。
这将重新打开在当前正文、单元格或标题(以最年轻者为准)中打开的所有尚未显式关闭的格式化元素。
按照本规范的编写方式,活动格式化元素列表 始终按时间顺序排列,最近添加的元素在最前面,最晚添加的元素在最后(当然,在执行上述算法的步骤 7 到 10 时除外)。
当以下步骤要求 UA 清除活动格式化元素列表直到最后一个标记 时,UA 必须执行以下步骤
最初,head
元素指针 和 form
元素指针 都为空。
一旦解析了 head
元素(无论是隐式还是显式),head
元素指针 将被设置为指向该节点。
form
元素指针 指向最后打开的 form
元素,并且其结束标记尚未出现。由于历史原因,它用于使表单控件在遇到严重错误的标记时与表单关联。在 template
元素内部,它会被忽略。
如果 脚本已启用,则 脚本标志 被设置为“启用”,该脚本与解析器创建时关联的 Document
相关联,否则被设置为“禁用”。
即使解析器是作为 HTML 片段解析算法 的一部分创建的,脚本标志 也可以启用,即使在这种情况下 script
元素不会执行。
frameset-ok 标志 在解析器创建时被设置为“ok”。在看到某些标记后,它被设置为“not ok”。
实现必须表现得好像它们使用以下状态机对 HTML 进行标记化。该状态机必须从 数据状态 开始。大多数状态消耗单个字符,这可能会有各种副作用,并且要么将状态机切换到一个新状态以 重新消耗 当前输入字符,要么切换到一个新状态以消耗 下一个字符,要么保持在同一状态以消耗下一个字符。某些状态的行为更复杂,可以在切换到另一个状态之前消耗多个字符。在某些情况下,标记化状态也会受到树构建阶段的影响。
当一个状态说要 重新消耗 在指定状态下匹配的字符时,这意味着切换到该状态,但当它尝试消耗 下一个输入字符 时,请提供 当前输入字符 而不是。
某些状态的确切行为取决于 插入模式 和 打开元素栈。某些状态还使用 临时缓冲区 来跟踪进度,而 字符引用状态 使用 返回状态 返回到它被调用的状态。
标记化步骤的输出是一系列零个或多个以下标记:DOCTYPE、开始标记、结束标记、注释、字符、文件结束。DOCTYPE 标记具有名称、公共标识符、系统标识符和 force-quirks 标志。当创建 DOCTYPE 标记时,它的名称、公共标识符和系统标识符必须标记为丢失(这是一个与空字符串不同的状态),并且 force-quirks 标志 必须设置为 off(它的另一个状态是 on)。开始和结束标记具有标记名称、自闭合标志 和属性列表,每个属性都有名称和值。当创建开始或结束标记时,它的 自闭合标志 必须取消设置(它的另一个状态是设置),并且它的属性列表必须为空。注释和字符标记具有数据。
当发出标记时,它必须立即由 树构建 阶段处理。树构建阶段会影响标记化阶段的状态,并可以将其他字符插入到流中。(例如,script
元素会导致脚本执行并使用 动态标记插入 API 将字符插入正在标记化的流中。)
创建标记和发出标记是不同的操作。标记可以被创建但隐式放弃(永远不会发出),例如,如果在处理被解析为开始标记的字符时文件意外结束。
当发出一个开始标记,其 自闭合标志 被设置时,如果该标志在被树构建阶段处理时没有被 确认,则这是一个 非空 HTML 元素开始标记带尾部斜杠 解析错误。
当发出一个结束标记,其带有属性时,则这是一个 结束标记带属性 解析错误。
当发出一个结束标记,其 自闭合标志 被设置时,则这是一个 结束标记带尾部斜杠 解析错误。
合适的结束标记 是一个结束标记,其标记名称与从该标记器发出的最后一个开始标记的标记名称匹配(如果有)。如果该标记器没有发出任何开始标记,则没有结束标记是合适的。
如果 返回状态 是 属性值(双引号)状态、属性值(单引号)状态 或 属性值(无引号)状态,则称 字符引用 被 消耗为属性的一部分。
当一个状态说要 刷新作为字符引用消耗的代码点 时,这意味着对于 临时缓冲区 中的每个 代码点(按照它们添加到缓冲区的顺序),用户代理必须将缓冲区中的代码点追加到当前属性的值(如果字符引用被 消耗为属性的一部分),或者将代码点发出为字符标记(否则)。
在标记器的每个步骤之前,用户代理必须首先检查 解析器暂停标志。如果它是 true,则标记器必须中止对标记器任何嵌套调用的处理,将控制权返回给调用者。
标记器状态机由以下小节中定义的状态组成。
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
script
",则切换到 脚本数据双重转义状态。否则,切换到 脚本数据转义状态。将 当前输入字符 作为字符标记发出。消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
script
",则切换到 脚本数据转义状态。否则,切换到 脚本数据双重转义状态。将 当前输入字符 作为字符标记发出。消耗 下一个输入字符
消耗 下一个输入字符
当用户代理离开属性名称状态时(如果合适,在发出标记令牌之前),必须将完整的属性名称与同一令牌上的其他属性进行比较;如果令牌上已经存在一个具有完全相同名称的属性,那么这是一个 重复属性 解析错误,并且必须从令牌中删除新属性。
如果以这种方式从令牌中删除了一个属性,那么它以及与之关联的值(如果有)将永远不会被解析器再次使用,因此实际上会被丢弃。但是,以这种方式删除属性不会改变它作为标记器目的的“当前属性”的状态。
消耗 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
如果接下来的几个字符是
消费 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消费下一个输入字符
消费下一个输入字符
消费下一个输入字符
消费下一个输入字符
消费下一个输入字符
消费下一个输入字符
消费下一个输入字符
消费下一个输入字符
消费下一个输入字符
消费下一个输入字符
消费下一个输入字符
如果从当前输入字符开始的六个字符与单词 "PUBLIC" 的ASCII 不区分大小写匹配,则消费这些字符并切换到DOCTYPE 公共关键字之后状态。
否则,如果从当前输入字符开始的六个字符与单词 "SYSTEM" 的ASCII 不区分大小写匹配,则消费这些字符并切换到DOCTYPE 系统关键字之后状态。
否则,这是一个DOCTYPE 名称之后的无效字符序列解析错误。将当前 DOCTYPE 标记的强制怪异模式标志设置为 on。重新消费在虚假 DOCTYPE 状态。
消费下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消费 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
消耗 下一个输入字符
U+0000 NULL 字符在树构建阶段处理,作为 在外部内容中 插入模式的一部分,这是 CDATA 区段唯一可能出现的地方。
消耗 下一个输入字符
消耗 下一个输入字符
将 临时缓冲区 设置为空字符串。将一个 U+0026 和号(&)字符追加到 临时缓冲区。消耗 下一个输入字符
消耗尽可能多的字符,其中消耗的字符是 命名字符引用 表的第一列中的一个标识符。在消耗时将每个字符追加到 临时缓冲区。
如果字符引用被用作属性的一部分,并且匹配的最后一个字符不是 U+003B 分号字符 (;),以及下一个输入字符是 U+003D 等号字符 (=) 或ASCII 字母数字字符,那么出于历史原因,将作为字符引用消耗的代码点刷新,并切换到返回状态。
否则
如果标记包含(不在属性中)字符串 I'm ¬it; I tell you
,字符引用将被解析为“not”,就像 I'm ¬it; I tell you
(这是一个解析错误)。但如果标记是 I'm ∉ I tell you
,字符引用将被解析为“notin;”,导致 I'm ∉ I tell you
(没有解析错误)。
但是,如果标记包含字符串 I'm ¬it; I tell you
在属性中,不会解析任何字符引用,字符串保持不变(并且没有解析错误)。
消耗下一个输入字符
将字符引用代码设置为零 (0)。
消耗下一个输入字符
消耗下一个输入字符
消耗下一个输入字符
消耗下一个输入字符
消耗下一个输入字符
检查字符引用代码
如果数字大于 0x10FFFF,那么这是一个超出 Unicode 范围的字符引用解析错误。将字符引用代码设置为 0xFFFD。
如果数字是 0x0D,或者一个控制字符,它不是ASCII 空白,那么这是一个控制字符引用解析错误。如果数字是下表第一列中的数字之一,那么找到第一列中包含该数字的行,并将字符引用代码设置为该行第二列中的数字。
数字 | 代码点 | |
---|---|---|
0x80 | 0x20AC | 欧元符号 (€) |
0x82 | 0x201A | 单低 9 引号 (‚) |
0x83 | 0x0192 | 小写拉丁字母 f 带钩 (ƒ) |
0x84 | 0x201E | 双低 9 引号 („) |
0x85 | 0x2026 | 水平省略号 (…) |
0x86 | 0x2020 | 匕首 (†) |
0x87 | 0x2021 | 双匕首 (‡) |
0x88 | 0x02C6 | 修饰字母抑扬符 (ˆ) |
0x89 | 0x2030 | 千分号 (‰) |
0x8A | 0x0160 | 大写拉丁字母 S 带抑扬符 (Š) |
0x8B | 0x2039 | 单左指向角度引号 (‹) |
0x8C | 0x0152 | 大写拉丁字母连字 OE (Œ) |
0x8E | 0x017D | 大写拉丁字母 Z 带抑扬符 (Ž) |
0x91 | 0x2018 | 左单引号 (‘) |
0x92 | 0x2019 | 右单引号 (’) |
0x93 | 0x201C | 左双引号 (“) |
0x94 | 0x201D | 右双引号 (”) |
0x95 | 0x2022 | 项目符号 (•) |
0x96 | 0x2013 | 短破折号 (–) |
0x97 | 0x2014 | 长破折号 (—) |
0x98 | 0x02DC | 小波浪号 (˜) |
0x99 | 0x2122 | 商标符号 (™) |
0x9A | 0x0161 | 带抑扬符的小写拉丁字母 s (š) |
0x9B | 0x203A | 单右指向角引号 (›) |
0x9C | 0x0153 | 小写拉丁字母连字符 oe (œ) |
0x9E | 0x017E | 带抑扬符的小写拉丁字母 z (ž) |
0x9F | 0x0178 | 带分音符的大写拉丁字母 y (Ÿ) |
将 临时缓冲区 设置为一个空字符串。在 临时缓冲区 中追加一个与 字符引用代码 相等的代码点。 将作为字符引用所消耗的代码点刷新。切换到 返回状态。
树构建阶段的输入是来自 标记化 阶段的一系列标记。当创建解析器时,树构建阶段与一个 DOM Document
对象关联。此阶段的“输出”包括动态修改或扩展该文档的 DOM 树。
本规范没有定义交互式用户代理何时必须呈现 Document
以便用户可以使用它,或者何时必须开始接受用户输入。
当解析器从标记化器中发出每个标记时,用户代理必须按照以下列表中的相应步骤执行,这些步骤被称为 树构建分派器
annotation-xml
元素且该标记是一个开始标记,其标记名称是“svg”下一个标记 是将要由 树构建分派器 处理的标记(即使该标记随后被忽略)。
如果节点是以下元素之一,则它是一个 MathML 文本集成点
mi
元素mo
元素mn
元素ms
元素mtext
元素如果节点是以下元素之一,则它是一个 HTML 集成点
annotation-xml
元素,其开始标记标记具有一个名为“encoding”的属性,其值与字符串“text/html
”的 ASCII 不区分大小写 匹配annotation-xml
元素,其开始标记标记具有一个名为“encoding”的属性,其值与字符串“application/xhtml+xml
”的 ASCII 不区分大小写 匹配foreignObject
元素desc
元素title
元素如果所讨论的节点是传递给 HTML 片段解析算法 的 上下文 元素,则该元素的开始标记标记是在 HTML 片段解析算法 中创建的“假”标记。
下面提到的并非所有标记名称在本规范中都是符合规范的标记名称;其中许多标记名称是为了处理遗留内容而包含的。它们仍然是实现需要实现以声明符合规范的算法的一部分。
下面描述的算法对生成的 DOM 树的深度或标记名称、属性名称、属性值、Text
节点等的长度没有限制。虽然鼓励实现者 避免任意限制,但认识到实际问题可能会迫使用户代理强加嵌套深度约束。
当解析器正在处理标记时,它可以启用或禁用 养父模式。这会影响以下算法。
插入节点的适当位置(可选地使用特定覆盖目标)是在运行以下步骤后返回的元素中的位置
如果指定了覆盖目标,则令 target 为覆盖目标。
否则,令 target 为 当前节点。
使用以下列表中的第一个匹配步骤确定 调整后的插入位置
table
、tbody
、tfoot
、thead
或 tr
元素当内容在表格中错误嵌套时,就会发生养父模式。
运行以下子步骤
如果有 最后一个模板 并且要么没有 最后一个表格,要么有一个,但是 最后一个模板 在 打开元素堆栈 中比 最后一个表格 更低(最近添加),则:令 调整后的插入位置 为 最后一个模板 的 模板内容 中,在其最后一个子节点(如果有)之后,并中止这些步骤。
如果没有 最后一个表格,则令 调整后的插入位置 为 打开元素堆栈 中的第一个元素(html
元素)中,在其最后一个子节点(如果有)之后,并中止这些步骤。 (片段情况)
如果 最后一个表格 有一个父节点,则令 调整后的插入位置 为 最后一个表格 的父节点中,在 最后一个表格 之前,并中止这些步骤。
令 前一个元素 为 打开元素堆栈 中在 最后一个表格 上面的元素。
令 调整后的插入位置 为 前一个元素 中,在其最后一个子节点(如果有)之后。
这些步骤涉及的部分原因是,元素(尤其是这种情况下的 table
元素)可能在解析器插入元素之后,被脚本在 DOM 中移动,甚至完全从 DOM 中删除。
令 调整后的插入位置 为 target 中,在其最后一个子节点(如果有)之后。
如果 调整后的插入位置 在 template
元素中,则改为将其放在 template
元素的 模板内容 中,在其最后一个子节点(如果有)之后。
返回 调整后的插入位置。
当以下步骤要求 UA 为标记创建元素 时,在特定 给定命名空间 中,并且具有特定 预期父节点,UA 必须运行以下步骤
如果 活动推测 HTML 解析器 不为空,则返回 创建推测性模拟元素 的结果,给定 给定命名空间、给定标记的标记名称以及给定标记的属性。
否则,可以选择性地 创建假设的模拟元素,给定 给定命名空间,给定标记的标签名称,以及给定标记的属性。
结果不用。此步骤允许从非假设解析开始发起 假设获取。获取在此阶段仍然是假设的,因为例如,到元素插入时,预期父级可能已从文档中删除。
设 文档 为 预期父级 的 节点文档。
设 本地名称 为标记的标签名称。
设 is 为给定标记中 “is
” 属性的值,如果存在这样的属性,否则为 null。
设 定义 为给定 文档、给定命名空间、本地名称 和 is 时,查找自定义元素定义 的结果。
如果 定义 非空且解析器不是作为 HTML 片段解析算法 的一部分创建的,则设 将执行脚本 为 true。否则,设其为 false。
如果 将执行脚本 为 true,则
增加 文档 的 抛出动态标记插入计数器。
如果 JavaScript 执行上下文堆栈 为空,则 执行微任务检查点。
设 元素 为给定 文档、localName、给定命名空间、null 和 is 时,创建元素 的结果。如果 将执行脚本 为 true,则设置 同步自定义元素标志;否则,保留其未设置状态。
这将导致 自定义元素构造函数 运行,如果 将执行脚本 为 true。然而,由于我们增加了 抛出动态标记插入计数器,这不会导致 新的字符插入到标记器中,或 文档被清除。
追加 给定标记中的每个属性到 元素。
这可以 将自定义元素回调反应排队 用于 attributeChangedCallback
,这可能会立即运行(在下一步中)。
即使 is
属性控制 创建 自定义内置元素,但在执行相关 自定义元素构造函数 时,它不存在;它将在这一步中与所有其他属性一起追加。
如果 将执行脚本 为 true,则
调用自定义元素反应 在 队列 中。
减少 文档 的 抛出动态标记插入计数器。
如果 元素 具有一个 xmlns
属性 *在 XMLNS 命名空间 中*,其值不完全与元素的命名空间相同,则这是一个 解析错误。类似地,如果 元素 具有一个 xmlns:xlink
属性在 XMLNS 命名空间 中,其值不是 XLink 命名空间,则这是一个 解析错误。
如果 元素 是一个 与表单关联的元素 且不是一个 与表单关联的自定义元素,form
元素指针 非空,打开元素堆栈 上没有 template
元素,元素 既不是 列出的,也没有 form
属性,且 预期父级 与 form
元素指针 指向的元素位于同一 树 中,则 关联 元素 与 form
元素指针 指向的 form
元素,并设置 元素 的 解析器插入标志。
返回 元素。
要 在调整后的插入位置插入元素,带有元素 元素
设 调整后的插入位置 为 插入节点的适当位置。
如果无法在 调整后的插入位置 插入 元素,则中止这些步骤。
如果解析器不是作为 HTML 片段解析算法 的一部分创建的,则将一个新的 元素队列 推入 元素 的 相关代理 的 自定义元素反应堆栈 中。
在 调整后的插入位置 插入 元素。
如果解析器不是作为 HTML 片段解析算法 的一部分创建的,则从 元素 的 相关代理 的 自定义元素反应堆栈 中弹出 元素队列,并在该队列中 调用自定义元素反应。
如果 调整后的插入位置 无法接受更多元素,例如,因为它是一个 Document
且已具有元素子级,则 元素 被丢弃在地板上。
当以下步骤要求用户代理 插入一个外部元素 用于给定命名空间中的标记,并带有布尔值 onlyAddToElementStack 时,用户代理必须运行以下步骤
设 调整后的插入位置 为 插入节点的适当位置。
设 元素 为在给定命名空间中 为标记创建元素 的结果,其中预期父级为 调整后的插入位置 所在的元素。
如果 onlyAddToElementStack 为 false,则运行 在调整后的插入位置插入元素,带有 元素。
返回 元素。
当以下步骤要求用户代理 插入一个 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 命名空间 |
当以下步骤要求用户代理在处理令牌时插入字符时,用户代理必须运行以下步骤
令 data 为传递给算法的字符,或者,如果没有明确指定字符,则为正在处理的字符令牌的字符。
令 调整后的插入位置 为插入节点的适当位置。
如果 调整后的插入位置 位于 Document
节点中,则返回。
如果在 调整后的插入位置 之前有一个 Text
节点,则将 data 附加到该 Text
节点的 data。
否则,创建一个新的 Text
节点,其 data 为 data,其 node document 与 调整后的插入位置 所在的元素相同,并将新创建的节点插入 调整后的插入位置。
以下是一些解析器的示例输入及其导致的 Text
节点数量,假设用户代理会执行脚本。
输入 | Text 节点数量 |
---|---|
| 文档中一个 Text 节点,包含 "AB"。 |
| 三个 Text 节点;脚本前的 "A"、脚本的内容以及脚本后的 "BC"(解析器将附加到脚本创建的 Text 节点)。 |
| 文档中两个相邻的 Text 节点,包含 "A" 和 "BC"。 |
| 表格前一个 Text 节点,包含 "ABCD"。(这是由寄养父节点引起的。) |
| 表格前一个 Text 节点,包含 "A B C"(A-空格-B-空格-C)。(这是由寄养父节点引起的。) |
| 表格前一个 Text 节点,包含 "A BC"(A-空格-B-C),表格内一个 Text 节点(作为 tbody 的子节点),包含单个空格字符。(即使其他令牌随后被忽略,由非字符令牌分隔的空格字符也不会受到寄养父节点的影响。) |
当以下步骤要求用户代理在处理注释令牌时插入注释时,可以选择带有显式插入位置 position,用户代理必须运行以下步骤
令 data 为正在处理的注释令牌中给出的数据。
如果指定了 position,则令 调整后的插入位置 为 position。否则,令 调整后的插入位置 为插入节点的适当位置。
创建一个 Comment
节点,其 data
属性设置为 data,其 node document 与 调整后的插入位置 所在的节点相同。
将新创建的节点插入 调整后的插入位置。
通用原始文本元素解析算法 和 通用 RCDATA 元素解析算法 包括以下步骤。这些算法总是响应开始标签令牌被调用。
插入 HTML 元素 用于该令牌。
如果调用了 通用原始文本元素解析算法,则将标记器切换到 RAWTEXT 状态;否则,调用了 通用 RCDATA 元素解析算法,则将标记器切换到 RCDATA 状态。
当以下步骤要求 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 必须将 当前节点 从 打开元素堆栈 中弹出。
Document
对象具有关联的解析器无法更改模式标志(布尔值)。它最初为 false。
当用户代理要应用 "initial" 插入模式 的规则时,用户代理必须按如下方式处理令牌
忽略该标记。
如果 DOCTYPE 标记的名称不是 "html
",或者标记的公共标识符不缺失,或者标记的系统标识符既不缺失也不为 "
",那么存在一个 解析错误。about:legacy-compat
将一个 DocumentType
节点附加到 Document
节点,其 名称 设置为 DOCTYPE 标记中给出的名称,或者如果名称缺失则为空字符串;其 公共标识符 设置为 DOCTYPE 标记中给出的公共标识符,或者如果公共标识符缺失则为空字符串;其 系统标识符 设置为 DOCTYPE 标记中给出的系统标识符,或者如果系统标识符缺失则为空字符串。
这也确保了 DocumentType
节点被返回作为 doctype
属性的 Document
对象的值。
然后,如果文档不是 一个 iframe
srcdoc
文档,并且 解析器不能更改模式标志 为 false,并且 DOCTYPE 标记匹配以下列表中的一个条件,那么将 Document
设置为 怪癖模式
html
"。-//W3O//DTD W3 HTML Strict 3.0//EN//
"-/W3C/DTD HTML 4.0 Transitional/EN
"HTML
"http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd
"+//Silmaril//dtd html Pro v0r11 19970101//
" 开头。-//AS//DTD HTML 3.0 asWedit + extensions//
" 开头。-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//
" 开头。-//IETF//DTD HTML 2.0 Level 1//
" 开头。-//IETF//DTD HTML 2.0 Level 2//
" 开头。-//IETF//DTD HTML 2.0 Strict Level 1//
" 开头。-//IETF//DTD HTML 2.0 Strict Level 2//
" 开头。-//IETF//DTD HTML 2.0 Strict//
" 开头。-//IETF//DTD HTML 2.0//
" 开头。-//IETF//DTD HTML 2.1E//
" 开头。-//IETF//DTD HTML 3.0//
" 开头。-//IETF//DTD HTML 3.2 Final//
" 开头。-//IETF//DTD HTML 3.2//
" 开头。-//IETF//DTD HTML 3//
" 开头。-//IETF//DTD HTML Level 0//
" 开头。-//IETF//DTD HTML Level 1//
" 开头。-//IETF//DTD HTML Level 2//
" 开头。-//IETF//DTD HTML Level 3//
" 开头。-//IETF//DTD HTML Strict Level 0//
" 开头。-//IETF//DTD HTML Strict Level 1//
" 开头。-//IETF//DTD HTML Strict Level 2//
" 开头。-//IETF//DTD HTML Strict Level 3//
" 开头。-//IETF//DTD HTML Strict//
" 开头。-//IETF//DTD HTML//
" 开头。-//Metrius//DTD Metrius Presentational//
" 开头。-//Microsoft//DTD Internet Explorer 2.0 HTML Strict//
" 开头。-//Microsoft//DTD Internet Explorer 2.0 HTML//
" 开头。-//Microsoft//DTD Internet Explorer 2.0 Tables//
" 开头。-//Microsoft//DTD Internet Explorer 3.0 HTML Strict//
" 开头。-//Microsoft//DTD Internet Explorer 3.0 HTML//
" 开头。-//Microsoft//DTD Internet Explorer 3.0 Tables//
" 开头。-//Netscape Comm. Corp.//DTD HTML//
" 开头。-//Netscape Comm. Corp.//DTD Strict HTML//
" 开头。-//O'Reilly and Associates//DTD HTML 2.0//
" 开头。-//O'Reilly and Associates//DTD HTML Extended 1.0//
" 开头。-//O'Reilly and Associates//DTD HTML Extended Relaxed 1.0//
" 开头。-//SQ//DTD HTML 2.0 HoTMetaL + extensions//
" 开头。-//SoftQuad Software//DTD HoTMetaL PRO 6.0::19990601::extensions to HTML 4.0//
" 开头。-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::extensions to HTML 4.0//
" 开头。-//Spyglass//DTD HTML 2.0 Extended//
" 开头。-//Sun Microsystems Corp.//DTD HotJava HTML//
" 开头。-//Sun Microsystems Corp.//DTD HotJava Strict HTML//
" 开头。-//W3C//DTD HTML 3 1995-03-24//
" 开头。-//W3C//DTD HTML 3.2 Draft//
" 开头。-//W3C//DTD HTML 3.2 Final//
" 开头。-//W3C//DTD HTML 3.2//
" 开头。-//W3C//DTD HTML 3.2S Draft//
" 开头。-//W3C//DTD HTML 4.0 Frameset//
" 开头。-//W3C//DTD HTML 4.0 Transitional//
" 开头。-//W3C//DTD HTML Experimental 19960712//
" 开头。-//W3C//DTD HTML Experimental 970421//
" 开头。-//W3C//DTD W3 HTML//
" 开头。-//W3O//DTD W3 HTML 3.0//
" 开头。-//WebTechs//DTD Mozilla HTML 2.0//
" 开头。-//WebTechs//DTD Mozilla HTML//
" 开头。-//W3C//DTD HTML 4.01 Frameset//
" 开头。-//W3C//DTD HTML 4.01 Transitional//
" 开头。否则,如果文档不是 一个 iframe
srcdoc
文档,并且 解析器不能更改模式标志 为 false,并且 DOCTYPE 标记匹配以下列表中的一个条件,那么将 Document
设置为 有限怪癖模式
-//W3C//DTD XHTML 1.0 Frameset//
" 开头。-//W3C//DTD XHTML 1.0 Transitional//
" 开头。-//W3C//DTD HTML 4.01 Frameset//
" 开头。-//W3C//DTD HTML 4.01 Transitional//
" 开头。系统标识符和公共标识符字符串必须以 ASCII 不区分大小写 的方式与上面列表中给出的值进行比较。系统标识符的值为空字符串,在上述条件中不被视为缺失。
然后,将 插入模式 切换为 "before html
"。
如果文档不是 一个 iframe
srcdoc
文档,那么这是一个 解析错误;如果 解析器不能更改模式标志 为 false,那么将 Document
设置为 怪癖模式。
在任何情况下,将 插入模式 切换为 "before html
",然后重新处理该标记。
当用户代理要应用 "before html" 插入模式 的规则时,用户代理必须按如下方式处理该标记
解析错误。忽略该标记。
忽略该标记。
为该标记创建一个元素,在 HTML 命名空间 中,以 Document
作为预期的父节点。将其附加到 Document
对象。将此元素放入 打开元素堆栈 中。
将 插入模式 切换为 "before head
"。
按如下面的 "其他任何内容" 条目中所述进行操作。
解析错误。忽略该标记。
创建一个 html
元素,其 节点文档 为 Document
对象。将其附加到 Document
对象。将此元素放入 打开元素堆栈 中。
该文档元素最终可能会从文档
对象中移除,例如,通过脚本移除;在这种情况下,不会发生任何特殊的事情,内容会继续按照下一节中描述的顺序追加到节点。
当用户代理需要应用“头部之前”插入模式的规则时,用户代理必须按照以下方式处理标记
忽略该标记。
解析错误。忽略该标记。
按如下面的 "其他任何内容" 条目中所述进行操作。
解析错误。忽略该标记。
为一个没有属性的“head”开始标记插入一个 HTML 元素.
重新处理当前标记。
当用户代理需要应用“头部内”插入模式的规则时,用户代理必须按照以下方式处理标记
插入字符.
解析错误。忽略该标记。
为该标记插入一个 HTML 元素。立即从打开元素栈中弹出当前节点。
确认标记的自闭合标志,如果它被设置。
为该标记插入一个 HTML 元素。立即从打开元素栈中弹出当前节点。
确认标记的自闭合标志,如果它被设置。
如果活动的推测性 HTML 解析器为空,那么
否则,如果该元素有一个http-equiv
属性,其值为ASCII 忽略大小写匹配字符串“Content-Type
”,并且该元素有一个content
属性,并且将从 meta
元素中提取字符编码的算法应用于该属性的值返回一个编码,并且置信度当前为暂定,那么将编码更改为提取的编码。
该推测性 HTML 解析器不会推测性地应用字符编码声明,以降低实现复杂度。
遵循通用原始文本元素解析算法。
将插入模式切换到“头部 noscript 内”。
运行以下步骤
将调整后的插入位置设置为插入节点的合适位置。
为该标记创建一个元素,该元素位于HTML 命名空间中,其预期父元素为调整后的插入位置所在的元素。
将该元素的解析器文档设置为文档
,并将该元素的强制异步设置为 false。
这确保了,如果该脚本是外部的,则该脚本中的任何document.write()
调用将在内联执行,而不是破坏文档,正如在大多数其他情况下那样。它还阻止该脚本在看到结束标记之前执行。
如果该解析器是作为HTML 片段解析算法的一部分创建的,则将script
元素的已开始设置为 true。(片段情况)
如果该解析器是通过document.write()
或document.writeln()
方法调用的,则可以选择将script
元素的已开始设置为 true。(例如,用户代理可以使用此子句来阻止通过document.write()
插入的跨域脚本在网络速度慢的情况下或页面加载时间过长的情况下执行。)
将新创建的元素插入到调整后的插入位置。
将标记器切换到脚本数据状态。
按如下面的 "其他任何内容" 条目中所述进行操作。
将模板开始标记设置为开始标记。
将框架集允许标志设置为“不允许”。
将“模板内”推送到模板插入模式栈中,使其成为新的当前模板插入模式。
将调整后的插入位置设置为插入节点的合适位置。
将预期父元素设置为调整后的插入位置所在的元素。
将文档设置为预期父元素的节点文档。
如果以下任何一项为 false
shadowrootmode
不在none状态;则 插入一个 HTML 元素 用于该标记。
否则
设 声明式影子宿主元素 为 调整后的当前节点。
设 模式 为 模板开始标记 的 shadowrootmode
属性的值。
设 可克隆 为真,如果 模板开始标记 有一个 shadowrootclonable
属性;否则为假。
设 可序列化 为真,如果 模板开始标记 有一个 shadowrootserializable
属性;否则为假。
设 委托焦点 为真,如果 模板开始标记 有一个 shadowrootdelegatesfocus
属性;否则为假。
如果 声明式影子宿主元素 是一个 影子宿主,则 在调整后的插入位置插入一个元素,该元素的模板为 模板。
否则
如果 打开元素栈 中没有 模板
元素,则这是一个 解析错误;忽略该标记。
否则,运行以下步骤
解析错误。忽略该标记。
从 打开元素栈 中弹出 当前节点(它将是 head
元素)。
将 插入模式 切换到 " after head" 。
重新处理该标记。
当用户代理要应用 " in head noscript" 插入模式 的规则时,用户代理必须按如下方式处理该标记
解析错误。忽略该标记。
按如下面的 "其他任何内容" 条目中所述进行操作。
解析错误。忽略该标记。
解析错误.
从 打开元素栈 中弹出 当前节点 (它将是一个 noscript
元素);新的 当前节点 将是一个 head
元素。
重新处理该标记。
当用户代理要应用 " after head" 插入模式 的规则时,用户代理必须按如下方式处理该标记
插入字符.
解析错误。忽略该标记。
插入一个 HTML 元素 用于该标记。
将 frameset-ok 标记 设置为 "not ok"。
插入一个 HTML 元素 用于该标记。
将 插入模式 切换到 " in frameset" 。
解析错误.
从 打开元素栈 中删除 head
元素指针 指向的节点。(它可能此时不是 当前节点)。
head
元素指针 此时不能为 null。
按如下面的 "其他任何内容" 条目中所述进行操作。
解析错误。忽略该标记。
插入一个 HTML 元素,用于一个没有属性的 "body" 开始标记标记。
重新处理当前标记。
当用户代理要应用 " in body" 插入模式 的规则时,用户代理必须按如下方式处理该标记
解析错误。忽略该标记。
重建活动格式化元素,如果有。
重建活动格式化元素,如果有。
将 frameset-ok 标记 设置为 "not ok"。
解析错误。忽略该标记。
解析错误.
否则,对于该标记上的每个属性,检查该属性是否已经存在于 打开元素栈 的顶层元素上。如果没有,则将该属性及其对应值添加到该元素中。
解析错误.
如果打开元素堆栈 只有一个节点,如果打开元素堆栈 上的第二个元素不是一个body
元素,或者如果打开元素堆栈 上有一个template
元素,则忽略此标记。(片段情况 或者堆栈上有一个template
元素)
否则,将frameset-ok 标记 设置为“不ok”;然后,对于标记上的每个属性,检查该属性是否已存在于打开元素堆栈 上的第二个元素(body
元素)上,如果没有,则将该属性及其对应的值添加到该元素。
解析错误.
如果打开元素堆栈 只有一个节点,或者如果打开元素堆栈 上的第二个元素不是一个body
元素,则忽略此标记。(片段情况 或者堆栈上有一个template
元素)
如果frameset-ok 标记 设置为“不ok”,则忽略此标记。
否则,执行以下步骤
从其父节点(如果有)中删除打开元素堆栈 上的第二个元素。
为该标记插入一个 HTML 元素。
将插入模式 切换到“frameset 中”。
如果模板插入模式堆栈 不为空,则使用“模板中”插入模式 的规则来处理该标记。
否则,执行以下步骤
如果打开元素堆栈 没有一个body
元素在范围内,则这是一个解析错误;忽略此标记。
否则,如果打开元素堆栈 中有一个节点既不是一个dd
元素,也不是一个dt
元素,也不是一个li
元素,也不是一个optgroup
元素,也不是一个option
元素,也不是一个p
元素,也不是一个rb
元素,也不是一个rp
元素,也不是一个rt
元素,也不是一个rtc
元素,也不是一个tbody
元素,也不是一个td
元素,也不是一个tfoot
元素,也不是一个th
元素,也不是一个thead
元素,也不是一个tr
元素,也不是body
元素,也不是html
元素,则这是一个解析错误。
如果打开元素堆栈 没有一个body
元素在范围内,则这是一个解析错误;忽略此标记。
否则,如果打开元素堆栈 中有一个节点既不是一个dd
元素,也不是一个dt
元素,也不是一个li
元素,也不是一个optgroup
元素,也不是一个option
元素,也不是一个p
元素,也不是一个rb
元素,也不是一个rp
元素,也不是一个rt
元素,也不是一个rtc
元素,也不是一个tbody
元素,也不是一个td
元素,也不是一个tfoot
元素,也不是一个th
元素,也不是一个thead
元素,也不是一个tr
元素,也不是body
元素,也不是html
元素,则这是一个解析错误。
重新处理该标记。
如果打开元素堆栈 有一个p
元素在按钮范围内,则关闭一个p
元素。
为该标记插入一个 HTML 元素。
如果打开元素堆栈 有一个p
元素在按钮范围内,则关闭一个p
元素。
如果当前节点 是一个HTML 元素,其标记名称为以下之一:“h1”,"h2","h3","h4","h5","h6",则这是一个解析错误;将当前节点 从打开元素堆栈 中弹出。
为该标记插入一个 HTML 元素。
如果打开元素堆栈 有一个p
元素在按钮范围内,则关闭一个p
元素。
为该标记插入一个 HTML 元素。
如果下一个标记 是一个 U+000A LINE FEED (LF) 字符标记,则忽略该标记并继续处理下一个标记。(pre
块开头的换行符被忽略,作为一种作者便利。)
将frameset-ok 标记 设置为“不ok”。
如果form
元素指针 不为空,并且打开元素堆栈 上没有template
元素,则这是一个解析错误;忽略此标记。
否则
如果打开元素堆栈 有一个p
元素在按钮范围内,则关闭一个p
元素。
插入 HTML 元素 用于该标记,并且如果 打开元素栈 上没有 模板
元素,则将 form
元素指针 设置为指向创建的元素。
运行以下步骤
将 frameset-ok 标志 设置为“不 ok”。
将 node 初始化为 当前节点(栈中最底部的节点)。
循环:如果 node 是一个 li
元素,则执行以下子步骤
否则,将 node 设置为 打开元素栈 中的前一个条目,并返回到标记为循环的步骤。
完成:如果 打开元素栈 在按钮作用域中包含一个p
元素,则 关闭一个p
元素。
最后,插入 HTML 元素 用于该标记。
运行以下步骤
将 frameset-ok 标志 设置为“不 ok”。
将 node 初始化为 当前节点(栈中最底部的节点)。
循环:如果 node 是一个 dd
元素,则执行以下子步骤
如果 node 是一个 dt
元素,则执行以下子步骤
否则,将 node 设置为 打开元素栈 中的前一个条目,并返回到标记为循环的步骤。
完成:如果 打开元素栈 在按钮作用域中包含一个p
元素,则 关闭一个p
元素。
最后,插入 HTML 元素 用于该标记。
如果 打开元素栈 在按钮作用域中包含一个p
元素,则 关闭一个p
元素。
插入 HTML 元素 用于该标记。
将标记器切换到 纯文本状态。
一旦看到了标记名称为“plaintext”的开始标记,所有剩余的标记将是字符标记(以及最终的文件结束标记),因为无法将标记器从 纯文本状态 切换出去。但是,由于树构建器仍然处于其现有的插入模式,它可能会 重建活动格式化元素,同时处理这些字符标记。这意味着解析器可以将其他元素插入到 plaintext
元素中。
如果 打开元素栈 在作用域中包含一个button
元素,则执行以下子步骤
重建活动格式化元素,如果有的话。
插入 HTML 元素 用于该标记。
将 frameset-ok 标志 设置为“不 ok”。
如果 打开元素栈 不 在作用域中包含 一个与标记相同标记名称的 HTML 元素,则这是一个 解析错误;忽略该标记。
否则,运行以下步骤
如果 打开元素栈 不 在按钮作用域中包含一个p
元素,则这是一个 解析错误;插入 HTML 元素 用于没有属性的“p”开始标记标记。
如果 打开元素栈 不 在列表项作用域中包含一个li
元素,则这是一个 解析错误;忽略该标记。
否则,运行以下步骤
如果打开元素栈不包含作用域内的元素,该元素是与标记具有相同标签名称的HTML 元素,则这是一个解析错误;忽略标记。
否则,运行以下步骤
如果打开元素栈不包含作用域内的元素,该元素是HTML 元素,其标签名称为 "h1"、"h2"、"h3"、"h4"、"h5" 或 "h6" 中的其中之一,则这是一个解析错误;忽略标记。
否则,运行以下步骤
深呼吸,然后按照下面 "其他结束标签" 条目中描述的操作进行。
如果活动格式化元素列表在列表末尾和列表上的最后一个标记(或如果列表上没有标记,则为列表开头)之间包含一个a
元素,则这是一个解析错误;针对标记运行收养机构算法,然后从活动格式化元素列表和打开元素栈中删除该元素(如果收养机构算法尚未删除它,则可能不会删除它(如果元素不在表格作用域中)。
在非标准流<a href="a">a<table><a href="b">b</table>x
中,第一个a
元素将在看到第二个元素时关闭,而 "x" 字符将位于指向 "b" 的链接内,而不是指向 "a" 的链接内。这是因为外部a
元素不在表格作用域中(这意味着表格开头的常规</a>
结束标签不会关闭外部a
元素)。结果是,两个a
元素间接地彼此嵌套 — 非标准标记在解析时通常会产生非标准 DOM。
重建活动格式化元素(如果有)。
插入 HTML 元素,用于标记。将该元素推送到活动格式化元素列表中。
重建活动格式化元素(如果有)。
插入 HTML 元素,用于标记。将该元素推送到活动格式化元素列表中。
重建活动格式化元素(如果有)。
如果打开元素栈包含作用域内的 nobr
元素,则这是一个解析错误;针对标记运行收养机构算法,然后再次重建活动格式化元素(如果有)。
插入 HTML 元素,用于标记。将该元素推送到活动格式化元素列表中。
针对标记运行收养机构算法。
重建活动格式化元素(如果有)。
插入 HTML 元素,用于标记。
将frameset-ok 标志设置为 "not ok"。
如果打开元素栈不包含作用域内的元素,该元素是与标记具有相同标签名称的HTML 元素,则这是一个解析错误;忽略标记。
否则,运行以下步骤
如果文档
不设置为怪异模式,并且打开元素栈包含按钮作用域内的 p
元素,则关闭 p
元素。
插入 HTML 元素,用于标记。
将frameset-ok 标志设置为 "not ok"。
解析错误。从标记中删除属性,并按照下一条目的描述进行操作;即,假设这是一个没有属性的 "br" 起始标签标记,而不是它实际的结束标签标记。
重建活动格式化元素(如果有)。
插入 HTML 元素,用于标记。立即从打开元素栈中弹出当前节点。
确认标记的自闭合标志(如果设置)。
将frameset-ok 标志设置为 "not ok"。
重建活动格式化元素(如果有)。
插入 HTML 元素,用于标记。立即从打开元素栈中弹出当前节点。
确认标记的自闭合标志(如果设置)。
如果标记没有名为 "type" 的属性,或者有,但该属性的值与字符串 "hidden
" 的ASCII 不区分大小写匹配,则:将frameset-ok 标志设置为 "not ok"。
插入 HTML 元素,用于标记。立即从打开元素栈中弹出当前节点。
确认标记的自闭合标志(如果设置)。
如果打开元素栈包含按钮作用域内的 p
元素,则关闭 p
元素。
插入 HTML 元素,用于标记。立即从打开元素栈中弹出当前节点。
确认标记的自闭合标志,如果已设置。
将frameset-ok 标志设置为“不正常”。
解析错误。将标记的标签名更改为“img”并重新处理它。(别问。)
运行以下步骤
插入一个 HTML 元素 用于该标记。
如果下一个标记是 U+000A LINE FEED (LF) 字符标记,则忽略该标记并继续处理下一个标记。(在textarea
元素开头的新行被忽略,作为作者的便利。)
将标记器切换到RCDATA 状态。
将frameset-ok 标志设置为“不正常”。
如果打开元素栈在按钮范围内包含一个p
元素,则关闭一个p
元素。
重建活动格式化元素,如果有。
将frameset-ok 标志设置为“不正常”。
遵循通用原始文本元素解析算法。
将frameset-ok 标志设置为“不正常”。
遵循通用原始文本元素解析算法。
遵循通用原始文本元素解析算法。
重建活动格式化元素,如果有。
插入一个 HTML 元素 用于该标记。
将frameset-ok 标志设置为“不正常”。
如果插入模式是“在表格中”,“在标题中”,“在表格主体中”,“在行中”或“在单元格中”之一,则将插入模式切换到“在表格中的 select 中”。否则,将插入模式切换到“在 select 中”。
如果当前节点是一个option
元素,则从打开元素栈中弹出当前节点。
重建活动格式化元素,如果有。
插入一个 HTML 元素 用于该标记。
如果打开元素栈在范围内包含一个ruby
元素,则生成隐式结束标签。如果当前节点现在不是一个ruby
元素,则这是一个解析错误。
插入一个 HTML 元素 用于该标记。
如果打开元素栈在范围内包含一个ruby
元素,则生成隐式结束标签,除了rtc
元素。如果当前节点现在不是一个rtc
元素或一个ruby
元素,则这是一个解析错误。
插入一个 HTML 元素 用于该标记。
重建活动格式化元素,如果有。
调整 MathML 属性 用于该标记。(这修复了不是全部小写的 MathML 属性的情况。)
调整外来属性 用于该标记。(这修复了命名空间属性的使用,尤其是 XLink。)
插入一个外来元素 用于该标记,带有MathML 命名空间 和 false。
如果标记的自闭合标志 已设置,则从打开元素栈中弹出当前节点,并确认标记的自闭合标志。
重建活动格式化元素,如果有。
调整 SVG 属性 用于该标记。(这修复了不是全部小写的 SVG 属性的情况。)
调整外来属性 用于该标记。(这修复了命名空间属性的使用,尤其是 SVG 中的 XLink。)
插入一个外来元素 用于该标记,带有SVG 命名空间 和 false。
如果标记的自闭合标志 已设置,则从打开元素栈中弹出当前节点,并确认标记的自闭合标志。
解析错误。忽略该标记。
重建活动格式化元素,如果有。
插入一个 HTML 元素 用于该标记。
运行以下步骤
当上面的步骤说用户代理要关闭一个p
元素 时,这意味着用户代理必须执行以下步骤
收养机构算法,它以一个标记token 作为其唯一参数,该算法正在运行,它包含以下步骤
令subject 为token 的标签名。
如果当前节点 是一个HTML 元素,其标签名是subject,并且当前节点 不在活动格式化元素列表 中,则从打开元素栈 中弹出当前节点 并返回。
令outerLoopCounter 为 0。
当真时
如果outerLoopCounter 大于或等于 8,则返回。
将outerLoopCounter 增加 1。
令formattingElement 为活动格式化元素列表 中的最后一个元素,它
如果没有这样的元素,则返回,并改为按照上面“任何其他结束标签”条目中所述进行操作。
如果 `formattingElement` 在 `已打开元素堆栈` 中,但元素不在 `作用域中`,那么这是一个 `解析错误`;返回。
设 `furthestBlock` 为 `已打开元素堆栈` 中最顶层的节点,该节点在堆栈中比 `formattingElement` 低,并且是 `特殊` 类别中的元素。可能不存在。
如果没有 `furthestBlock`,那么 UA 必须首先从 `已打开元素堆栈` 的底部弹出所有节点,从 `当前节点` 开始,直到并包括 `formattingElement`,然后从 `活动格式化元素列表` 中删除 `formattingElement`,最后返回。
设 `commonAncestor` 为 `已打开元素堆栈` 中 `formattingElement` 上方的元素。
设一个书签标记 `formattingElement` 在 `活动格式化元素列表` 中的位置,相对于列表中它两侧的元素。
设 `node` 和 `lastNode` 为 `furthestBlock`。
设 `innerLoopCounter` 为 0。
当真时
将 `innerLoopCounter` 加 1。
设 `node` 为 `已打开元素堆栈` 中 `node` 上方的元素,或者如果 `node` 不再在 `已打开元素堆栈` 中(例如,因为它被此算法删除),则在 `node` 被删除之前,`已打开元素堆栈` 中 `node` 上方的元素。
如果 `node` 是 `formattingElement`,那么 `中断`。
如果 `innerLoopCounter` 大于 3 且 `node` 在 `活动格式化元素列表` 中,那么从 `活动格式化元素列表` 中删除 `node`。
为创建元素 `node` 的标记 `创建元素`,在 `HTML 命名空间` 中,使用 `commonAncestor` 作为预期父级;用新元素的条目替换 `活动格式化元素列表` 中 `node` 的条目,用新元素的条目替换 `已打开元素堆栈` 中 `node` 的条目,并设 `node` 为新元素。
如果 `last node` 是 `furthestBlock`,那么将上述书签移动到 `活动格式化元素列表` 中新 `node` 的紧后面。
将 `lastNode` `追加` 到 `node`。
将 `lastNode` 设为 `node`。
将上一步骤中 `lastNode` 最终成为的元素插入 `插入节点的适当位置`,但使用 `commonAncestor` 作为 _覆盖目标_。
为创建 `formattingElement` 的标记 `创建元素`,在 `HTML 命名空间` 中,使用 `furthestBlock` 作为预期父级。
获取 `furthestBlock` 的所有子节点,并将它们追加到上一步骤中创建的元素。
将该新元素追加到 `furthestBlock`。
从 `活动格式化元素列表` 中删除 `formattingElement`,并将新元素插入 `活动格式化元素列表` 中上述书签的位置。
从 `已打开元素堆栈` 中删除 `formattingElement`,并将新元素插入 `已打开元素堆栈` 中 `furthestBlock` 在该堆栈中的位置的紧下方。
此算法的名称“收养机构算法”源于它导致元素更改父级的方式,并且与 `其他可能的算法` 对处理嵌套错误的内容形成对比。
当用户代理要应用“`文本`”`插入模式` 的规则时,用户代理必须按如下方式处理标记
这永远不可能是 U+0000 NULL 字符;标记器将这些字符转换为 U+FFFD REPLACEMENT CHARACTER 字符。
解析错误.
如果 `活动推测性 HTML 解析器` 为 null,且 `JavaScript 执行上下文堆栈` 为空,那么 `执行微任务检查点`。
设 `script` 为 `当前节点`(它将是 `script
元素)。
设 `旧插入点` 的值与当前 `插入点` 的值相同。设 `插入点` 为 `下一个输入字符` 的正前方。
将解析器的 `脚本嵌套级别` 加 1。
如果 `活动推测性 HTML 解析器` 为 null,那么 `准备脚本元素` `script`。这可能会导致某些脚本执行,这可能会导致 `将新字符插入标记器`,并且可能会导致标记器输出更多标记,从而导致 `解析器重新进入调用`。
将解析器的 `脚本嵌套级别` 减 1。如果解析器的 `脚本嵌套级别` 为零,那么将 `解析器暂停标志` 设为 false。
设 `插入点` 的值为 `旧插入点`。(换句话说,将 `插入点` 恢复为它的先前值。此值可能是“undefined”值。)
在此阶段,如果 `挂起的解析阻塞脚本` 不为 null,那么
将 `解析器暂停标志` 设为 true,并中止对标记器任何嵌套调用的处理,将控制权交回调用者。(当调用者返回到“外部”树构建阶段时,标记将恢复。)
此特定解析器的树构建阶段 `正在被重新进入调用`,例如,从对 `document.write()
的调用进行调用。
当 `挂起的解析阻塞脚本` 不为 null 时
设 `脚本` 为 `挂起的解析阻塞脚本`。
将 `挂起的解析阻塞脚本` 设为 null。
为 HTML 解析器的此实例 `启动推测性 HTML 解析器`。
如果解析器的 `Document
`有阻止脚本的样式表` 或 `脚本` 的 `准备好被解析器执行` 为 false:`循环运行事件循环`,直到解析器的 `Document
`没有阻止脚本的样式表`,且 `脚本` 的 `准备好被解析器执行` 变成 true。
如果此 `解析器已被中止`,那么返回。
这可能会发生,例如,当 `循环运行事件循环` 算法正在运行时,`Document
被 `销毁`,或者在 `Document
上调用了 `document.open()
方法。
为 HTML 解析器的此实例 `停止推测性 HTML 解析器`。
将解析器的脚本嵌套级别增加一(在这一步之前,它应该为零,因此这将其设置为一)。
执行脚本元素the script。执行脚本元素
让插入点再次变为未定义。
当用户代理需要应用“in table” 插入模式的规则时,用户代理必须按如下方式处理标记
table
、tbody
、template
、tfoot
、thead
或tr
元素让pending table character tokens成为一个空的标记列表。
将插入模式切换到“in table text”并重新处理标记。
解析错误。忽略标记。
将堆栈清除到表格上下文。(见下文。)
为标记插入一个 HTML 元素,然后将插入模式切换到“in caption”。
将堆栈清除到表格上下文。(见下文。)
为标记插入一个 HTML 元素,然后将插入模式切换到“in column group”。
将堆栈清除到表格上下文。(见下文。)
为一个没有属性的“colgroup”开始标记标记插入一个 HTML 元素,然后将插入模式切换到“in column group”。
重新处理当前标记。
将堆栈清除到表格上下文。(见下文。)
为标记插入一个 HTML 元素,然后将插入模式切换到“in table body”。
将堆栈清除到表格上下文。(见下文。)
为一个没有属性的“tbody”开始标记标记插入一个 HTML 元素,然后将插入模式切换到“in table body”。
重新处理当前标记。
解析错误.
如果打开元素堆栈在表格范围内没有table
元素,则忽略标记。
否则
从该堆栈中弹出元素,直到从堆栈中弹出一个table
元素为止。
重新处理该标记。
如果打开元素堆栈在表格范围内没有table
元素,则这是一个解析错误;忽略标记。
否则
从该堆栈中弹出元素,直到从堆栈中弹出一个table
元素为止。
解析错误。忽略标记。
如果标记没有名为“type”的属性,或者有,但该属性的值与字符串“hidden
”不区分大小写匹配,则:按照下面“其他任何情况”条目中描述的进行操作。
否则
解析错误.
为标记插入一个 HTML 元素。
如果设置了标记的自闭合标志,则确认标记的自闭合标志。
解析错误.
如果打开元素堆栈上有template
元素,或者form
元素指针不为空,则忽略标记。
否则
为标记插入一个 HTML 元素,并将form
元素指针设置为指向创建的元素。
当上面的步骤要求 UA 将堆栈清除到表格上下文时,这意味着 UA 必须在当前节点不是table
、template
或html
元素时,从打开元素堆栈中弹出元素。
这与在表格范围内存在元素步骤中使用的元素列表相同。
在这个过程之后,当前节点成为一个html
元素,这是一个片段情况。
当用户代理需要应用“in table text” 插入模式的规则时,用户代理必须按如下方式处理标记
解析错误。忽略标记。
将字符标记追加到pending table character tokens列表。
如果pending table character tokens列表中的任何标记是字符标记,且这些字符标记不是ASCII 空格,则这是一个解析错误:使用“in table”插入模式中的“其他任何情况”条目中给出的规则重新处理pending table character tokens列表中的字符标记。
否则,插入由pending table character tokens列表给出的字符。
当用户代理需要应用“in caption” 插入模式的规则时,用户代理必须按如下方式处理标记
如果打开元素堆栈在表格范围内没有caption
元素,则这是一个解析错误;忽略标记。(片段情况)
否则
现在,如果当前节点不是一个caption
元素,则这是一个解析错误。
从该栈中弹出元素,直到从栈中弹出 caption
元素。
如果 打开元素栈 中没有 在表格作用域中包含 caption
元素,则这是一个 解析错误;忽略此标记。(片段情况)
否则
现在,如果 当前节点 不是 caption
元素,则这是一个 解析错误。
从该栈中弹出元素,直到从栈中弹出 caption
元素。
重新处理该标记。
解析错误。忽略此标记。
当用户代理要应用 "in column group" 插入模式 的规则时,用户代理必须按如下方式处理此标记。
插入字符.
解析错误。忽略此标记。
插入 HTML 元素 用于此标记。立即从 打开元素栈 中弹出 当前节点。
确认此标记的 自闭合标志,如果它已设置。
解析错误。忽略此标记。
如果 当前节点 不是 colgroup
元素,则这是一个 解析错误;忽略此标记。
重新处理该标记。
当用户代理要应用 "in table body" 插入模式 的规则时,用户代理必须按如下方式处理此标记。
将栈清除回表格正文上下文。(参见下文。)
插入 HTML 元素 用于此标记,然后将 插入模式 切换为 "in row"。
解析错误.
将栈清除回表格正文上下文。(参见下文。)
插入 HTML 元素 用于一个没有属性的 "tr" 开始标签标记,然后将 插入模式 切换为 "in row"。
重新处理当前标记。
如果 打开元素栈 中没有 在表格作用域中包含 与此标记标签名称相同的 HTML 元素,则这是一个 解析错误;忽略此标记。
否则
将栈清除回表格正文上下文。(参见下文。)
如果 打开元素栈 中没有 在表格作用域中包含 tbody
、thead
或 tfoot
元素,则这是一个 解析错误;忽略此标记。
否则
将栈清除回表格正文上下文。(参见下文。)
从 打开元素栈 中弹出 当前节点。将 插入模式 切换为 "in table"。
重新处理该标记。
解析错误。忽略此标记。
当上述步骤要求 UA 将栈清除回表格正文上下文 时,意味着 UA 必须,当 当前节点 不是 tbody
、tfoot
、thead
、template
或 html
元素时,从 打开元素栈 中弹出元素。
当用户代理要应用 "in row" 插入模式 的规则时,用户代理必须按如下方式处理此标记。
将栈清除回表格行上下文。(参见下文。)
插入 HTML 元素 用于此标记,然后将 插入模式 切换为 "in cell"。
如果 打开元素栈 中没有 在表格作用域中包含 tr
元素,则这是一个 解析错误;忽略此标记。
否则
将栈清除回表格行上下文。(参见下文。)
从 打开元素栈 中弹出 当前节点(它将是一个 tr
元素)。将 插入模式 切换为 "in table body"。
如果 打开元素栈 中没有 在表格作用域中包含 tr
元素,则这是一个 解析错误;忽略此标记。
否则
将栈清除回表格行上下文。(参见下文。)
从 打开元素栈 中弹出 当前节点(它将是一个 tr
元素)。将 插入模式 切换为 "in table body"。
重新处理该标记。
如果打开元素栈没有在表格作用域中包含元素,该元素是一个与标记名称相同的HTML 元素,则这是一个解析错误;忽略此标记。
如果打开元素栈没有在表格作用域中包含一个tr
元素,则忽略此标记。
否则
清除栈回到表格行上下文。(见下文)
从打开元素栈中弹出当前节点(它将是一个tr
元素)。将插入模式切换到“表格主体中”。
重新处理该标记。
解析错误。忽略此标记。
当上述步骤要求UA清除栈回到表格行上下文时,这意味着UA必须在当前节点不是tr
、template
或html
元素的情况下,从打开元素栈中弹出元素。
此过程完成后,当前节点是一个html
元素,这是一个片段情况。
当用户代理需要应用“单元格中”插入模式的规则时,用户代理必须按以下方式处理此标记
如果打开元素栈没有在表格作用域中包含元素,该元素是一个与标记名称相同的HTML 元素,则这是一个解析错误;忽略此标记。
否则
现在,如果当前节点不是一个与标记名称相同的HTML 元素,则这是一个解析错误。
关闭单元格(见下文)并重新处理此标记。
解析错误。忽略此标记。
如果打开元素栈没有在表格作用域中包含元素,该元素是一个与标记名称相同的HTML 元素,则这是一个解析错误;忽略此标记。
否则,关闭单元格(见下文)并重新处理此标记。
当上述步骤说要关闭单元格时,它们意味着要运行以下算法
打开元素栈不能同时在表格作用域中包含一个td
和一个th
元素,也不能在调用关闭单元格算法时同时包含两者。
当用户代理需要应用“选择中”插入模式的规则时,用户代理必须按以下方式处理此标记
解析错误。忽略此标记。
解析错误。忽略此标记。
如果当前节点是一个option
元素,则从打开元素栈中弹出该节点。
插入HTML 元素,以表示此标记。
如果当前节点是一个option
元素,则从打开元素栈中弹出该节点。
如果当前节点是一个optgroup
元素,则从打开元素栈中弹出该节点。
插入HTML 元素,以表示此标记。
如果当前节点是一个option
元素,则从打开元素栈中弹出该节点。
如果当前节点是一个optgroup
元素,则从打开元素栈中弹出该节点。
插入HTML 元素,以表示此标记。立即从打开元素栈中弹出当前节点。
确认此标记的自闭合标记,如果已设置。
首先,如果当前节点是一个option
元素,并且打开元素栈中紧接其前的节点是一个optgroup
元素,则从打开元素栈中弹出当前节点。
如果打开元素栈没有在选择作用域中包含一个select
元素,则这是一个解析错误;忽略此标记。(片段情况)
否则
解析错误.
如果打开元素栈没有在选择作用域中包含一个select
元素,则忽略此标记。(片段情况)
否则
它将像结束标记一样被处理。
解析错误.
如果 打开元素栈 没有 在选择范围中包含一个 select
元素,则忽略该标记。 (片段情况)
否则
从 打开元素栈 中弹出元素,直到一个 select
元素被弹出栈。
重新处理该标记。
解析错误。忽略该标记。
当用户代理要应用 "在表格中的选择" 插入模式 的规则时,用户代理必须按如下方式处理该标记。
解析错误.
从 打开元素栈 中弹出元素,直到一个 select
元素被弹出栈。
重新处理该标记。
解析错误.
如果 打开元素栈 没有 在表格范围中包含一个 具有与该标记相同标签名称的 HTML 元素,则忽略该标记。
否则
从 打开元素栈 中弹出元素,直到一个 select
元素被弹出栈。
重新处理该标记。
当用户代理要应用 "在模板" 插入模式 的规则时,用户代理必须按如下方式处理该标记。
解析错误。忽略该标记。
如果 打开元素栈 上没有 template
元素,则 停止解析。 (片段情况)
否则,这是一个 解析错误。
从 打开元素栈 中弹出元素,直到一个 template
元素被弹出栈。
重新处理该标记。
当用户代理要应用 "主体之后" 插入模式 的规则时,用户代理必须按如下方式处理该标记。
解析错误。忽略该标记。
如果解析器是作为 HTML 片段解析算法 的一部分创建的,则这是一个 解析错误;忽略该标记。 (片段情况)
停止解析.
当用户代理要应用 "在框架集" 插入模式 的规则时,用户代理必须按如下方式处理该标记。
插入字符.
解析错误。忽略该标记。
插入 HTML 元素 用于该标记。
如果 当前节点 是根 html
元素,则这是一个 解析错误;忽略该标记。 (片段情况)
如果解析器不是作为 HTML 片段解析算法 的一部分创建的 (片段情况),并且 当前节点 不再是 frameset
元素,则将 插入模式 切换为 "框架集之后"。
插入 HTML 元素 用于该标记。立即从 打开元素栈 中弹出 当前节点。
确认该标记的 自闭合标志,如果已设置。
停止解析.
解析错误。忽略标记。
当用户代理要应用"帧集之后"插入模式的规则时,用户代理必须按如下方式处理标记。
插入字符.
解析错误。忽略标记。
停止解析.
解析错误。忽略标记。
当用户代理要应用"主体之后之后"插入模式的规则时,用户代理必须按如下方式处理标记。
停止解析.
当用户代理要应用"帧集之后之后"插入模式的规则时,用户代理必须按如下方式处理标记。
停止解析.
解析错误。忽略标记。
当用户代理要应用解析外国内容中标记的规则时,用户代理必须按如下方式处理标记。
将帧集-确定标志设置为“不确定”。
解析错误。忽略标记。
解析错误.
当当前节点不是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”结束标记的步骤进行操作。
从打开元素堆栈中弹出当前节点,并确认标记的自闭合标志。
script
元素让旧插入点的值与当前插入点的值相同。让插入点位于下一个输入字符之前。
如果活动推测性 HTML 解析器为空,并且用户代理支持 SVG,则根据 SVG 规则处理 SVG script
元素。[SVG]
即使这导致将新字符插入标记器,解析器也不会重新递归执行,因为解析器暂停标志为真。
运行以下步骤
将节点初始化为当前节点(堆栈的最底层节点)。
如果节点的标记名称转换为 ASCII 小写与标记的标记名称不相同,则这是一个解析错误。
如果 node 的标签名 转换为 ASCII 小写 后与该标记的标签名相同,则从 打开元素栈 中弹出元素,直到 node 被弹出栈,然后返回。
将 node 设置为 打开元素栈 中的上一项。
如果 node 不是 HTML 命名空间 中的元素,则返回到标记为 loop 的步骤。
否则,根据与当前 插入模式 相对应的 HTML 内容部分中给出的规则处理该标记。
Document/DOMContentLoaded_event
所有当前引擎都支持。
一旦用户代理 停止解析 文档,用户代理必须执行以下步骤
所有当前引擎都支持。
如果 活动推测 HTML 解析器 不为空,则 停止推测 HTML 解析器 并返回。
将 插入点 设置为 undefined。
更新当前文档就绪状态 为 "interactive
"。
从 打开元素栈 中弹出 所有 节点。
当 文档解析完成后将执行的脚本列表 不为空时
循环事件循环,直到 文档解析完成后将执行的脚本列表 中的第一个 script
的 准备解析执行 设置为 true 并且 解析器的 Document
没有阻止脚本的样式表。
执行脚本元素,该元素由 文档解析完成后将执行的脚本列表 中的第一个 script
给出。
从 文档解析完成后将执行的脚本列表 中移除第一个 script
元素(即,从列表中移出第一个条目)。
在 DOM 操作任务源 上排队一个全局任务,该任务由 Document
的 相关全局对象 给出,以运行以下子步骤
将 Document
的 加载时间信息 的 DOM 内容加载事件开始时间 设置为由 Document
的 相关全局对象 给出的 当前高分辨率时间。
触发一个事件,名为 DOMContentLoaded
,在 Document
对象上,其 bubbles
属性初始化为 true。
将 Document
的 加载时间信息 的 DOM 内容加载事件结束时间 设置为由 Document
的 相关全局对象 给出的 当前高分辨率时间。
启用 客户端消息队列,该队列属于 ServiceWorkerContainer
对象,该对象的关联 服务工作者客户端 是 Document
对象的 相关设置对象。
调用 WebDriver BiDi DOM 内容已加载,并使用 Document
的 浏览上下文 和一个新的 WebDriver BiDi 导航状态,该状态的 id 是 Document
对象的 用于 WebDriver BiDi 的加载期间导航 ID,status 是 "pending
",并且 url 是 Document
对象的 URL。
循环事件循环,直到 尽快执行的脚本集 和 尽快按顺序执行的脚本列表 为空。
在 DOM 操作任务源 上排队一个全局任务,该任务由 Document
的 相关全局对象 给出,以运行以下步骤
更新当前文档就绪状态 为 "complete
"。
调用 WebDriver BiDi 加载完成,并使用 Document
的 浏览上下文 和一个新的 WebDriver BiDi 导航状态,该状态的 id 是 Document
对象的 用于 WebDriver BiDi 的加载期间导航 ID,status 是 "complete
",并且 url 是 Document
对象的 URL。
将 Document
对象的 用于 WebDriver BiDi 的加载期间导航 ID 设置为 null。
完全完成 文档
的加载。
现在 文档
已准备好执行加载后任务。
当用户代理需要 中止解析器 时,它必须执行以下步骤。
丢弃 输入流 中所有挂起的內容,并丢弃将要添加到其中的任何未来内容。
停止 此 HTML 解析器的 推测性 HTML 解析器。
更新当前文档就绪状态 为 "interactive
"。
从 打开元素堆栈 中弹出所有节点。
更新当前文档就绪状态 为 "complete
"。
用户代理可以实现本节中描述的优化,以推测性地获取在 HTML 标记中声明的资源,而 HTML 解析器则等待 挂起的解析阻塞脚本 被获取并执行,或者在正常解析期间,在 为令牌创建元素 的时候。虽然此优化没有明确定义,但有一些规则需要考虑以确保互操作性。
每个 HTML 解析器 可以有一个 活动推测性 HTML 解析器。它最初为 null。
推测性 HTML 解析器 必须像普通 HTML 解析器一样工作(例如,树构建器规则适用),但有一些例外情况。
普通 HTML 解析器和文档本身的状态不得受到影响。
例如,普通 HTML 解析器的 下一个输入字符 或 打开元素堆栈 不受 推测性 HTML 解析器 的影响。
推送到 HTML 解析器的 输入字节流 中的字节也必须推送到推测性 HTML 解析器的 输入字节流 中。从流中读取的字节必须是独立的。
推测性解析的结果主要是 推测性获取。推测性获取哪些类型的资源是 实现定义的,但用户代理不得推测性地获取那些使用普通 HTML 解析器不会获取的资源,假设阻塞 HTML 解析器的脚本什么都不做。
有可能从 推测性 HTML 解析器 和普通 HTML 解析器多次看到相同的标记。预计重复的获取将通过缓存规则来防止,这些规则尚未完全指定。
对 推测性模拟元素 element 的 推测性获取 必须遵循以下规则。
这些内容是否应该应用于文档“真正”,即使它们是推测性地找到的?
如果 推测性 HTML 解析器 遇到以下元素之一,则表现得好像该元素已处理,以供其对后续推测性获取的影响。
base
元素。meta
元素,其 http-equiv
属性处于 内容安全策略 状态。meta
元素,其 name
属性与 "referrer
" ASCII 不区分大小写 匹配。meta
元素,其 name
属性与 "viewport
" ASCII 不区分大小写 匹配。(这会影响媒体查询列表是否 匹配环境。) [CSSDEVICEADAPT]设 url 为如果 element 被正常处理,它将获取的 URL。如果没有这样的 URL 或如果它为空字符串,则什么也不做。否则,如果 url 已经在 推测性获取 URL 列表 中,则什么也不做。否则,就像元素被正常处理一样获取 url,并将 url 添加到 推测性获取 URL 列表 中。
每个 文档
都有一个 推测性获取 URL 列表,它是一个 列表,其中包含 URL,最初为空。
要为 HTML 解析器实例 parser 启动推测性 HTML 解析器
可选地,返回。
此步骤允许用户代理选择不进行推测性 HTML 解析。
如果 parser 的 活动推测性 HTML 解析器 不为 null,则为 parser 停止推测性 HTML 解析器。
这可能发生在 document.write()
写入另一个解析阻塞脚本时。为简单起见,此规范始终重新启动推测性解析,但用户代理可以实现更有效的策略,只要最终结果等效即可。
设 speculativeParser 为一个新的 推测性 HTML 解析器,其状态与 parser 相同。
设 speculativeDoc 为 parser 的 文档
的一个新的同构表示,其中所有元素都替换为 推测性模拟元素。设 speculativeParser 解析到 speculativeDoc 中。
将 parser 的 活动推测性 HTML 解析器 设置为 speculativeParser。
要为 HTML 解析器实例 parser 停止推测性 HTML 解析器
设 speculativeParser 为 parser 的 活动推测性 HTML 解析器。
如果 speculativeParser 为 null,则返回。
丢弃 speculativeParser 的 输入流 中所有挂起的內容,并丢弃将要添加到其中的任何未来内容。
将 parser 的 活动推测性 HTML 解析器 设置为 null。
推测性 HTML 解析器 将创建 推测性模拟元素,而不是普通元素。树构建器通常对元素执行的 DOM 操作预计将在推测性模拟元素上正常工作。
要给定 namespace、tagName 和 attributes 创建推测性模拟元素
设 element 为一个新的 推测性模拟元素。
将 element 的 命名空间 设置为 namespace。
将 element 的 本地名称 设置为 tagName。
将 element 的 属性列表 设置为 attributes。
可选地,为 element 执行 推测性获取。
返回 元素。
当树构建器说要将元素插入到 template
元素的 模板内容 中时,如果这是一个 推测性模拟元素,并且 template
元素的 模板内容 不是一个 ShadowRoot
节点,则什么也不做。在非声明式阴影根 template
元素中推测性地找到的 URL 本身可能也是模板,并且不得推测性地获取。
当应用程序将 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。
如果该工具无法以任何方式传达带外信息,则该工具可能会删除以下信息
form
元素祖先(在解析器中使用 form
元素指针)template
元素的 模板内容。本节中允许的变动在 HTML 解析器 的规则应用之后才应用。例如,<a::>
开始标签将由 </a::>
结束标签关闭,而不是由 </aU00003AU00003A>
结束标签关闭,即使用户代理使用上述规则为该开始标签在 DOM 中生成一个实际的元素,其名称为 aU00003AU00003A
。
本节是非规范性的。
本节检查了一些错误标记,并讨论了 HTML 解析器 如何处理这些情况。
本节是非规范性的。
最常讨论的错误标记示例如下
< p > 1< b > 2< i > 3</ b > 4</ i > 5</ p >
对该标记的解析直到 "3" 都是直观的。此时,DOM 看起来像这样
这里,打开元素栈 上有五个元素:html
、body
、p
、b
和 i
。 活动格式化元素列表 只有两个:b
和 i
。 插入模式 是 "正文内"。
接收到标签名称为 "b" 的结束标签标记后,将调用 "收养机构算法"。这是一个简单的情况,因为 格式化元素 是 b
元素,并且没有 最远块。因此,打开元素栈 最终只有三个元素:html
、body
和 p
,而 活动格式化元素列表 只有一个:i
。此时,DOM 树没有修改。
下一个标记是字符 ("4"),它会触发 活动格式化元素的重建,在本例中只有 i
元素。因此,为 "4" Text
节点创建了一个新的 i
元素。在接收 "i" 的结束标签标记以及插入 "5" Text
节点之后,DOM 看起来如下
本节是非规范性的。
与前一个示例类似的情况如下
< b > 1< p > 2</ b > 3</ p >
直到 "2",这里的解析都是直观的
有趣的部分是解析标签名称为 "b" 的结束标签标记时。
在看到该标记之前,打开元素栈 上有四个元素:html
、body
、b
和 p
。 活动格式化元素列表 只有一个:b
。 插入模式 是 "正文内"。
接收到标签名称为 "b" 的结束标签标记后,将调用 "收养机构算法",如前一个示例所示。但是,在本例中,存在 最远块,即 p
元素。因此,这次不会跳过收养机构算法。
共同祖先 是 body
元素。一个概念上的 "书签" 标记了 活动格式化元素列表 中 b
的位置,但由于该列表中只有一个元素,因此书签的影响不大。
随着算法的进展,节点 最终设置为格式化元素 (b
),而 最后一个节点 最终设置为 最远块 (p
)。
最后一个节点 被追加(移动)到 共同祖先,因此 DOM 看起来像这样
创建了一个新的 b
元素,并将 p
元素的子节点移动到该元素中
最后,新的 b
元素被附加到 p
元素,使得 DOM 看起来像
从 活动格式化元素列表 和 打开元素栈 中移除 b
元素,因此在解析 "3" 时,它被附加到 p
元素
本节是非规范性的。
出于历史原因,表格中的错误处理特别奇怪。例如,考虑以下标记
< table > < b > < tr >< td > aaa</ td ></ tr > bbb</ table > ccc
突出显示的 b
元素开始标签不允许直接放在这样的表格中,解析器通过将元素放在表格之前来处理这种情况。(这被称为寄养父母。)可以通过检查 DOM 树在 table
元素的开始标签被看到之后的情况来观察
…然后在 b
元素开始标签被看到之后
此时,打开元素栈 上面包含元素 html
、body
、table
和 b
(按此顺序,尽管结果 DOM 树是如此);活动格式化元素列表 只包含 b
元素;插入模式 是 "in table"。
tr
开始标签导致 b
元素从栈中弹出,并隐式地创建一个 tbody
开始标签;然后,tbody
和 tr
元素以相当直接的方式进行处理,使解析器通过 "in table body" 和 "in row" 插入模式,之后 DOM 看起来如下
这里,打开元素栈 上面包含元素 html
、body
、table
、tbody
和 tr
;活动格式化元素列表 仍然包含 b
元素;插入模式 是 "in row"。
td
元素开始标签令牌,在将 td
元素放在树上之后,在 活动格式化元素列表 上放置一个 标记(它还切换到 "in cell" 插入模式)。
该 标记 意味着当看到 "aaa" 字符令牌时,不会创建 b
元素来保存结果 Text
节点
结束标签以直接的方式进行处理;在处理它们之后,打开元素栈 上面包含元素 html
、body
、table
和 tbody
;活动格式化元素列表 仍然包含 b
元素(标记 已被 "td" 结束标签令牌移除);插入模式 是 "in table body"。
因此,发现 "bbb" 字符令牌。这些触发 "in table text" 插入模式(原始插入模式 设置为 "in table body"). 收集字符令牌,当看到下一个令牌(table
元素结束标签)时,将它们作为一个组进行处理。因为它们不是空格,所以它们根据 "in table" 插入模式中的 "其他任何内容" 规则进行处理,该规则委托给 "in body" 插入模式,但使用 寄养父母。
当 重建活动格式化元素 时,会创建一个 b
元素并进行 寄养父母,然后将 "bbb" Text
节点附加到它
打开元素栈 上面包含元素 html
、body
、table
、tbody
和 新的 b
(再次注意,这与结果树不匹配!);活动格式化元素列表 包含新的 b
元素;插入模式 仍然是 "in table body"。
如果字符令牌仅仅是 ASCII 空格 而不是 "bbb",那么这些 ASCII 空格 就会被附加到 tbody
元素。
最后,table
通过一个 "table" 结束标签关闭。这会将所有节点从 打开元素栈 中弹出,直到并包括 table
元素,但它不会影响 活动格式化元素列表,因此表格之后的 "ccc" 字符令牌会导致创建另一个 b
元素,这次是在表格之后
本节是非规范性的。
考虑以下标记,在这个例子中,我们假设它是具有 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”的警报。
本节是非规范性的。
详细说明上一节中的示例,考虑第二个script
元素是外部脚本(即具有src
属性的脚本)的情况。由于该元素在创建时不在解析器的Document
中,因此该外部脚本甚至不会被下载。
在script
元素(具有src
属性)正常解析到解析器的Document
中,但在下载外部脚本期间,该元素被移动到另一个文档,该脚本继续下载,但不执行。
一般来说,在Document
之间移动script
元素被认为是一种不好的做法。
本节是非规范性的。
以下标记显示了嵌套的格式化元素(如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 树如下所示
html
html
请注意,标记中的第二个p
元素没有显式的b
元素,但在生成的 DOM 中,在元素的“X”之前,最多会重建每种格式化元素的三种(在本例中,三种具有类属性的b
元素,以及两个未修饰的b
元素)。
还要注意,这意味着在最后一段中,只需要六个b
结束标签就可以完全清除活动格式化元素列表,即使到目前为止已经看到了九个b
开始标签。
为了以下算法的目的,如果元素类型是空元素之一,或为basefont
、bgsound
、frame
、keygen
或param
,则元素序列化为空。
以下步骤构成了HTML 片段序列化算法。该算法将 DOM Element
、Document
或DocumentFragment
(称为该节点)作为输入,以及布尔值serializableShadowRoots和一个sequence<ShadowRoot>
shadowRoots,并返回一个字符串。
该算法序列化正在序列化的节点的子节点,而不是节点本身。
如果该节点序列化为空,则返回空字符串。
令s为一个字符串,并将其初始化为空字符串。
如果该节点是template
元素,则令该节点改为template
元素的模板内容(一个DocumentFragment
节点)。
如果当前节点是影子宿主,则
令shadow为当前节点的影子根。
如果以下情况之一为真
serializableShadowRoots 为真,且 shadow 的 可序列化 为真;或
shadowRoots 包含 shadow,
则
追加“<template shadowrootmode="
”。
如果 shadow 的 模式 为“open
”,则追加“open
”。否则,追加“closed
”。
追加“"
”。
如果 shadow 的 委托焦点 设置,则追加“ shadowrootdelegatesfocus=""
”。
如果 shadow 的 可序列化 设置,则追加“ shadowrootserializable=""
”。
如果 shadow 的 可克隆 设置,则追加“ shadowrootclonable=""
”。
追加“>
”。
追加使用 shadow、serializableShadowRoots 和 shadowRoots 运行 HTML 片段序列化算法 的结果值(因此对该元素递归调用此算法)。
追加“</template>
”。
对于 该节点 的每个子节点,按树状顺序执行以下步骤
令 当前节点 为正在处理的子节点。
将以下列表中的适当字符串追加到 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:
”后跟属性的本地名称。
xmlns
属性的序列化名称是字符串“xmlns
”。
xmlns
属性的序列化名称是字符串“xmlns:
”后跟属性的本地名称。
属性的序列化名称是字符串“xlink:
”后跟属性的本地名称。
属性的序列化名称是属性的限定名称。
虽然属性的精确顺序是 实现定义的,并且可能取决于诸如属性在原始标记中给出的顺序之类的因素,但排序顺序必须是稳定的,这样连续调用此算法将以相同的顺序序列化元素的属性。
追加 U+003E 大于号字符 (>)。
如果 当前节点 序列化为空,则在此时 继续 到下一个子节点。
追加使用 当前节点、可序列化影子根 和 影子根 运行 HTML 片段序列化算法 的值(因此为该节点递归进入此算法),后跟 U+003C 小于号字符 (<)、U+002F 斜杠字符 (/)、标签名 再次出现,最后是 U+003E 大于号字符 (>)。
文本
节点如果 当前节点 的父节点是 style
、script
、xmp
、iframe
、noembed
、noframes
或 plaintext
元素,或者如果 当前节点 的父节点是 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 大于号)。
返回 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 >
出于历史原因,此算法不会对 pre
、textarea
或 listing
元素中的初始 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 >
转义字符串(在上述算法的范围内)包括执行以下步骤。
用字符串 "&
" 替换任何出现的 "&
" 字符。
用字符串 "
" 替换任何出现的 U+00A0 不间断空格字符。
如果算法是在 *属性模式* 中调用的,用字符串 ""
" 替换任何出现的 ""
" 字符。
如果算法 *未* 在 *属性模式* 中调用,用字符串 "<
" 替换任何出现的 "<
" 字符,用字符串 ">
" 替换任何出现的 ">
" 字符。
以下步骤构成 HTML 片段解析算法。该算法以 Element
节点作为输入,称为 context 元素,用于提供解析器的上下文,input,要解析的字符串,以及一个可选的布尔值 allowDeclarativeShadowRoots(默认值为 false)。它返回一个包含零个或多个节点的列表。
在解析器部分的算法中标记为 片段情况 的部分是仅在解析器为该算法的目的创建时才出现的部分。为了便于信息获取,算法用此类标记进行了注释;此类标记没有规范性权重。如果即使解析器不是为了处理该算法而创建的,也可能出现描述为 片段情况 的条件,那么这则是规范中的错误。
如果 context 元素的 节点文档 处于 怪癖模式,则让 Document
也处于 怪癖模式。否则,如果 context 元素的 节点文档 处于 有限怪癖模式,则让 Document
也处于 有限怪癖模式。否则,让 Document
处于 非怪癖模式。
如果 allowDeclarativeShadowRoots 为 true,则将 Document
的 允许声明式影子根 设置为 true。
根据 context 元素,如下设置 HTML 解析器 的 标记化 阶段的状态。
title
textarea
style
xmp
iframe
noembed
noframes
script
noscript
plaintext
为了提高性能,不报告错误并直接使用本规范中描述的实际状态机的实现,可以在上述列表中提到 RAWTEXT 和脚本数据状态的地方,使用 PLAINTEXT 状态代替它们。除了关于解析错误的规则外,它们是等效的,因为在片段情况中没有 合适的结束标签标记,但它们涉及更少的状态转换。
让 root 是一个新的 html
元素,没有属性。
将元素 root 附加到上面创建的 Document
节点。
设置解析器的 打开元素堆栈,使其仅包含单个元素 root。
如果 context 元素是 template
元素,则将 "在模板中" 推入 模板插入模式堆栈,使其成为新的 当前模板插入模式。
解析器将引用 context 元素作为该算法的一部分。
将解析器的 form
元素指针 设置为最接近 context 元素的 form
元素节点(沿着祖先链向上,如果该元素本身是 form
元素,则包括该元素),如果有的话。(如果没有这样的 form
元素,则 form
元素指针 保持其初始值,null。)
启动解析器,并让它运行,直到它消耗了刚刚插入输入流中的所有字符。
返回 root 的子节点,按 树序 排列。