HTML文檔解析和DOM樹的構建


瀏覽器解析HTML文檔生成DOM樹的過程,以下是一段HTML代碼,以此為例來分析解析HTML文檔的原理

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <script src="script.js"></script>  
    <link  rel="stylesheet" type="text/css" href="style.css">  
    <title></title>  
</head>  
<body>  
    <h1>HelloWorld</h1>  
    <div>  
        <div>  
            <p>picture:</p>  
            <img src="example.png"/>  
        </div>  
        <div>  
            <p>A paragraph of explanatory text...</p>  
        </div>  
    </div>  
</body>  
</html>

  

豌豆資源搜索網站 https://55wd.com

瀏覽器解析HTML文檔,在<head>中發現了<script>和<link>引入文件,於是向服務器請求文件,在請求和下載文件過程中將繼續向下解析HTML,當引入文件下載完成后會通知瀏覽器回頭來解析css和script文件。

如果瀏覽器在代碼中發現一個<img>標簽引用了一張圖片,向服務器發出請求。此時瀏覽器同樣不會等到圖片下載完,而是繼續渲染后面的代碼;

 

現在進入正題,講講自己對解析HTML文檔構建DOM樹的理解:

此過程可分為兩個主要模塊構成,即

  • 標簽解析
  • DOM樹構建

 

1. 標簽解析

這部分完成從HTML字符串中解析出標簽的功能。主要使用標記化算法。

標記化算法的輸入結果是HTML標記,使用狀態機表示。狀態機一共有4個狀態:數據狀態(Data)、標記打開狀態(Tag open)、標記名稱狀態(Tag name)、關閉標記打開狀態(Close tag open state)。

初始狀態是數據狀態。

當標記是處於數據狀態時,

       1)遇到字符<時,狀態更改為“標記打開狀態”:

              a. 接收一個a-z字符會創建“起始標記”,狀態更改為“標記名稱狀態”,並保持到接收>字符。此期間的字符串會形成一個新的標記名稱。接收到>標記后,將當前的新標記發送給樹構造器,狀態改回“數據狀態”

              b. 接收下一個輸入字符/時,會創建關閉標記打開狀態,並更改為“標記名稱狀態”。直到接收>字符,將當前的新標記發送給樹構造器,並改回“數據狀態”。

       2)遇到a-z字符時,會將每個字符創建成字符標記,並發送給樹構造器。

 

2. DOM樹構建

當標簽解析器解析出標簽后會發送到DOM樹構建器,我們可以認為DOM樹構建器主要有以下兩部分組成:

  • DOM樹
  • 一個存放標簽名的棧

用如下代碼演示生成DOM樹的過程:

<html>  
<body>  
    <h1>HelloWorld</h1>  
    <div>  
        <div>  
            <p>picture:</p>  
            <img src="example.png"/>  
        </div>  
        <div>  
            <p>A paragraph of explanatory text...</p>  
        </div>  
    </div>  
</body>  
</html>
<span><span class="tag"></span></span>

  

 

首先樹構建器接收到標簽解析器發來的起始標簽名后,會加入到棧中,圖1是解析到<h1>標簽的棧中壓入的內容,共有<html><body><h1>三個標簽,此時還未向DOM樹中添加任何結點(圖中黑色實線框代表開始標簽,紅色虛線框代表結束標簽,結束標簽不會入棧)。

繼續向下解析,接收到一個</h1>結束標簽,此時查詢棧頂元素,如果和傳入的結束標簽屬於同種類型的p標簽(如圖2),則將棧頂元素彈出,向DOM樹中加入此節點,然后繼續向下解析(如圖3)。

如果遇到的是沒有封閉標簽的元素如<img/>,則直接加入DOM樹中即可,無需入棧。

依次向下解析,當棧為空,即<html>根節點也加入到DOM樹中,DOM樹構建完畢。

 

這里需要指出的是,當某個元素缺失結束標簽時,假如上述代碼中第一個<div>標簽缺失了</div>結束標簽,即:

<html>  
<body>  
    <h1>HelloWorld</h1>  
    <div>  
        <div>  
            <p>picture:</p>  
            <img src="example.png"/>  
        </div>  
        <div>  
            <p>A paragraph of explanatory text...</p>  
        </div>  
  
</body>  
</html>

 

 

那么,此時的棧如圖4所示。即此時傳來的結束標簽是</body>,而棧頂元素是<div>,兩者不是同一種標簽,說明div缺少了結束標簽,這種情況也將棧頂<div>元素彈出,加入到DOM樹中。相當於給<div>補了一個</div>結束標簽。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM