Jsoup代码解读之五-parser(中)
轉載自? ??Jsoup代碼解讀之五-parser(中)
上一篇文章講到了狀態機和詞法分析的基本知識,這一節我們來分析Jsoup是如何進行詞法分析的。
代碼結構
先介紹以下parser包里的主要類:
Parser
Jsoup parser的入口facade,封裝了常用的parse靜態方法。可以設置maxErrors,用于收集錯誤記錄,默認是0,即不收集。與之相關的類有ParseError,ParseErrorList。基于這個功能,我寫了一個PageErrorChecker來對頁面做語法檢查,并輸出語法錯誤。
Token
保存單個的詞法分析結果。Token是一個抽象類,它的實現有Doctype,StartTag,EndTag,Comment,Character,EOF6種,對應6種詞法類型。
Tokeniser
保存詞法分析過程的狀態及結果。比較重要的兩個字段是state和emitPending,前者保存狀態,后者保存輸出。其次還有tagPending/doctypePending/commentPending,保存還沒有填充完整的Token。
CharacterReader
對讀取字符的邏輯的封裝,用于Tokenize時候的字符輸入。CharacterReader包含了類似NIO里ByteBuffer的consume()、unconsume()、mark()、rewindToMark(),還有高級的consumeTo()這樣的用法。
TokeniserState
用枚舉實現的詞法分析狀態機。
HtmlTreeBuilder
語法分析,通過token構建DOM樹的類。
HtmlTreeBuilderState
語法分析狀態機。
TokenQueue
雖然披了個Token的馬甲,其實是在query的時候用到,留到select部分再講。
詞法分析狀態機
現在我們來講講HTML的詞法分析過程。這里借用一下http://ued.ctrip.com/blog/?p=3295里的圖,圖中描述了一個Tag標簽的狀態轉移過程,
這里忽略了HTML注釋、實體以及屬性,只保留基本的開始/結束標簽,例如下面的HTML:
<!-- lang: html --> <div>test</div>Jsoup里詞法分析比較復雜,我從里面抽取出了對應的部分,就成了我們的miniSoupLexer(這里省略了部分代碼,完整代碼可以看這里MiniSoupTokeniserState):
<!-- lang: java --> enum MiniSoupTokeniserState implements ITokeniserState {/*** 什么層級都沒有的狀態* ?* <div>test</div>* ?* <div>test</div>*/Data {// in data state, gather characters until a character reference or tag is foundpublic void read(Tokeniser t, CharacterReader r) {switch (r.current()) {case '<':t.advanceTransition(TagOpen);break;case eof:t.emit(new Token.EOF());break;default:String data = r.consumeToAny('&', '<', nullChar);t.emit(data);break;}}},/*** ?* <div>test</div>*/TagOpen {...},/*** ?* <div>test</div>*/EndTagOpen {...},/*** ?* <div>test</div>*/TagName {...};}參考這個程序,可以看到Jsoup的詞法分析的大致思路。分析器本身的編寫是比較繁瑣的過程,涉及屬性值(區分單雙引號)、DocType、注釋、HTML實體,以及一些錯誤情況。不過了解了其思路,代碼實現也是按部就班的過程。
下一節開始介紹語法分析部分。
最后還是附上我的Jsoup解讀系列文章及代碼地址:
https://github.com/code4craft/jsoup-learning
總結
以上是生活随笔為你收集整理的Jsoup代码解读之五-parser(中)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑配置2015年(电脑配置 2015)
- 下一篇: 2015电脑配置(2015 电脑配置)