• 基于开源库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,运行就能看到例子效果。测试用例源码如下:

    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。

    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数据打印出来。

    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生成的字符串来做解析,完整源码见附录。

    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字符串,是不能用同样方式解析的。

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

    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例子完整源码:

    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

  • 相关阅读:
    Android UI 之实现多级列表TreeView
    python小游戏实现代码
    【iOS知识学习】_UITableView简介
    根据指定电话号码得到通讯录上的姓名
    【转载】公钥、私钥、数字签名等知识
    常见的哈希Hash算法 & MD5 & 对称非对称加密 & 海明码
    Mac电脑解压文件unrar用密码问题解决
    一道题目- Find the smallest range that includes at least one number from each of the k lists
    求逆序对数总结 & 归并排序
    【转载】非常棒的算法面试类资源汇总
  • 原文地址:https://www.cnblogs.com/wxmdevelop/p/7803249.html
Copyright © 2020-2023  润新知