C++高效解析JSON字符串
1. 什么是JSON字符串說明?
定義:
JSON(Javascript Object Notation)是一種輕量級的數據交換格式,易于閱讀和編寫,也易于機器解析和生成。
結構:
a. 名稱/值 的集合,Json對象是鍵值對構成,類似于map。其鍵為普通字符串,值可以為任意類型,如數字、邏輯值、文本、數組對象、Json對象、null等。
b. 數組,Json對象也可以為一個數組,有一個或者多個數值構成,其中數值可以為任意類型,如數字、邏輯值、文本、數組對象、Json對象、null等。
c. 語法
數據在名稱/值對中
數據由逗號分隔
花括號保存對象
方括號保存數組
舉例:
a. 簡單例子:{"firstname": "peisheng"}
b. 多個數據:{"firstname": "peisheng", "lastname": "h", "email": "buzhidao"}
c. 數組例子:
{ "zubie": "cad",
"members": [
{"firstname": "peisheng", "lastname": "h", "email": "buzhidao"},
{"firstname": "peisheng", "lastname": "h", "email": "buzhidao"},
{"firstname": "peisheng", "lastname": "h", "email": "buzhidao"}
]
}
2. 為什么選擇Json作為數據傳輸?而不是XML?
可讀性:Json和XML相比可謂不相上下,一邊是簡單的語法,一邊是規范的標簽形式,很難分出勝負。
可擴展性:XML天生有很好的可擴展性,Json也有。
編碼難度:XML有豐富的編碼工具,Json也有提供,但是XML要輸入很多結構字符。
解碼難度:凡是可擴展的數據結構,解析起來都很困難。
數據量: Json具有輕小的特點,降低了數據傳輸量。
3. JSONCPP庫介紹
目前市場上有很多Json解析的開源庫,http://www.json.org/,這個網站中有對Json的介紹,以及列出了各種語言實現的Json解析庫。JSONCPP是一個C++實現的面向對象的跨平臺開源庫,具有易用、易讀的特點。
JSONCPP中重要的類:
a. Json::Value 可以表示所有的類型,比如int、string、object、array等。
b. Json::Reader 可以從Json字符串中解析出Json::Value對象。
c. Json::Writer 可以把Json::Value對象寫入到字符串流或者文件中。
但是JsonCPP解析性能低,使用了std標準庫的東西,在CAD的環境下很容易崩潰,最后放棄。
4. 如何讀取Json字符串?
解碼時,把Json字符串看成是一個map對象(object),對象(object)的鍵為字符串,值為任意類型,可以為int、string、bool、array、object等。解析Json字符串時,首先對當前層map解析解析,解析出key/val對。
解析過程:
a. 在鍵值對出現時,記錄鍵的起始位置,kvoff1_key, kvoff1_val
b. 在鍵值對結束時,記錄值的結束位置,kvoff2_key, kvoff2_val
c. 設置*kvoff2_key = 0, *kvoff2_val = 2
d. 在Json對象中,用map記錄鍵值的起始位置
e. 重復a~d四個步驟
舉例說明:
{"k1":"x1","k2":[1,2,3],"k3":{"k31":"v1"}}
按照上面的步驟進行解析
a. kvoff1_key=2, kvoff1_val=7
b. kvoff2_key=4, kv0ff2_val=9
c. *kvoff2_key=0, *kvoff2_val=0
d. Map.insert(kvoff1_key, kvoff1_val)
e. 重復a~d
5. 如何編輯Json字符串?
由于Json對象在內部維護了一份Json字符串內存RawBuf,插入時,在RawBuf后面添加一份鍵值對,并在所屬的Json對象中記錄一下鍵值對的起始位置,設置鍵和值的末尾值為0。
如果追加的字符串的大小,比RawBuf剩余空間大時,添加List<TCHAR*> RawBufs字段,提供多緩沖支持,最后一個Buffer為當前正在使用的Buffer。
RawBuf是使用步驟:
a. 初始化Json對象時,初始化一個 RAWBUFLEN=65535的TCHAR數組,并將該數組的指針添加到RawBufs中。
b. 插入一個鍵值對時,如果Buffer的剩余空間不足,生成一個大小為max(RAWBUFLEN, len(key) + len(val) + 2) 大小的TCHAR數組,并將數組的指針添加到RawBufs中,在將新值復制到剛才申請的空間里。