浏览器都具有错误处理的能力,但是,另人惊讶的是,这并不是html最新规范的内容,就像书签及前进后退按钮一样,它只是浏览器长期发展的结果。一些比较知名的非法html结构,在许多站点中出现过,浏览器都试着以一种和其他浏览器一致的方式去修复。
Html5规范定义了这方面的需求,webkit在html解析类开始部分的注释中做了很好的总结。
解析器将符号化的输入解析为文档并创建文档,但不幸的是,我们必须处理很多没有很好格式化的html文档,至少要小心下面几种错误情况。
1. 在未闭合的标签中添加明确禁止的元素。这种情况下,应该先将前一标签闭合
2. 不能直接添加元素。有些人在写文档的时候会忘了中间一些标签(或者中间标签是可选的),比如HTML HEAD BODY TR TD LI等
3. 想在一个行内元素中添加块状元素。关闭所有的行内元素,直到下一个更高的块状元素
4. 如果这些都不行,就闭合当前标签直到可以添加该元素。
下面来看一些webkit容错的例子:
</br>替代<br>
一些网站使用</br>替代<br>,为了兼容IE和Firefox,webkit将其看作<br>。
代码:
if (t->isCloseTag(brTag) && m_document->inCompatMode()) {
reportError(MalformedBRError);
t->beginTag = true;
}
Note -这里的错误处理在内部进行,用户看不到。
迷路的表格
这指一个表格嵌套在另一个表格中,但不在它的某个单元格内。
比如下面这个例子:
<table>
<table>
<tr><td>inner table</td></tr>
</table>
<tr><td>outer table</td></tr>
</table>
webkit将会将嵌套的表格变为两个兄弟表格:
<table>
<tr><td>outer table</td></tr>
</table>
<table>
<tr><td>inner table</td></tr>
</table>
代码:
if (m_inStrayTableContent && localName == tableTag)
popBlock(tableTag);
webkit使用堆栈存放当前的元素内容,它将从外部表格的堆栈中弹出内部的表格,则它们变为了兄弟表格。
嵌套的表单元素
用户将一个表单嵌套到另一个表单中,则第二个表单将被忽略。
代码:
if (!m_currentFormElement) {
m_currentFormElement = new HTMLFormElement(formTag,m_document);
}
太深的标签继承
是一个由嵌套层次的站点的例子,最多只允许20个相同类型的标签嵌套,多出来的将被忽略。
代码:
bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName)
{
unsigned i = 0;
for (HTMLStackElem* curr = m_blockStack;
i < cMaxRedundantTagDepth && curr && curr->tagName == tagName;
curr = curr->next, i++) { }
return i != cMaxRedundantTagDepth;
}
放错了地方的html、body闭合标签
又一次不言自明。
支持不完整的html。我们从来不闭合body,因为一些愚蠢的网页总是在还未真正结束时就闭合它。我们依赖调用end方法去执行关闭的处理。
代码:
if (t->tagName == htmlTag || t->tagName == bodyTag )
return;
所以,web开发者要小心了,除非你想成为webkit容错代码的范例,否则还是写格式良好的html吧。
CSS解析(CSS parsing)还记得简介中提到的解析的概念吗,不同于html,css属于上下文无关文法,可以用前面所描述的解析器来解析。Css规范定义了css的词法及语法文法。
看一些例子:
每个符号都由正则表达式定义了词法文法(词汇表):
comment///*[^*]*/*+([^/*][^*]*/*+)*//
num[0-9]+|[0-9]*"."[0-9]+
nonascii[/200-/377]
nmstart[_a-z]|{nonascii}|{escape}
nmchar[_a-z0-9-]|{nonascii}|{escape}
name{nmchar}+
ident{nmstart}{nmchar}*
“ident”是识别器的缩写,相当于一个class名,“name”是一个元素id(用“#”引用)。
语法用BNF进行描述:
ruleset
: selector [ ',' S* selector ]*
'{' S* declaration [ ';' S* declaration ]* '}' S*
;
selector
: simple_selector [ combinator selector | S+ [ combinator selector ] ]
;
simple_selector
: element_name [ HASH | class | attrib | pseudo ]*
| [ HASH | class | attrib | pseudo ]+
;
class
: '.' IDENT
;
element_name
: IDENT | '*'
;
attrib
: '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
[ IDENT | STRING ] S* ] ']'
;
pseudo
: ':' [ IDENT | FUNCTION S* [IDENT S*] ')' ]
;
说明:一个规则集合有这样的结构
div.error , a.error {
color:red;
font-weight:bold;
}
div.error和a.error时选择器,大括号中的内容包含了这条规则集合中的规则,这个结构在下面的定义中正式的定义了:
ruleset
: selector [ ',' S* selector ]*
'{' S* declaration [ ';' S* declaration ]* '}' S*
;