json(JavaScript Object Notation)是一種輕量級高效數據交換格式。相比於XML,其更加簡潔,解析更加方便。在實習期間,我負責的程序模塊,多次使用到json進行數據傳輸。由於之前只對json稍稍了解,而且不熟悉項目組使用的開源json解析庫,故在編碼過程中效率很低,而且還出現過bug。雖然,最后項目組的事情比較順利的完成了,但感覺自己對json的編解碼熟悉仍然不夠,故翻閱了相關文檔,寫下這篇技術博客。與君共勉。
1.什么是json
JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。它基於ECMAScript的一個子集。 JSON采用完全獨立於語言的文本格式,但是也使用了類似於C語言家族的習慣(包括C、C++、C#、Java、JavaScript、Perl、Python等)。這些特性使JSON成為理想的數據交換語言。 易於人閱讀和編寫,同時也易於機器解析和生成(網絡傳輸速率)[摘自百度百科]。
再舉個簡單的例子。假如要用xml和json來存儲一個學生的個人信息,則XML和json的數據格式分別如下:
XML:
<student>
<name>joekuang</name>
<age>25</age>
<hobby>sports</hobby>
</student>
json:
{"name":"joekuang","age":25,"hobby":"sports"}
相比之下,顯而易見,json存儲所需的空間要小得多,數據更加簡潔。不過xml也有它的好處,就是格式清晰明了,更容易解析。
2.jsoncpp簡介及測試用例
jsoncpp是一個開源的輕量級C++ json解析庫,簡單易用,非常方便。可通過如下兩個地址獲取源碼:(1)http://sourceforge.net/projects/jsoncpp/ (2) https://github.com/open-source-parsers/jsoncpp。json源碼的目錄如下:
- ├── include
- │ └── json
- │ ├── autolink.h
- │ ├── config.h
- │ ├── features.h
- │ ├── forwards.h
- │ ├── json.h
- │ ├── reader.h
- │ ├── value.h
- │ └── writer.h
- ├── makefile
- └── src
- ├── json
- │ ├── json_batchallocator.h
- │ ├── json_internalarray.inl
- │ ├── json_internalmap.inl
- │ ├── json_reader.cpp
- │ ├── json_value.cpp
- │ ├── json_valueiterator.inl
- │ ├── json_writer.cpp
- │ └── sconscript
- └── main.cpp
如上圖所示,include/json目錄下為開源解析庫頭文件目錄,src/json為源碼文件,main.cpp為測試用例文件。通過在根目錄下鍵入make命令,即可生成可執行程序main,運行就能看到例子效果。測試用例源碼如下:
- #include <string>
- #include <json/json.h>
-
- void readJson();
- void writeJson();
-
- int main(int argc, char** argv) {
- readJson();
- writeJson();
- return 0;
- }
-
- void readJson() {
- using namespace std;
- std::string strValue = "{\"name\":\"json\",\"array\":[{\"cpp\":\"jsoncpp\"},{\"java\":\"jsoninjava\"},{\"php\":\"support\"}]}";
-
- Json::Reader reader;
- Json::Value value;
-
- if (reader.parse(strValue, value))
- {
- std::string out = value["name"].asString();
- std::cout << out << std::endl;
- const Json::Value arrayObj = value["array"];
- for (unsigned int i = 0; i < arrayObj.size(); i++)
- {
- if (!arrayObj[i].isMember("cpp"))
- continue;
- out = arrayObj[i]["cpp"].asString();
- std::cout << out;
- if (i != (arrayObj.size() - 1))
- std::cout << std::endl;
- }
- }
- }
-
- void writeJson() {
- using namespace std;
-
- Json::Value root;
- Json::Value arrayObj;
- Json::Value item;
-
- item["cpp"] = "jsoncpp";
- item["java"] = "jsoninjava";
- item["php"] = "support";
- arrayObj.append(item);
-
- root["name"] = "json";
- root["array"] = arrayObj;
-
- root.toStyledString();
- std::string out = root.toStyledString();
- std::cout << out << std::endl;
- }
- </span>
執行效果如下:


在實際使用開源庫的過程中,為了方便起見,我一般把include和src兩個目錄下的文件進行合並。

3.如何使用jsoncpp
對於絕大部分程序員來說,只要了解jsoncpp中的三個類的使用就基本可以完成json數據的生成與解析工作。這三個類分別是:Json::Value,Json::Reader,Json::Writer。
3.1 Json::Value
Json::Value 是jsoncpp 中最基本、最重要的類,用於表示各種類型的對象,jsoncpp 支持的對象類型可在value.h文件的ValueType中查看,包括:
1.nullValue空值類型,即內容為空
2.intValue 有符號整型類型
3.uintValue 無符號整型
4.realValue 有理數,即浮點數
5.stringValue 字符串
6.booleanValue 布爾類型:true,false
7.arrayValue 數組,數組內容可為上述6種
8.objectValue 對象類型,對象內容可為上述7種
現在就基於上述幾種類型構建一個復雜的Json::Value。
- Json::Value joe;
- joe["name"]=Json::Value("joekuang");
- joe["age"]=Json::Value(25);
- joe["wage"]=Json::Value(123.45);
- joe["wife"]=Json::Value();
- joe["hobby"].append("running");
- joe["hobby"].append("basketball");
- Json::Value family;
- family["name"]=Json::Value("joe's home");
- family["isCountry"]=Json::Value(true);
- family["member"]=joe;
3.2 Json::Writer
在3.1節中,產生的Json數據,要怎么才能顯示出來呢?或者說,怎么轉換成可查看的內容(string)?這個時候,就需要使用到Json::Writer了。Json::Writer是一個虛類,不能直接使用,我們可以通過它的兩個子類Json::FastWriter和Json::StyledWriter來輸出顯示。兩者的區別是,FastWriter顯示的內容去掉了格式(回車等),為純字符串,而StyledWriter保留了格式。現在我們通過實例,來將3.1中生成的Json數據打印出來。
- Json::FastWriter fast_writer;
- Json::StyledWriter styled_writer;
- std::cout << fast_writer.write(family)<< std::endl;
- std::cout << styled_writer.write(family)<< std::endl;
輸出結果為:


3.3 Json::Reader
Json::Reader的作用是將字符串解析為Json::Value對象,解析使用Reader對象的parse函數。我們直接提取3.2生成的字符串來做解析,完整源碼見附錄。
- std::string sFamilyJson="{\"isCountry\":true,\"member\":{\"age\":25,\"hobby\":[\"running\",\"basketball\"],\"name\":\"joekuang\",\"wage\":123.450,\"wife\":null},\"name\":\"joe's home\"}";
- Json::Value family;
- Json::Reader reader;
- if(!reader.parse(sFamilyJson,family))
- {
- <span style="white-space:pre"> </span>std::cout<<"parse string to json failed !"<<std::endl;
- <span style="white-space:pre"> </span>return -1;
- }
- int iAge=family["member"]["age"].asInt();
- double dWage=family["member"]["wage"].asDouble();
- std::string sFamily=family["name"].asString();
- std::string sSecondHobby=family["member"]["hobby"][1].asString();
-
-
- std::cout << "joe's age is:"<< iAge<< std::endl;
- std::cout << "joe's wage is:"<<dWage<< std::endl;
- std::cout << "family name is:"<< sFamily<< std::endl;
- std::cout << "joe's second hobby is:"<<sSecondHobby<< std::endl;
- return 0;
- }
解析結果為:


4.注意事項
通過上文,基本可以完成簡單的json生成與解析了。但還有些小問題需要注意。
4.1 異常拋出
在解析的過程中,可能會有異常拋出,比如對Json::Value的下標取值操作,如果數據為非ArrayValue,則會拋出異常。故,建議編碼的過程中,加入TryCatch來做異常捕獲。
4.2 區分字符串與Json數據
比如以下兩個Json字符串,是不能用同樣方式解析的。
- {\"isCountry\":true,\"member\":{\"age\":25,\"hobby\":[\"running\",\"basketball\"],\"name\":\"joekuang\",\"wage\":123.450,\"wife\":null},\"name\":\"joe's home\"}
- {\"isCountry\":true,\"member\":{\"age\":25,\"hobby\":\"[\"running\",\"basketball\"]\",\"name\":\"joekuang\",\"wage\":123.450,\"wife\":null},\"name\":\"joe's home\"}
在hobby這個key對應的數據中,第一個對應的為ArrayValue,第二個對應的是stringValue。對於第一個,我們直接用[]操作就可以把Hobby對應的數據取出來了。而對於第二個,實際上我們需要使用reader進行第二次解析,把字符串解析為ArrayValue。
4.3其它注意事項
暫時沒有,后續有機會再補充。
附錄:
1.Json::Writer例子完整源碼:
- #include <string>
- #include <json/json.h>
-
-
- int main(int argc, char** argv) {
- Json::Value joe;
- joe["name"]=Json::Value("joekuang");
- joe["age"]=Json::Value(25);
- joe["wage"]=Json::Value(123.45);
- joe["wife"]=Json::Value();
- joe["hobby"].append("running");
- joe["hobby"].append("basketball");
- Json::Value family;
- family["name"]=Json::Value("joe's home");
- family["isCountry"]=Json::Value(true);
- family["member"]=joe;
- Json::FastWriter fast_writer;
- Json::StyledWriter styled_writer;
- std::cout << fast_writer.write(family)<< std::endl;
- std::cout << styled_writer.write(family)<< std::endl;
- return 0;
- }
2.Json::Reader例子完整源碼:
- #include <string>
- #include <json/json.h>
-
-
- int main(int argc, char** argv) {
- std::string sFamilyJson="{\"isCountry\":true,\"member\":{\"age\":25,\"hobby\":[\"running\",\"basketball\"],\"name\":\"joekuang\",\"wage\":123.450,\"wife\":null},\"name\":\"joe's home\"}";
- Json::Value family;
- Json::Reader reader;
- if(!reader.parse(sFamilyJson,family))
- {
- std::cout<<"parse string to json failed !"<<std::endl;
- return -1;
- }
- int iAge=family["member"]["age"].asInt();
- double dWage=family["member"]["wage"].asDouble();
- std::string sFamily=family["name"].asString();
- std::string sSecondHobby=family["member"]["hobby"][1].asString();
-
-
-
-
- std::cout << "joe's age is:"<< iAge<< std::endl;
- std::cout << "joe's wage is:"<<dWage<< std::endl;
- std::cout << "family name is:"<< sFamily<< std::endl;
- std::cout << "joe's second hobby is:"<<sSecondHobby<< std::endl;
- return 0;
- }
3.整理后的開源庫文件
http://pan.baidu.com/s/1qWGatzQ
轉載地址:http://blog.csdn.net/kxc0720/article/details/48422595