在开始介绍概念之前,让我们详细了解一下术语。解析这个词的意思是将某物分成其组成部分,然后描述它们的句法作用。文字处理是一个熟悉的词,代表使用标准程序处理某事。结合这两个解释 HTML 解析器如何从 text/html 资源生成 DOM 树。
这种方法定义了 HTML 文档的解析规则,以确定它们在语法上是否正确。语法不匹配的点,会引发解析错误。在程序结束时,如果资源被确定为 HTML 语法,那么它就是一个 HTML 文档。
解析模型概述
HTML 解析过程的输入由代码点流组成,然后通过标记化阶段和树构建阶段,以生成 Document 对象作为输出。大多数情况下,标记化阶段处理的数据来自网络,但也可以来自在用户代理中运行的脚本,例如使用 document.write() API。分词器和树构建阶段只有一组状态,但是当树构建阶段处理一个标记时,分词器可以恢复。因为这个树构建阶段通常被认为是可重入的。为了处理这种情况,解析器有一个脚本嵌套级别,它必须最初设置为 0 和一个解析器暂停标志,必须初始化为 false。
解析错误:如前所述,在解析资源时,会检查其语法,如果某些内容与标准协议不匹配,则会引发解析错误。如果发现资源没有错误,它就成为一个文档。解析错误仅处理有关 HTML 文档语法的错误。除了检查解析错误之外,一致性检查器还验证文档以匹配基本的一致性要求。解析错误的错误处理是明确定义的。如果在文档中发现一个或多个解析条件,则一致性检查员有责任报告其中至少一个,如果没有出现错误则不报告任何一个。如果文档中遇到多个解析错误条件,一致性检查器可能会报告多个解析错误条件。
了解每一层
- 输入字节流:
将作为标记化阶段输入的代码点流最初将被用户代理视为通常来自网络或本地文件系统的字节流。字节根据特定字符编码对实际字符编码,用户代理使用该编码将字节解码为字符。给定字符编码,必须将输入字节流中的字节转换为字符,以便将它们与标记器一起用作其输入流,绕过输入字节流和字符编码进行解码。
当 HTML 解析器对输入字节流进行解码时,它使用字符编码和暂时的、确定的或不相关的置信度。所使用的编码以及对该编码的置信度类型在解析过程中被用来确定是否更改编码。如果不需要编码,例如因为解析器在 Unicode 流上运行并且根本不必使用字符编码,那么置信度就无关紧要。
- 输入流预处理器:输入流由在解码输入字节流时推入其中的字符或来自直接操作输入流的各种 API 组成。在标记化阶段之前,换行符在输入流中被规范化。最初,一个输入字符是在输入是尚待消耗和当前输入字符是已经消耗的最后一个字符的第一个字符。插入点是使用 () 插入的内容实际插入的位置。插入点不是输入流中的绝对偏移量,而是相对于紧跟其后的字符的位置。最初,插入点是未定义的。
- 标记化:预期实现的行为就像它们使用以下状态机来标记 HTML 一样。状态机预计以数据状态启动。大多数状态采用单个字符,它要么将状态机切换到新状态以重新使用当前输入字符,要么将其切换到新状态以使用下一个字符。某些状态具有更复杂的行为,并且可以在切换到另一个状态之前接收多个字符。在某些情况下,分词器状态也受树构建阶段的影响。
此步骤中生成的输出是一系列零个或多个以下标记:DOCTYPE、开始标记、结束标记、注释、字符、文件结尾。同样创建和发出令牌是两个完全不同的概念。当发出令牌时,必须立即由树构建阶段参与。树构建阶段会影响标记化阶段的状态,甚至允许在流中插入额外的字符。
- 树构建:来自标记化状态的标记序列形成树构建阶段的输入。创建解析器后,树构建阶段与文档对象模型 (DOM) 相关联。此阶段的输出包括动态修改或扩展该文档的 DOM 树。当每个令牌从令牌生成器分派时,用户代理应该遵循特定的算法来处理它们。