精品欧美一区二区三区在线观看 _久久久久国色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在线观看| 亚洲精品suv精品一区二区| 中文字幕欧美人与畜| 91亚洲精品国偷拍自产在线观看| 希岛爱理av一区二区三区| 日韩一级二级三级精品视频| 久久精品视频16| 伊人免费在线| jlzzjlzz亚洲日本少妇| 国产精品三级网站| 国产无精乱码一区二区三区| 久久成人av| 91精品国产入口在线| 六月丁香激情网| 成人影院在线看| 久久精品夜色噜噜亚洲a∨| 91亚洲精品久久久| 中文字幕xxxx| 日韩午夜免费| 久久国产精品视频| 欧美三级视频网站| 伦理一区二区| 日韩一区二区三区电影| 99热手机在线| 在线看片福利| 亚洲国产精品嫩草影院| 亚洲亚洲精品三区日韩精品在线视频| 欧美一区二区公司| 国产精品影视网| 国产精品视频一区二区三区四| 日韩乱码在线观看| 午夜精品偷拍| 久久久国产在线视频| 99久久久无码国产精品衣服| 免费成人三级| 精品国产乱子伦一区| 久久精品久久99| 成人全视频免费观看在线看| 日本精品一级二级| 久久久精品在线视频| 成人免费图片免费观看| 亚洲一级二级在线| 欧美美女黄色网| 精精国产xxxx视频在线| 亚洲国产精品高清| 日本一区二区在线视频| 日本韩国一区| 99久久精品免费精品国产| 国产99视频精品免费视频36| 99久久国产免费| 国产综合一区二区| 成人国产精品久久久| 夜夜躁很很躁日日躁麻豆| 三级久久三级久久| 日韩av免费在线看| 久久久久在线视频| 日韩黄色免费网站| 国产精品久久久久久中文字 | 自拍偷拍欧美精品| 自拍偷拍一区二区三区| 成人av福利| 亚洲精品久久久久久国产精华液| 欧洲xxxxx| 亚洲色图美国十次| 亚洲一二三四在线| 日韩精品 欧美| 亚洲欧美小说色综合小说一区| 欧美日韩中文在线观看| 免费日韩中文字幕| 91成人在线| 欧美一卡二卡三卡| 影音先锋资源av| 女同久久另类99精品国产| 亚洲美女性生活视频| www.黄色在线| 亚洲欧美色图| 午夜精品久久久久久99热| 欧美特黄aaaaaa| 日韩在线a电影| 国产日韩欧美在线观看| 性一交一乱一精一晶| av中文字幕亚洲| 日韩精品电影网站| 麻豆tv入口在线看| 亚洲成av人片一区二区| 国产情侣av自拍| 四虎影视成人精品国库在线观看| 欧美电影免费提供在线观看| www.免费av| 三上亚洲一区二区| 欧美国产高跟鞋裸体秀xxxhd| 日本三级网站在线观看| 日韩精品成人一区二区三区| 亚洲自拍偷拍一区| 欧美婷婷久久五月精品三区| 中文字幕视频一区| 免费看日本毛片| 四虎国产精品免费久久5151| 亚洲精品美女在线观看| а天堂中文在线资源| 亚洲一级电影| 国产精品一二三在线| 后进极品白嫩翘臀在线视频| 国产精品午夜春色av| 成年人网站国产| 九九热这里有精品| 日韩av一区二区在线| 婷婷国产成人精品视频| 99精品福利视频| 91九色综合久久| 撸视在线观看免费视频| 一区二区三区美女视频| 五月婷婷丁香综合网| 你懂的在线观看一区二区| 久久亚洲私人国产精品va| 五月婷婷激情视频| 不卡的av网站| 小泽玛利亚av在线| 精品美女一区| 亚洲最新中文字幕| 中文字幕一区二区人妻电影| 粉嫩aⅴ一区二区三区四区 | 国产福利第一视频在线播放| 一区二区三区国产| 天天操天天干天天做| 欧美日本成人| 91地址最新发布| 亚洲国产日韩在线观看| 亚洲欧美乱综合| jizz18女人| 蜜桃视频欧美| 97在线观看免费| 六月丁香综合网| 亚洲精品中文字幕在线观看| www.夜夜爽| 久久五月天小说| 国产精品视频永久免费播放 | 99精品国产高清一区二区麻豆| 日韩亚洲第一页| 中文字幕一区二区免费| 久久免费视频一区| 免费黄色福利视频| 欧美亚洲色图校园春色| 88国产精品欧美一区二区三区| www久久久com| 亚洲精品日韩一| 欧美专区第二页| 欧美成人一品| 操一操视频一区| 欧美色图天堂| 精品欧美一区二区三区精品久久| 久久久精品人妻一区二区三区四| 国产一区二区精品久久99| 一区二区免费在线观看| 婷婷丁香久久| 免费不卡在线观看av| av网站在线观看免费| 亚洲另类中文字| 97精品人人妻人人| 国产欧美在线| 欧美日韩另类综合| 国产成人精品123区免费视频| 亚洲天堂免费观看| 中文字幕视频一区二区| 亚洲欧美日韩一区二区三区在线观看| 日本一二三四区视频| 国内精品久久久久久久影视麻豆| 国产精品免费一区二区三区| 国产精品原创| 在线播放日韩av| 国产精品久久久久久久免费看 | 国产一二三四区在线观看| 亚洲日本va中文字幕| 97香蕉超级碰碰久久免费的优势| 撸视在线观看免费视频| 欧美精品v日韩精品v韩国精品v| 蜜臀av午夜精品久久| 成人午夜激情影院| 国内外成人免费激情视频| 日韩欧美高清| 高清不卡一区二区三区| 伊伊综合在线| 精品国产欧美一区二区五十路| 成 人 黄 色 片 在线播放| 精品美女国产在线| 手机免费观看av| 成人一区二区三区视频在线观看 | 国产不卡精品| 97av在线影院| 麻豆网站在线| 日韩精品免费视频| 国产精品久久久久久在线| 亚洲va欧美va人人爽| 日本免费www| 懂色av一区二区三区蜜臀| 粉嫩虎白女毛片人体| 亚洲五月综合| 青青成人在线| 91嫩草精品| 成人国产精品av| 日韩欧美一中文字暮专区| 精品国产依人香蕉在线精品| 四虎永久在线精品免费网址| 欧美日本乱大交xxxxx| 国产精品变态另类虐交| 中文字幕一区av| 亚洲av无码一区二区二三区| 国产麻豆一精品一av一免费 | 欧美交换配乱吟粗大25p| 精品久久视频| 麻豆视频成人| 91国内精品| 成人h视频在线观看播放| 久久uomeier| 久久久视频精品| 成人国产免费电影| 最新的欧美黄色| 人成在线免费视频| 精品国产一区二区国模嫣然| 一本一道人人妻人人妻αv| 欧美视频在线观看 亚洲欧| 91porn在线视频| 成人免费在线播放视频| 懂色av蜜桃av| 国产欧美一区视频| 韩国女同性做爰三级| 99re成人在线| 亚州av综合色区无码一区| 国产91精品精华液一区二区三区| 99久久99精品| 国产在线国偷精品免费看| 亚洲va综合va国产va中文| 免费视频一区二区| 精品少妇无遮挡毛片| 久久精品一区二区国产| 亚洲自偷自拍熟女另类| 一区二区三区精品视频在线观看 | 色在线视频观看| 97视频免费在线看| 成人观看网址| 97精品久久久中文字幕免费| a国产在线视频| 38少妇精品导航| 国产精品专区免费| 国产97免费视| 91综合国产| 国产日韩一区在线| 婷婷久久免费视频| 亚洲iv一区二区三区| 精品中文在线| 99视频免费观看| 澳门成人av| 久久久7777| 精品国产精品国产偷麻豆| 日韩欧美亚洲在线| 999精品在线| 国产一区一区三区| 欧美日本精品| 91好吊色国产欧美日韩在线| 9国产精品视频| 国产性xxxx18免费观看视频| 日本怡春院一区二区| 亚洲xxx在线观看| 国产精品1区2区3区在线观看| 无码人妻丰满熟妇区毛片蜜桃精品| 国产精品99久久久久久有的能看 | 国产精品久久久久av蜜臀| 激情欧美一区二区三区中文字幕| 婷婷国产精品| 亚洲日本无吗高清不卡| 欧美涩涩网站| 国产aaa一级片| 精品综合免费视频观看| www日本在线观看| 麻豆成人入口| 精品亚洲aⅴ在线观看| 三级视频网站在线| 一本色道久久88精品综合| 亚洲成人三级| 欧美极品少妇xxxxⅹ免费视频 | 91精品国产色综合久久不卡98口| 欧美黑人粗大| 国产在线播放不卡| 好吊妞视频这里有精品| 日韩欧美在线观看强乱免费| 欧美一区二区三区免费看| 少妇高潮喷水久久久久久久久久| 麻豆国产精品官网| 在线观看免费视频国产| 国产日本欧美一区二区| 麻豆视频在线观看| 欧美一a一片一级一片| xxxx18国产| 原创国产精品91| 91九色美女在线视频| 国产精品日韩欧美综合| h视频久久久| 一区二区三区三区在线| 夜久久久久久| 四虎1515hh.com| 免费观看黄网站| 久久黄色网页| 久国产精品视频| 久久伊99综合婷婷久久伊| 中文字幕在线观看2018| 懂色av一区二区三区| 国产女人高潮时对白| 日韩黄色av网站| 中文字幕中文字幕在线中高清免费版| 欧美野外猛男的大粗鳮| 日韩一区二区三区在线看| 日韩欧美一区二区三区四区 | 九九热在线精品视频| 亚洲电影有码| 麻豆成人av| 影音先锋在线一区| 爱豆国产剧免费观看大全剧苏畅| 久久老女人爱爱| 国产污污视频在线观看| 欧美大黄免费观看| 久久亚洲天堂| 国产综合视频在线观看| 欧美三级情趣内衣| 哪个网站能看毛片| av不卡免费电影| 久久精品无码人妻| 欧美变态tickling挠脚心| 大片免费在线观看| 成人免费午夜电影| 天天做天天爱天天爽综合网| 九色porny自拍| 国产精品乱码一区二三区小蝌蚪| 加勒比在线一区| 亚洲色图美腿丝袜| 成人勉费视频| 久久综合精品一区| 国产精品婷婷| 精品无码在线视频| 五月天欧美精品| 四虎国产精品永远| 欧美一级视频免费在线观看| 神马日本精品| 无码人妻丰满熟妇区毛片18| 久久亚洲精品小早川怜子| 最新中文字幕一区| 日韩国产欧美精品在线| 中文字幕不卡三区视频| 欧美日韩一区在线播放| 久久久国产精品一区二区中文| 国产特黄级aaaaa片免| 色偷偷成人一区二区三区91| 黄色av网站在线免费观看| 国产精品jvid在线观看蜜臀| 成人嫩草影院| 色啦啦av综合| 亚洲精品伦理在线| 国产成人三级在线观看视频| 97在线视频观看| 精品久久成人| 欧美激情国内自拍| 亚洲资源在线观看| av7777777| 93在线视频精品免费观看| 99sesese| 亚洲一区二区三区四区五区中文| 嫩草影院一区二区| 91a在线视频| 欧美伦理影院| 日本xxxx免费| 狠狠做深爱婷婷久久综合一区| 国产三级在线| 亚洲综合色激情五月| 国产午夜久久| 成人黄色短视频| 欧美不卡一区二区三区四区| 天堂av中文在线观看| 偷拍视频一区二区| 国产91在线|亚洲| 国产免费一级视频| 久久久精品亚洲| 精品久久ai电影| 国产一二三四在线视频| 一区二区三区精品在线观看| 日韩欧美在线观看一区二区| 国产欧美一区二区白浆黑人| 午夜精品久久久久99热蜜桃导演| 中文在线一区二区三区| 欧美视频一区在线| 不卡的av影片| 在线视频欧美一区| 99久久久精品| 国产又粗又猛又爽又黄的| 韩国三级电影久久久久久| 精品日产免费二区日产免费二区| 妖精视频在线观看| 91久久人澡人人添人人爽欧美| 成人在线app| 日韩影片在线播放| 成人激情免费网站| 91精品国产乱码久久久|