日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

自己实现JSON、XML的解析 没那么难

發(fā)布時間:2024/1/17 asp.net 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自己实现JSON、XML的解析 没那么难 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文的目的,不是針對現(xiàn)有的可用于生產(chǎn)環(huán)境的JSON、XML解析器源碼進(jìn)行剖析,而是介紹文本掃描的基礎(chǔ)方法next(char),并以此為核心武器,根據(jù)目標(biāo)語言的詞法和語法特點(diǎn),一步步地組織出條例清晰、易維護(hù)的解析器代碼。希望這會是一篇實(shí)踐性強(qiáng),讓您有所收獲的文章。

另外,這里需要提前說明的是,本文所實(shí)現(xiàn)的解析器僅作為coding練習(xí)使用。一些目標(biāo)語言的規(guī)范中提到的語法,可能無法正常解析。另外,本文所實(shí)現(xiàn)的解析器也缺少大量的實(shí)例進(jìn)行測試。請不要用于生產(chǎn)用途。

前言

作為一個非科班前端程序員,我最近特別癡迷于自學(xué)《編譯原理》這門課。原因在于,自己大學(xué)時代的專業(yè)是語言學(xué),其中的理論有頗多相似之處;再加上前端工作中,模版編譯成render function,webpack通過loader加載文件等都方面涉及到了編譯。我也希望自己能多了解一些編譯知識,說不定能在日后的前端工作中能夠發(fā)揮奇效。

看了一些youtube上的公開課資源,啃了一點(diǎn)龍書這樣的編譯原理經(jīng)典作品后,我感覺自己只了解了一堆關(guān)于詞法法解析、語法解析的理論總結(jié),很難從中獲得“學(xué)會了”、“會用了”這樣的成就感。于是在稍稍有了一點(diǎn)知識基礎(chǔ)后,我開始尋找github上關(guān)于解析器的源碼。

JSON的解析

這里想給大家推薦的是JSON之父,Douglas Crockford的repo: JSON-js中的這個源代碼,它也是本文的靈感源泉:

JSON-js/json_parse.js at master · douglascrockford/JSON-js

據(jù)代碼注釋,這個文件實(shí)現(xiàn)了JSON.parse方法,使用的解析手段是recursive decending(遞歸下降分析)。

在同一個repo里還有一個json_parse_state.js文件,也是JSON.parse方法的實(shí)現(xiàn),使用的解析手段是state machine(狀態(tài)機(jī))。

其實(shí)我個人認(rèn)為上文鏈接中的源代碼使用的解析手段也是state machine,因?yàn)閞ecursive decending應(yīng)該是語法分析使用的方法來著= =。

但從代碼的清晰度上來看,json_parse.js要好不少,所以更推薦閱讀。

快速地過一遍源碼,我們可以發(fā)現(xiàn)一個核心函數(shù):

var next = function (c) {// If a c parameter is provided, verify that it matches the current character.if (c && c !== ch) {error("Expected '" + c + "' instead of '" + ch + "'");}// Get the next character. When there are no more characters, // return the empty string.ch = text.charAt(at);at += 1;return ch; }; 復(fù)制代碼

這個方法相當(dāng)于一個字符掃描器,其中使用的全局變量at是當(dāng)前掃描光標(biāo)所處位置的索引,ch是當(dāng)前掃描光標(biāo)所處位置的字符。調(diào)用next方法時,如果傳入了參數(shù)c(也是一個字符),則會比較此字符與當(dāng)前掃描器所在的字符,如果不相同就會報(bào)錯,并且掃描光標(biāo)不會向前移動;如果未傳參數(shù),掃描光標(biāo)的位置和所指的字符都會向前更新一個位置。

這份代碼中的其他函數(shù),充斥著對next的調(diào)用,讓我們來看幾個例子感受一下next的用法。

var word = function () {// true, false, or null.switch (ch) {case "t":next("t");next("r");next("u");next("e");return true;case "f":next("f");next("a");next("l");next("s");next("e");return false;case "n":next("n");next("u");next("l");next("l");return null;}error("Unexpected '" + ch + "'"); }; 復(fù)制代碼

word函數(shù)用來處理JSON中的三個常量token,即true, false和null。整個函數(shù)根據(jù)首字母,分別接收t->r->u->e,f->a->l->s->e,n->u->l->l這樣的字符輸入。如果其中出現(xiàn)了其他順序的字符輸入,都會拋出Error。word方法還會在匹配token的同時,返回所匹配到的token的值。3個return語句所出現(xiàn)的位置,表示word函數(shù)已經(jīng)接受了這段字符輸入,并成功解析出了一個值。

再來看另一個不傳參調(diào)用next()的例子:

var white = function () {// Skip whitespace.while (ch && ch <= " ") {next();} }; 復(fù)制代碼

white函數(shù)的作用僅在于跳過空白,只要當(dāng)前字符是屬于空白的,就不停地調(diào)用next()作無條件后跳。

源碼中還有number和string函數(shù),其用途和上面的word, white一樣,只不過邏輯更為復(fù)雜,可以解析出不定長度、不定字符組合的數(shù)字和字符串。

一步一步地寫出這些“零件”的解析函數(shù)后,我們就可以進(jìn)一步寫出一些復(fù)合結(jié)構(gòu)的解析函數(shù)了,也就是源碼中的array和object函數(shù)。

最后,源碼中實(shí)現(xiàn)了可以解析任意一個JSON元素的value函數(shù)。從語法的角度講,這里所定義的value,可以是任何一個string, number, array或object,至此,我們就完成了解析所有JSON元素需要的函數(shù)。

以上就是解析的核心代碼了,個人認(rèn)為十分地易于理解并且有明確的分層,易于維護(hù)以及以后增加功能。我也在這里用同樣的next函數(shù)的手法,嘗試重寫了這個JSON解析器源代碼。作為練習(xí),我沒有實(shí)現(xiàn)escape或revive等功能,但把各個解析函數(shù)拆分得更加精細(xì)(例如為每個單字符token都寫了解析函數(shù),將array拆解為[ + elements + ]等),使得代碼更易讀。地址是:

18 JSON parser

XML的解析

有了上面的JSON解析器實(shí)現(xiàn)的“手感”,我又嘗試著用同樣的next函數(shù)手法,部分地實(shí)現(xiàn)了XML的解析。和JSON相比,個人在實(shí)現(xiàn)過程中發(fā)現(xiàn)的坑點(diǎn)主要在于:

  • JSON對象基本上就是JavaScript中Object對象的字面化表示,所以每次解析出來一小段之后,直接以JavaScript數(shù)列或?qū)ο蟮男问奖4婕纯伞ML節(jié)點(diǎn)需要為其定義類似下面的數(shù)據(jù)結(jié)構(gòu),所以代碼的復(fù)雜度略有增加:
Node {tagName //節(jié)點(diǎn)標(biāo)簽名attrs //節(jié)點(diǎn)上的屬性,為key/value的數(shù)組children //節(jié)點(diǎn)的子節(jié)點(diǎn),為Node的數(shù)組 } 復(fù)制代碼
  • XML對象必須作語法分析,也就是close tag有沒有匹配的問題。諸如<a><b></a></b>這樣的XML需要提示解析錯誤。不過實(shí)現(xiàn)這個也很簡單,使用一個nodeStack棧,在opentag時推入節(jié)點(diǎn);在closetag時檢查當(dāng)前節(jié)點(diǎn)是否和棧尾的tag相匹配,匹配則推出末尾的節(jié)點(diǎn);在comment節(jié)點(diǎn)或text節(jié)點(diǎn)時不作處理即可。
  • comment節(jié)點(diǎn)的結(jié)束判斷。comment節(jié)點(diǎn)的格式是<!--content-->,因此在解析content部分時,每輸入一個字符,需要作3個字符的提前判斷。即,如果當(dāng)前所讀到的字符的接下來三個字符分別是-->時,停止解析。

我所實(shí)現(xiàn)的XML解析器的代碼如下(沒有實(shí)現(xiàn)self-closing tag的解析功能,例如<br>, <input>等。所有tag必須成對出現(xiàn)):

20 XML parser

轉(zhuǎn)載于:https://juejin.im/post/5a46e174518825698e726486

總結(jié)

以上是生活随笔為你收集整理的自己实现JSON、XML的解析 没那么难的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。