当你看到这篇文章意味着我辜负了@教主的殷切指望周末木有去约会,以及苏老师@我思故我在北京鼓楼的乘人之危成功了……html
本文demo powered by 已经结婚的@老赵的再也不维护的wind.jsgit
物是人非啊……github
说回正经事,在上一篇文章中,咱们取得了初步成果,毫无心义的字符变成了有意义的token。数组
接下来咱们要把这些简单的词变成DOM树,这个过程咱们是使用栈来实现的,任何语言几乎都有栈,为了给你们跑着玩咱们仍是用JS来实现吧,JS中的栈只要用数组就行了:浏览器
function HTMLSyntaticalParser(){ var stack = [new HTMLDocument]; this.receiveInput = function(token) { //TODO } this.getOutput = function(){ return stack[0]; } }
为了构建DOM树,咱们须要一个Node类,接下来咱们全部的节点都会是这个Node类的实例。在彻底符合标准的浏览器中,不同的HTML节点对应了不一样的Node的子类,咱们为了简化,就不完整实现这个继承体系了。咱们仅仅把Node分为Element和Text(若是是基于类的OOP的话,咱们须要抽象工厂来建立对象。)this
function Element(){ this.childNodes = [];
}
function Text(value){
this.value = value || "";
}
前面咱们的token中,如下两个是须要成对匹配的:翻译
因而咱们的作法是遇到tag start就入栈,遇到tag end就出栈,而且校验一下是否匹配。code
对于Text节点,咱们则须要把相邻的Text节点合并起来,咱们的作法是当字符token入栈时检查栈顶是不是Text节点,若是是的话就合并Text节点htm
一样咱们来看看直观的解析过程:对象
当咱们的源代码彻底遵循xhtml时,这很是简单问题,然而HTML具备很强的容错能力,奥妙在于当tag end跟栈顶的start tag不匹配的时候如何处理。
因而有一个极其复杂的规则来的,幸亏w3c又一次很贴心地把所有规则都整理的很好,咱们只要翻译成对应的伪代码就行了:
http://www.w3.org/html/wg/drafts/html/master/syntax.html#tree-construction
略微干净的代码能够在这个gist找到:
https://gist.github.com/wintercn/5618683#file-htmlsyntaticalparser-js