webkit源码阅读:dom树的构建

 

今天关注webkit中dom树是怎么构建的,HTML是怎么分析的。

1、dom相关的代码在webcore中dom目录下,有很多类,比较重要的是

Document.h、DocumentFragment.h、DocumentParser.h

DocumentParser是一个基类感觉好像没干什么事,只是传入了一个开始parse的状态,在DocumentFragment中有parseHTML,好像开始了真正的parse操作;

 

2、HTML的parse操作,从DocumentFragment中的parseHTML开始,相关的parser放置在WebCore/html/parser下,具体是由HTMLDocumentParser来完成的。

 

DocumentFragment::parseHTML()

         -->HTMLDocumentParser::parseDocumentFragment()

             -->HTMLDocuemntParser::insert()

                      {

                         设置好输入流

                         调用pumpTokenlizerIfPossible准备建树

                      -->HTMLDocumentParser::pumpTokenlizerIfPossible()                       

                            -->HTMLDocumentParser::pumpTokenlizer()

                                 {

                                          while() {

                                                       HTMLTokenizer::nextToken(stream, HTMLToken::m_token)

                                                       HTMLTreeBuilder::constructTreeFromToken(m_token)

                                                               {

                                                                         将HTMLToken转成AtomicHTMLToken;

                                                                        再调用建树函数constructTreeFromAtomicToken(m_token);

                                                                        -->HTMLTreeBuilder::constructTreeFromAtomicToken()

                                                                            {

                                                                                   根据token的类型分别调用:

                                                                                    HTMLTreeBuilder::ASSERT_NOT_REACHED()

                                                                                    HTMLTreeBuilder::processDoctypeToken()

                                                                                    HTMLTreeBuilder::processStartTag()

\                                                                                    HTMLTreeBuilder::processEndTag()

                                                                                    HTMLTreeBuilder::processComment()

                                                                                    HTMLTreeBuilder::processCharacter()

                                                                                    HTMLTreeBuilder::processEndOfFile()

                                                                                   完成树的构建

                                                                              }

                                                                 }

                                                    }

                                     }

                     }

整个Dom树的构建过程非常清晰,其中一些比较重要的类,包括:HTMLDocumentParser完成parse的整体流程,协调HTMLInputStream、HTMLTokenlizer、HTMLTreeBuilder的工作,其中:

1)HTMLInputStream负责HTML数据的输入;

2)HTMLTokenlizer根据输入的数据流把HTML进行tokenlize;

3)HTMLTreeBuilder根据输入的token进行建树、完成树的构建;

 

HTMLTokenlizer的实现就是一个大的状态机,根据input的数据,不断变换着内部的状态,完成tokenlization的过程,吐出一个个的token。

 

 树的构建过程是通过HTMLTreeBuilder和HTMLContructionSite等类来完成的,Dom树的构建过程是比较复杂的,但原理是比较清晰的,根据HTML文件的嵌套顺序,通过一个栈(HTMLElementStack m_openElements)来保存当前打开的节点标签。假设一段HTML的数据如下:

<div>

 <p>

<a>

</a>

 </p>

<br>

</br>

</div>

我们知道div节点有两个子节点,p和br,而p节点又有一个子节点a,具体处理过程简单描述如下:

假设当前栈为空;

首先处理<div>,遇到<div>时,调用processStartTag(),m_openElements中首先压入div;

继续处理,遇到<p>标签,调用processStartTag(),此时栈顶的div就是p节点的父节点,建立好p和div的连接,在加入节点p;

继续处理,遇到<a>标签,调用processStartTag(),此时栈定节点是p,当前节点是a,那么a的父节点是p,建立好父子关系,并将a压入栈;

继续处理,遇到</a>标签,调用processEndTag(),弹出栈定元素a(代码中使用“弹出直到标签a”一提高容错性,因为有可能会有没封闭的节点,导致栈混乱,使用弹出知道标签xxx,可以将没有封闭的标签带来的问题,限制在局部范围内,防止扩散);

继续处理,遇到</p>标签,调用processEndTag(),弹出p

继续处理,遇到<br>标签,调用processStartTag(),此时栈顶的div就是br节点的父节点,建立好br和div的连接,在加入节点br;

继续处理,遇到</br>标签,调用processEndTag(),弹出br

继续处理,遇到</div>标签,调用processEndTag(),弹出div

DOM树建立完毕。

原理虽然如此,但因为浏览器为了用户的方便,允许网页中有各种的错误,浏览器必须能够尽可能的显示出用户的数据,这就给DOM树的构建增加了很多复杂的处理,具体来说,DOM的数构建是由一个状态机来控制和容错的,比如在processStartTag函数中,根据当前构建过程的状态和获得的HTML token来决定下一步的动作,构建过程的状态包括:InitialMode, BeforeHTMLMode, BeforeHeadMode, InHeadMode, AfterHeadMode, InBodyMode, InTableMode, InCapationMode, InColumnGroupMode,...等等,如何根据这些状态和输入的token执行动作,在参考文献[1]中有全面的描述。经过这样的过程Dom树应就算建立完成了。

参考文献:

[1]http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#parsing-main-inbody

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值