精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

手寫簡易瀏覽器之Html Parser 篇

系統 瀏覽器
這篇是簡易瀏覽器中 html parser 的實現,少了自閉合標簽的處理,就是差一個 if else,后面會補上。

 [[403967]]

本文轉載自微信公眾號「神光的編程秘籍」,作者神說要有光zxg。轉載本文請聯系神光的編程秘籍公眾號。

思路分析

實現 html parser 主要分為詞法分析和語法分析兩步。

詞法分析

詞法分析需要把每一種類型的 token 識別出來,具體的類型有:

  • 開始標簽,如 <div>
  • 結束標簽,如 </div>
  • 注釋標簽,如 <!--comment-->
  • doctype 標簽,如 <!doctype html>
  • text,如 aaa

這是最外層的 token,開始標簽內部還要分出屬性,如 id="aaa" 這種。

也就是有這幾種情況:

第一層判斷是否包含 <,如果不包含則是 text,如果包含則再判斷是哪一種,如果是開始標簽,還要對其內容再取屬性,直到遇到 > 就重新判斷。

語法分析

語法分析就是對上面分出的 token 進行組裝,生成 ast。

html 的 ast 的組裝主要是考慮父子關系,記錄當前的 parent,然后 text、children 都設置到當前 parent 上。

我們來用代碼實現一下:

代碼實現

詞法分析

首先,我們要把 startTag、endTag、comment、docType 還有 attribute 的正則表達式寫出來:

正則

結束標簽就是

  1. const endTagReg = /^<\/([a-zA-Z0-9\-]+)>/; 

注釋標簽是 中間夾著非 --> 字符出現任意次

  1. const commentReg = /^<!\-\-[^(-->)]*\-\->/; 

doctype 標簽是 字符出現多次,加 >

  1. const docTypeReg = /^<!doctype [^>]+>/; 

attribute 是多個空格開始,加 a-zA-Z0-9 或 - 出現多次,接一個 =,之后是非 > 字符出多次

  1. const attributeReg = /^(?:[ ]+([a-zA-Z0-9\-]+=[^>]+))/; 

開始標簽是 < 開頭,接 a-zA-Z0-9 和 - 出現多次,然后是屬性的正則,最后是 > 結尾

  1. const startTagReg = /^<([a-zA-Z0-9\-]+)(?:([ ]+[a-zA-Z0-9\-]+=[^> ]+))*>/; 

分詞

之后,我們就可以基于這些正則來分詞,第一層處理 < 和 text:

  1. function parse(html, options) { 
  2.     function advance(num) { 
  3.         html = html.slice(num); 
  4.     } 
  5.  
  6.     while(html){ 
  7.         if(html.startsWith('<')) { 
  8.             //... 
  9.         } else { 
  10.             let textEndIndex = html.indexOf('<'); 
  11.             options.onText({ 
  12.                 type: 'text'
  13.                 value: html.slice(0, textEndIndex) 
  14.             }); 
  15.             textEndIndex = textEndIndex === -1 ? html.length: textEndIndex; 
  16.             advance(textEndIndex); 
  17.         } 
  18.     } 

第二層處理 <!-- 和 <!doctype 和結束標簽、開始標簽:

  1. const commentMatch = html.match(commentReg); 
  2. if (commentMatch) { 
  3.     options.onComment({ 
  4.         type: 'comment'
  5.         value: commentMatch[0] 
  6.     }) 
  7.     advance(commentMatch[0].length); 
  8.     continue
  9.  
  10. const docTypeMatch = html.match(docTypeReg); 
  11. if (docTypeMatch) { 
  12.     options.onDoctype({ 
  13.         type: 'docType'
  14.         value: docTypeMatch[0] 
  15.     }); 
  16.     advance(docTypeMatch[0].length); 
  17.     continue
  18.  
  19. const endTagMatch = html.match(endTagReg); 
  20. if (endTagMatch) { 
  21.     options.onEndTag({ 
  22.         type: 'tagEnd'
  23.         value: endTagMatch[1] 
  24.     }); 
  25.     advance(endTagMatch[0].length); 
  26.     continue
  27.  
  28. const startTagMatch = html.match(startTagReg); 
  29. if(startTagMatch) {     
  30.     options.onStartTag({ 
  31.         type: 'tagStart'
  32.         value: startTagMatch[1] 
  33.     }); 
  34.  
  35.     advance(startTagMatch[1].length + 1); 
  36.     let attributeMath; 
  37.     while(attributeMath = html.match(attributeReg)) { 
  38.         options.onAttribute({ 
  39.             type: 'attribute'
  40.             value: attributeMath[1] 
  41.         }); 
  42.         advance(attributeMath[0].length); 
  43.     } 
  44.     advance(1); 
  45.     continue

經過詞法分析,我們能拿到所有的 token:

語法分析

token 拆分之后,我們需要再把這些 token 組裝在一起,只處理 startTag、endTag 和 text 節點。通過 currentParent 記錄當前 tag。

  • startTag 創建 AST,掛到 currentParent 的 children 上,然后 currentParent 變成新創建的 tag
  • endTag 的時候把 currentParent 設置為當前 tag 的 parent
  • text 也掛到 currentParent 上
  1. function htmlParser(str) { 
  2.     const ast = { 
  3.         children: [] 
  4.     }; 
  5.     let curParent = ast; 
  6.     let prevParent = null
  7.     const domTree = parse(str,{ 
  8.         onComment(node) { 
  9.         }, 
  10.         onStartTag(token) { 
  11.             const tag = { 
  12.                 tagName: token.value, 
  13.                 attributes: [], 
  14.                 text: ''
  15.                 children: [] 
  16.             }; 
  17.             curParent.children.push(tag); 
  18.             prevParent = curParent; 
  19.             curParent = tag; 
  20.         }, 
  21.         onAttribute(token) { 
  22.             const [ name, value ] = token.value.split('='); 
  23.             curParent.attributes.push({ 
  24.                 name
  25.                 value: value.replace(/^['"]/, '').replace(/['"]$/, ''
  26.             }); 
  27.         }, 
  28.         onEndTag(token) { 
  29.             curParent = prevParent; 
  30.         }, 
  31.         onDoctype(token) { 
  32.         }, 
  33.         onText(token) { 
  34.             curParent.text = token.value; 
  35.         } 
  36.     }); 
  37.     return ast.children[0]; 

我們試一下效果:

  1. const htmlParser = require('./htmlParser'); 
  2.  
  3. const domTree = htmlParser(` 
  4. <!doctype html> 
  5. <body> 
  6.     <div> 
  7.         <!--button--> 
  8.         <button>按鈕</button> 
  9.         <div id="container"
  10.             <div class="box1"
  11.                 <p>box1 box1 box1</p> 
  12.             </div> 
  13.             <div class="box2"
  14.                 <p>box2 box2 box2</p> 
  15.             </div> 
  16.         </div> 
  17.     </div> 
  18. </body> 
  19. `); 
  20.  
  21. console.log(JSON.stringify(domTree, null, 4)); 

成功生成了正確的 AST。

總結

這篇是簡易瀏覽器中 html parser 的實現,少了自閉合標簽的處理,就是差一個 if else,后面會補上。

我們分析了思路并進行了實現:通過正則來進行 token 的拆分,把拆出的 token 通過回調函數暴露出去,之后進行 AST 的組裝,需要記錄當前的 parent,來生成父子關系正確的 AST。

html parser 其實也是淘系前端的多年不變的面試題之一,而且 vue template compiler 還有 jsx 的 parser 也會用到類似的思路。還是有必要掌握的。希望本文能幫大家理清思路。

代碼在 github:https://github.com/QuarkGluonPlasma/tiny-browser

 

責任編輯:武曉燕 來源: 神光的編程秘籍
相關推薦

2021-06-04 05:16:33

瀏覽器js源碼

2018-07-31 11:20:26

2012-05-07 14:24:15

HTML 5Web App

2012-05-28 13:09:12

HTML5

2012-04-23 13:43:02

HTML5瀏覽器

2012-03-20 11:31:58

移動瀏覽器

2012-03-19 17:25:22

2012-03-20 11:41:18

海豚瀏覽器

2012-03-20 11:07:08

2013-11-20 10:47:57

瀏覽器渲染html

2009-07-29 08:50:10

Windows 7瀏覽器歐洲版

2010-04-05 21:57:14

Netscape瀏覽器

2012-06-21 15:38:02

獵豹瀏覽器

2012-03-19 17:17:00

移動瀏覽器歐朋

2012-03-20 11:22:02

QQ手機瀏覽器

2021-02-06 12:25:42

微軟Chromium瀏覽器

2022-01-24 13:46:24

框架

2012-03-20 11:35:32

傲游手機瀏覽器

2012-05-17 09:45:30

2013-08-16 17:50:13

點贊
收藏

51CTO技術棧公眾號

一区二区视频免费看| 日本美女高潮视频| 国产 欧美 自拍| 国产亚洲综合精品| 中文字幕亚洲一区二区三区| 五月天婷婷在线观看视频| 丁香花在线电影| 久久蜜桃一区二区| 亚洲a成v人在线观看| 国产免费av一区二区| 日韩一级毛片| 亚洲国产欧美一区二区三区久久| 国产自偷自偷免费一区 | 免费高清在线视频一区·| 日韩视频一区在线| 午夜视频在线观看国产| 日韩成人精品一区二区三区| 亚洲国产wwwccc36天堂| 亚洲精品成人自拍| 成人久久精品人妻一区二区三区| 日韩国产欧美在线播放| 欧美激情视频三区| 婷婷丁香综合网| 日韩伦理一区二区三区| 欧美一级黄色片| 国产精品一区二区羞羞答答| 免费高潮视频95在线观看网站| 日韩一区有码在线| 欧美一区二区三区精美影视| 韩国av免费在线| 极品销魂美女一区二区三区| 国产精品黄视频| 欧美福利视频一区二区| 欧美成人日韩| 日韩性xxxx爱| 日本人亚洲人jjzzjjz| 日韩伦理一区二区三区| 亚洲精品一区二区三区99| 在线视频观看一区二区| 欧美第一视频| 色综合av在线| 日韩人妻精品无码一区二区三区| 欧美草逼视频| 亚洲免费在线看| 中文字幕久精品免| 9色在线观看| 欧美国产日韩a欧美在线观看| 久久99精品久久久久久青青日本| 亚洲精品免费在线观看视频| 国产精品综合av一区二区国产馆| 国产精品影片在线观看| 中文在线免费观看| 蜜桃视频一区二区| 国产精品视频一区二区三区四| 最近免费中文字幕大全免费版视频| 日韩亚洲国产欧美| 97免费在线视频| 亚洲天堂日韩av| 99视频+国产日韩欧美| 久久乐国产精品| 日韩免费av片| 亚洲精品美女| 欧美在线性视频| 一级黄色在线视频| 视频一区在线播放| 国产精品久久97| 中文字幕一区二区三区四区免费看 | 日韩免费av电影| 国产午夜视频在线观看| 国产欧美一区二区精品忘忧草 | 婷婷一区二区三区| 国自产拍偷拍精品啪啪一区二区| free性护士videos欧美| 懂色aⅴ精品一区二区三区蜜月| 日本毛片在线免费观看| 香蕉久久免费电影| 欧美无乱码久久久免费午夜一区| 色一情一区二区三区| 视频二区欧美毛片免费观看| 亚洲大胆美女视频| 老熟妇一区二区| 亚洲澳门在线| 久久久亚洲国产| 在线观看 亚洲| 久久精品国产一区二区三区免费看| 国产日韩在线观看av| 国内精品偷拍视频| 91丝袜呻吟高潮美腿白嫩在线观看| 欧美在线一二三区| 美女国产在线| 亚洲高清三级视频| 欧美日韩在线成人| 麻豆精品久久| 亚洲乱码国产乱码精品精| 91ts人妖另类精品系列| 国模吧视频一区| 国产a∨精品一区二区三区不卡| 亚洲天天综合网| 成人午夜激情视频| 亚洲国产欧美一区二区三区不卡| 日本无删减在线| 色视频一区二区| 日本少妇激三级做爰在线| 欧美电影在线观看免费| 久久精品免费播放| www.伊人久久| 国产一区二区电影| 欧美激情第一页在线观看| 国产精品扒开做爽爽爽的视频| 欧美人体视频xxxxx| 国产精品一区二区三区四区| 国内一区二区三区在线视频| av中文字幕一区二区三区| 亚洲午夜影视影院在线观看| 色播五月综合网| 欧美尿孔扩张虐视频| 久久久999精品免费| youjizz在线视频| 国产91丝袜在线18| 一区二区成人国产精品| 日韩深夜视频| 欧美大肚乱孕交hd孕妇| 日日碰狠狠添天天爽| 久热精品在线| 国产一区二区三区高清视频| caopeng在线| 欧美日韩国产精选| www在线观看免费视频| 在线欧美视频| 91福利视频导航| 婷婷视频在线| 在线日韩一区二区| 精品夜夜澡人妻无码av| 伊人久久久大香线蕉综合直播 | 久久综合导航| 国产精品免费看一区二区三区| 麻豆视频在线观看免费| 在线国产亚洲欧美| 亚洲图片另类小说| 性欧美xxxx大乳国产app| 俄罗斯精品一区二区| 国产超级va在线视频| 欧美色窝79yyyycom| www色com| 日韩av一区二| 日韩av一级大片| 国产精品亚洲一区二区三区在线观看| 日韩电影网在线| 日韩精品一区二区av| 不卡av在线网| 国产3p露脸普通话对白| 国产欧美一区二区三区米奇| 欧美精品久久久久久久久久| 亚洲毛片在线播放| 亚洲一级片在线观看| 中文字幕一区二区三区人妻在线视频| 最新国产精品| av资源一区二区| 超免费在线视频| 亚洲第一二三四五区| 日本少妇久久久| av在线一区二区三区| 国模无码视频一区二区三区| 亚洲毛片免费看| 国产不卡av在线| 成人影视在线播放| 欧美日本不卡视频| 欧美一区二区三区爽爽爽| 国产精品中文字幕一区二区三区| 成人免费在线视频播放| 加勒比久久高清| 欧美最顶级的aⅴ艳星| 国产视频网址在线| 欧美老人xxxx18| 久草免费新视频| 97se亚洲国产综合自在线不卡| 日本中文字幕片| 91免费视频污| 久久精品国产大片免费观看| 91九色单男在线观看| 秋霞在线视频| 日韩av在线影院| 国产黄色免费视频| 亚洲视频 欧洲视频| 无码人妻久久一区二区三区蜜桃| 性xx色xx综合久久久xx| 午夜精品美女久久久久av福利| av一级久久| 97色在线播放视频| 婷婷在线视频| 亚洲第一天堂无码专区| 人人妻人人爽人人澡人人精品| 亚洲欧美日韩人成在线播放| 97人妻天天摸天天爽天天| 日本欧美在线观看| 亚洲色婷婷久久精品av蜜桃| 伊人久久大香线蕉综合网蜜芽| 成人福利免费观看| 三妻四妾的电影电视剧在线观看| 中文字幕日韩欧美| 日韩一级片免费看| 欧美日韩精品免费观看视频| 日韩美女视频网站| 自拍偷拍亚洲综合| 亚洲国产无码精品| 国产福利一区二区三区在线视频| 欧美日韩第二页| 欧美三级网页| 日本成人黄色免费看| 亚洲高清在线一区| 国产精品a久久久久久| 国产一线二线在线观看| 色偷偷88888欧美精品久久久 | 久久sese| 欧美激情第1页| yjizz视频网站在线播放| 亚洲а∨天堂久久精品9966| 一卡二卡在线观看| 一本一本久久a久久精品综合麻豆| 极品久久久久久| 欧美激情在线免费观看| 污片免费在线观看| 国产成人亚洲综合a∨婷婷图片| 天美星空大象mv在线观看视频| 亚洲深爱激情| 97中文字幕在线| 亚洲精品一区二区妖精| 色综合电影网| 免费一区二区三区视频导航| 国产精品美女xx| 日本在线成人| 成人精品网站在线观看| 国产激情久久| 国产精品va在线播放我和闺蜜| 交100部在线观看| 欧美国产视频一区二区| 成人黄色在线电影| 久久亚洲电影天堂| 五月香视频在线观看| 亚洲最新在线视频| 国产在线自天天| 亚洲人成电影在线观看天堂色| 亚洲 欧美 精品| 亚洲精品国产精品久久清纯直播 | av亚洲一区| 国产999在线观看| 456亚洲精品成人影院| 国产99视频精品免视看7| 日韩电影av| 日韩av片免费在线观看| 性高爱久久久久久久久| 国产成人精品一区二区| 久久久成人av毛片免费观看| 国产aⅴ夜夜欢一区二区三区| 高清不卡av| 国产福利精品av综合导导航| 午夜精品成人av| 国产精品毛片a∨一区二区三区|国| 久久久成人av毛片免费观看| 国产精品久久久久久久电影 | 欧美色精品在线视频| 亚洲午夜激情视频| 91精品一区二区三区久久久久久| 91丨porny丨在线中文| 91精品国产色综合久久ai换脸 | 日韩电影第一页| 欧美色综合一区二区三区| 亚洲香蕉成人av网站在线观看| 成人不用播放器| 日韩视频一区在线| 青春草在线免费视频| 免费人成精品欧美精品 | 久久国产精品亚洲人一区二区三区| 亚洲午夜精品一区二区三区| 99久久久久国产精品| 特级黄色录像片| 在线精品在线| 欧美成人黑人猛交| 久久se这里有精品| 韩国一区二区三区四区| 99视频国产精品| 黄瓜视频污在线观看| 中文字幕精品在线不卡| 91高清免费观看| 午夜精品久久久久影视| 国产一级片一区二区| 日韩午夜在线观看视频| 视频一区二区三区国产| 中文字幕亚洲欧美在线| 爱情岛亚洲播放路线| 国产精品777| 亚洲专区**| 色狠狠久久av五月综合|| 在线国产一区| 中文字幕乱码人妻综合二区三区 | 午夜视频在线观看国产| 欧美激情在线免费观看| 国产在线拍揄自揄拍| 欧美在线高清视频| 亚洲免费成人网| 中文字幕在线视频日韩| 成人ssswww在线播放| 国产精品视频精品视频| 精品欠久久久中文字幕加勒比| 少妇免费毛片久久久久久久久| 亚洲一本视频| 五月天视频在线观看| 91理论电影在线观看| 青青草偷拍视频| 在线观看精品一区| 日本黄视频在线观看| 久久亚洲精品国产亚洲老地址| 中文字幕色婷婷在线视频| 亚洲一区二区三区成人在线视频精品 | 91久久国产综合久久蜜月精品| 国产91一区| 97超碰人人澡| 国产最新精品免费| 熟女少妇内射日韩亚洲| 亚洲va韩国va欧美va精品| 国产精品国产av| 综合视频一区| 91天堂在线视频| 欧美日韩国产传媒| 黄色一级在线视频| 国产乱子伦视频一区二区三区 | 国产精品久久毛片a| 中文字幕国产在线观看| 精品国产99国产精品| 18+视频在线观看| 国产日韩在线播放| 色135综合网| 日本888xxxx| 久久精品人人做| 视频一区二区三区四区五区| 日韩欧美一二三| 4438x成人网全国最大| 国产在线观看精品一区二区三区| 国产一区二区欧美| 熟女人妇 成熟妇女系列视频| 91丨九色丨国产丨porny| 日本中文字幕网| 亚洲成人黄色在线观看| 免费在线看电影| wwwxx欧美| 在线不卡欧美| 91丝袜在线观看| 精品久久久国产| 四虎影视精品成人| 91大神福利视频在线| 亚洲黄色录像| 国产精品wwwww| 国产人妖乱国产精品人妖| 波多野结衣视频在线观看| 亚洲最新中文字幕| 日韩黄色三级| 午夜久久久久久久久久久| 国产精品一区三区| 久久成人在线观看| 日韩av在线网页| 亚洲va中文在线播放免费| 手机成人在线| 激情五月播播久久久精品| 麻豆91精品91久久久| 亚洲精品一区二区三区四区高清 | 首页国产精品| www.五月天色| 亚洲午夜成aⅴ人片| 五十路在线观看| 国产精品va在线播放| 999精品色在线播放| 日韩大尺度视频| 欧美性生交大片免费| av在线电影播放| 亚洲自拍偷拍视频| 夜夜爽av福利精品导航| 色一情一交一乱一区二区三区 | 人妻一区二区三区免费| 26uuu另类亚洲欧美日本一| 教室别恋欧美无删减版| 999久久久精品视频| 亚洲高清久久久| 激情小说 在线视频| 成人在线视频网| 亚洲免费播放| 久久精品三级视频| 日韩欧美自拍偷拍| 唐人社导航福利精品| 无码毛片aaa在线| 久久蜜桃香蕉精品一区二区三区| 国产又粗又猛又爽又黄视频| 欧美精品九九久久| 精品一区二区三| 又色又爽又黄18网站| 色婷婷av一区二区三区大白胸| av网址在线看| 欧美午夜精品理论片a级大开眼界 欧美午夜精品久久久久免费视 | 日韩激情视频一区二区| 国产欧美一区二区三区网站| 精品欧美在线观看|