基於開源庫jsoncpp的json字符串解析


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源碼的目錄如下:

[html]  view plain  copy
  1. ├── include  
  2. │   └── json  
  3. │       ├── autolink.h  
  4. │       ├── config.h  
  5. │       ├── features.h  
  6. │       ├── forwards.h  
  7. │       ├── json.h  
  8. │       ├── reader.h  
  9. │       ├── value.h  
  10. │       └── writer.h  
  11. ├── makefile  
  12. └── src  
  13.     ├── json  
  14.     │   ├── json_batchallocator.h  
  15.     │   ├── json_internalarray.inl  
  16.     │   ├── json_internalmap.inl  
  17.     │   ├── json_reader.cpp  
  18.     │   ├── json_value.cpp  
  19.     │   ├── json_valueiterator.inl  
  20.     │   ├── json_writer.cpp  
  21.     │   └── sconscript  
  22.     └── main.cpp  
如上圖所示,include/json目錄下為開源解析庫頭文件目錄,src/json為源碼文件,main.cpp為測試用例文件。通過在根目錄下鍵入make命令,即可生成可執行程序main,運行就能看到例子效果。測試用例源碼如下:

[cpp]  view plain  copy
  1. #include <string>  
  2. #include <json/json.h>  
  3.   
  4. void readJson();  
  5. void writeJson();  
  6.   
  7. int main(int argc, char** argv) {  
  8.     readJson();  
  9.     writeJson();  
  10.     return 0;  
  11. }  
  12.   
  13. void readJson() {  
  14.     using namespace std;  
  15.     std::string strValue = "{\"name\":\"json\",\"array\":[{\"cpp\":\"jsoncpp\"},{\"java\":\"jsoninjava\"},{\"php\":\"support\"}]}";  
  16.   
  17.     Json::Reader reader;  
  18.     Json::Value value;  
  19.   
  20.     if (reader.parse(strValue, value))  
  21.     {  
  22.         std::string out = value["name"].asString();  
  23.         std::cout << out << std::endl;  
  24.         const Json::Value arrayObj = value["array"];  
  25.         for (unsigned int i = 0; i < arrayObj.size(); i++)  
  26.         {  
  27.             if (!arrayObj[i].isMember("cpp"))   
  28.                 continue;  
  29.             out = arrayObj[i]["cpp"].asString();  
  30.             std::cout << out;  
  31.             if (i != (arrayObj.size() - 1))  
  32.                 std::cout << std::endl;  
  33.         }  
  34.     }  
  35. }  
  36.   
  37. void writeJson() {  
  38.     using namespace std;  
  39.   
  40.     Json::Value root;  
  41.     Json::Value arrayObj;  
  42.     Json::Value item;  
  43.   
  44.     item["cpp"] = "jsoncpp";  
  45.     item["java"] = "jsoninjava";  
  46.     item["php"] = "support";  
  47.     arrayObj.append(item);  
  48.   
  49.     root["name"] = "json";  
  50.     root["array"] = arrayObj;  
  51.   
  52.     root.toStyledString();  
  53.     std::string out = root.toStyledString();  
  54.     std::cout << out << std::endl;  
  55. }  
  56. </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。

[cpp]  view plain  copy
  1. Json::Value joe;  
  2. joe["name"]=Json::Value("joekuang");  
  3. joe["age"]=Json::Value(25);  
  4. joe["wage"]=Json::Value(123.45);  
  5. joe["wife"]=Json::Value();  
  6. joe["hobby"].append("running");  
  7. joe["hobby"].append("basketball");  
  8. Json::Value family;  
  9. family["name"]=Json::Value("joe's home");  
  10. family["isCountry"]=Json::Value(true);  
  11. family["member"]=joe;  


3.2 Json::Writer

    在3.1節中,產生的Json數據,要怎么才能顯示出來呢?或者說,怎么轉換成可查看的內容(string)?這個時候,就需要使用到Json::Writer了。Json::Writer是一個虛類,不能直接使用,我們可以通過它的兩個子類Json::FastWriter和Json::StyledWriter來輸出顯示。兩者的區別是,FastWriter顯示的內容去掉了格式(回車等),為純字符串,而StyledWriter保留了格式。現在我們通過實例,來將3.1中生成的Json數據打印出來。

[cpp]  view plain  copy
  1. Json::FastWriter fast_writer;  
  2. Json::StyledWriter styled_writer;  
  3. std::cout << fast_writer.write(family)<< std::endl;  
  4. std::cout << styled_writer.write(family)<< std::endl;  

輸出結果為:



3.3 Json::Reader

    Json::Reader的作用是將字符串解析為Json::Value對象,解析使用Reader對象的parse函數。我們直接提取3.2生成的字符串來做解析,完整源碼見附錄。

[cpp]  view plain  copy
  1. std::string  sFamilyJson="{\"isCountry\":true,\"member\":{\"age\":25,\"hobby\":[\"running\",\"basketball\"],\"name\":\"joekuang\",\"wage\":123.450,\"wife\":null},\"name\":\"joe's home\"}";  
  2. Json::Value family;  
  3. Json::Reader reader;  
  4. if(!reader.parse(sFamilyJson,family))  
  5. {  
  6. <span style="white-space:pre">    </span>std::cout<<"parse string to json failed !"<<std::endl;  
  7. <span style="white-space:pre">    </span>return -1;  
  8. }  
  9. int iAge=family["member"]["age"].asInt();  
  10. double dWage=family["member"]["wage"].asDouble();  
  11. std::string sFamily=family["name"].asString();  
  12. std::string sSecondHobby=family["member"]["hobby"][1].asString();   
  13.   
  14.   
  15. std::cout << "joe's age  is:"<< iAge<< std::endl;  
  16.   std::cout << "joe's wage is:"<<dWage<< std::endl;  
  17. std::cout << "family name is:"<< sFamily<< std::endl;  
  18.   std::cout << "joe's second hobby is:"<<sSecondHobby<< std::endl;  
  19. return 0;  
  20. }  

解析結果為:



4.注意事項

    通過上文,基本可以完成簡單的json生成與解析了。但還有些小問題需要注意。

4.1 異常拋出

    在解析的過程中,可能會有異常拋出,比如對Json::Value的下標取值操作,如果數據為非ArrayValue,則會拋出異常。故,建議編碼的過程中,加入TryCatch來做異常捕獲。

4.2 區分字符串與Json數據

    比如以下兩個Json字符串,是不能用同樣方式解析的。

[cpp]  view plain  copy
  1. {\"isCountry\":true,\"member\":{\"age\":25,\"hobby\":[\"running\",\"basketball\"],\"name\":\"joekuang\",\"wage\":123.450,\"wife\":null},\"name\":\"joe's home\"}  
[cpp]  view plain  copy
  1. {\"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例子完整源碼:

[cpp]  view plain  copy
  1. #include <string>  
  2. #include <json/json.h>  
  3.   
  4.   
  5. int main(int argc, char** argv) {  
  6.     Json::Value joe;  
  7.     joe["name"]=Json::Value("joekuang");  
  8.     joe["age"]=Json::Value(25);  
  9.     joe["wage"]=Json::Value(123.45);  
  10.     joe["wife"]=Json::Value();  
  11.     joe["hobby"].append("running");  
  12.     joe["hobby"].append("basketball");  
  13.     Json::Value family;  
  14.     family["name"]=Json::Value("joe's home");  
  15.     family["isCountry"]=Json::Value(true);  
  16.     family["member"]=joe;     
  17.     Json::FastWriter fast_writer;  
  18.     Json::StyledWriter styled_writer;  
  19.     std::cout << fast_writer.write(family)<< std::endl;  
  20.     std::cout << styled_writer.write(family)<< std::endl;  
  21.     return 0;  
  22. }  

2.Json::Reader例子完整源碼:

[cpp]  view plain  copy
  1. #include <string>  
  2. #include <json/json.h>  
  3.   
  4.   
  5. int main(int argc, char** argv) {  
  6. std::string  sFamilyJson="{\"isCountry\":true,\"member\":{\"age\":25,\"hobby\":[\"running\",\"basketball\"],\"name\":\"joekuang\",\"wage\":123.450,\"wife\":null},\"name\":\"joe's home\"}";  
  7. Json::Value family;  
  8. Json::Reader reader;  
  9. if(!reader.parse(sFamilyJson,family))  
  10. {  
  11. std::cout<<"parse string to json failed !"<<std::endl;  
  12. return -1;  
  13. }  
  14. int iAge=family["member"]["age"].asInt();  
  15. double dWage=family["member"]["wage"].asDouble();  
  16. std::string sFamily=family["name"].asString();  
  17. std::string sSecondHobby=family["member"]["hobby"][1].asString();   
  18.   
  19.   
  20.   
  21.   
  22. std::cout << "joe's age  is:"<< iAge<< std::endl;  
  23.   std::cout << "joe's wage is:"<<dWage<< std::endl;  
  24. std::cout << "family name is:"<< sFamily<< std::endl;  
  25.   std::cout << "joe's second hobby is:"<<sSecondHobby<< std::endl;  
  26. return 0;  
  27. }  

3.整理后的開源庫文件

http://pan.baidu.com/s/1qWGatzQ


轉載地址:http://blog.csdn.net/kxc0720/article/details/48422595


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM