16.1 文本模式及其对解析器的影响
文本模式是解析器工作时的特殊状态;同一种字符在不同模式下解析结果完全不同,这是后续所有分支判断的前提。
一、什么是文本模式
- 文本模式(text mode)指的是解析器在工作时所进入的一些特殊状态,在不同状态下,解析器对文本的解析行为会有所不同;
- 解析器的初始模式是 DATA 模式;
- 模式本质上只决定两件事:字符
<是否开启一个标签、字符&是否作为 HTML 实体被解码。
二、五种模式对照
| 模式 | 进入时机 | 遇 < 的行为 | 是否解码 HTML 实体 |
|---|---|---|---|
| DATA | 初始模式 | 切换到标签开始状态(tag open state),可解析标签 | 是(遇 & 切换到字符引用状态) |
| RCDATA | 解析 <title>、<textarea> 时 | 进入 RCDATA less-than sign state,只识别自己的结束标签 | 是 |
| RAWTEXT | 解析 <style>、<xmp>、<iframe>、<noembed>、<noframes>、<noscript> 时 | 同 RCDATA,不识别标签 | 否(实体按普通字符处理) |
| CDATA | 遇到字符串 <![CDATA[ 时 | 任何字符都当普通字符,直到 ]]> | 否 |
| PLAINTEXT | 进入后永不退出 | 全部当普通字符 | 否(Vue 模板解析器用不到) |
三、各模式的关键结论
DATA 模式
- 遇
<→ 切换到标签开始状态(tag open state),因此该模式下能解析标签元素; - 遇
&→ 切换到字符引用状态(character reference state),也称 HTML 字符实体状态,因此该模式下能处理 HTML 实体。
RCDATA 模式
- 遇
<时不再进入 tag open state,而是进入 RCDATA less-than sign state;在该状态下若遇到字符/,则直接进入 RCDATA end tag open state(自己的结束标签); - 因此 RCDATA 模式下解析器不能识别标签元素:
<textarea>内的<只是普通文本; - 但仍支持 HTML 实体,因为遇
&依旧会切换到字符引用状态。
RAWTEXT 模式
- 工作方式与 RCDATA 类似,唯一区别是不再支持 HTML 实体,实体字符被当作普通字符;
- Vue.js 的模板 DSL 不允许出现
<script>,但模板解析器遇到<script>时同样会切换到 RAWTEXT;单文件组件的解析器也一样,会把<script>标签内的内容全部作为普通文本处理。
CDATA 模式
- 在 RAWTEXT 的基础上更进一步:把任何字符都作为普通字符处理,直到遇到 CDATA 的结束标志为止。
PLAINTEXT 模式
- 与 RAWTEXT 类似,但解析器一旦进入就不会再退出。
四、模式表
const TextModes = {
DATA: 'DATA', // 普通文本模式
RCDATA: 'RCDATA', // 受限的 CDATA 模式
RAWTEXT: 'RAWTEXT', // 原始文本模式
CDATA: 'CDATA' // CDATA 模式
}
易错点:模式决定了「
<是否开启标签、&是否解码实体」,所以<textarea>里可以随便写<,而<style>里写<不会被解码。
相关
- 16.2 递归下降算法构造模板 AST:
parseChildren如何在不同模式下选择解析函数 - 16.4 解析标签节点:解析标签后如何切换文本模式