在瀏覽器的背後(二) —— HTML語言的語法解析

當你看到這篇文章意味着我辜負了@教主的殷切指望週末木有去約會,以及蘇老師@我思故我在北京鼓樓乘人之危成功了……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

因而咱們的作法是遇到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

相關文章
相關標籤/搜索