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. void readJson();
  4. void writeJson();
  5. int main(int argc, char** argv) {
  6. readJson();
  7. writeJson();
  8. return 0;
  9. }
  10. void readJson() {
  11. using namespace std;
  12. std::string strValue = "{\"name\":\"json\",\"array\":[{\"cpp\":\"jsoncpp\"},{\"java\":\"jsoninjava\"},{\"php\":\"support\"}]}";
  13. Json::Reader reader;
  14. Json::Value value;
  15. if (reader.parse(strValue, value))
  16. {
  17. std::string out = value["name"].asString();
  18. std::cout << out << std::endl;
  19. const Json::Value arrayObj = value["array"];
  20. for (unsigned int i = 0; i < arrayObj.size(); i++)
  21. {
  22. if (!arrayObj[i].isMember("cpp"))
  23. continue;
  24. out = arrayObj[i]["cpp"].asString();
  25. std::cout << out;
  26. if (i != (arrayObj.size() - 1))
  27. std::cout << std::endl;
  28. }
  29. }
  30. }
  31. void writeJson() {
  32. using namespace std;
  33. Json::Value root;
  34. Json::Value arrayObj;
  35. Json::Value item;
  36. item["cpp"] = "jsoncpp";
  37. item["java"] = "jsoninjava";
  38. item["php"] = "support";
  39. arrayObj.append(item);
  40. root["name"] = "json";
  41. root["array"] = arrayObj;
  42. root.toStyledString();
  43. std::string out = root.toStyledString();
  44. std::cout << out << std::endl;
  45. }
  46. </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. std::cout << "joe's age  is:"<< iAge<< std::endl;
  14. std::cout << "joe's wage is:"<<dWage<< std::endl;
  15. std::cout << "family name is:"<< sFamily<< std::endl;
  16. std::cout << "joe's second hobby is:"<<sSecondHobby<< std::endl;
  17. return 0;
  18. }

解析结果为:

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. int main(int argc, char** argv) {
  4. Json::Value joe;
  5. joe["name"]=Json::Value("joekuang");
  6. joe["age"]=Json::Value(25);
  7. joe["wage"]=Json::Value(123.45);
  8. joe["wife"]=Json::Value();
  9. joe["hobby"].append("running");
  10. joe["hobby"].append("basketball");
  11. Json::Value family;
  12. family["name"]=Json::Value("joe's home");
  13. family["isCountry"]=Json::Value(true);
  14. family["member"]=joe;
  15. Json::FastWriter fast_writer;
  16. Json::StyledWriter styled_writer;
  17. std::cout << fast_writer.write(family)<< std::endl;
  18. std::cout << styled_writer.write(family)<< std::endl;
  19. return 0;
  20. }

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

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

3.整理后的开源库文件

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

转载地址:http://blog.csdn.net/kxc0720/article/details/48422595

基于开源库jsoncpp的json字符串解析的更多相关文章

  1. Java基础-处理json字符串解析案例

    Java基础-处理json字符串解析案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 作为一名开发人员,想必大家或多或少都有接触到XML文件,XML全称为“extensible ...

  2. jsoncpp构造json字符串和json数组

    jsoncpp构造json字符串和json数组 参考文章:Jsoncpp的简单使用 下载json文件夹放在c++项目的include目录下,在CMakeLists中include进去,然后就可以在代码 ...

  3. 前台的js对象数组传到后台处理。在前台把js对象数组转化为json字符串,在后台把json字符串解析为List<>

    前台的js对象数组传到后台处理.在前台把js对象数组转化为json字符串,在后台把json字符串解析为List<>

  4. VBScript把json字符串解析成json对象的2个方法

    这篇文章主要介绍了VBScript把json字符串解析成json对象的2个方法,本文通过MSScriptControl.ScriptControl和jscript实现,需要的朋友可以参考下 asp/v ...

  5. 复杂JSON字符串解析,可以少走弯路

    发现一个好文章:装载至http://www.verejava.com/?id=17174254038220 package com.json5;    import org.json.JSONArra ...

  6. 第三方库 jsoncpp 读写json

    一.摘要 JSON 的全称为:JavaScript Object Notation,顾名思义,JSON 是用于标记 Javascript 对象的,JSON 官方的解释为:JSON 是一种轻量级的数据传 ...

  7. JSON字符串解析成JSON数据格式

    在JS中将JSON的字符串解析成JSON数据格式,一般有两种方式: 1.一种为使用eval()函数. 2. 使用Function对象来进行返回解析. 使用eval函数来解析,并且使用jquery的ea ...

  8. JSON字符串解析

    有时保存在数据库的数据是一串json字符串,需要进行读取的时候就需要解析操作. 简单介绍两种: 1.net.sf.json.* 2.com.alibaba.fastjson.* 需要的包自行下载. 第 ...

  9. Json字符串解析原理、超大json对象的解析

    概述 附上完整的代码:https://pan.baidu.com/s/1dEDmGz3(入口类是Json)JSON:JavaScript 对象表示法(JavaScript Object Notatio ...

随机推荐

  1. 禁用chrome默认打印框直接打印

    在做web打印的时候 重要弹出一个对话框选择打印机等等, 比较影响操作, 经过一番谷歌终于找到了解决方案 在桌面的chrome 图标 右键 打开属性对话框 在目标 添加  --kiosk-printi ...

  2. oracle 实现多字段匹配一个关键字查询语句

    oracle 实现多字段匹配一个关键字查询语句:有两种方法(经测试,10g中不能用,11g才行): 第一种. select * from table where ('字段名1' ||'字段名2' || ...

  3. 微软MVP Round Table

    2017年7月7日,微软VS圈子的老大兼女神Julia(潘正磊)以及Peter Hu等人,和若干MVP一起在进行了一次Round Table讨论. 讨论过程中主要针对VS和TFS/VSTS相关的功能. ...

  4. 关于canvas绘制大转盘并旋转

    O(∩_∩)O包子不才,最近磕磕巴巴写了一个大转盘的效果.现在想说一下整个的思路部分,要是有设么不对的还请多多指教,期待共同成为优秀的前端~~大转盘整个思路: 绘制整个转盘 编写一个随机数,用来当接口 ...

  5. IIS7发布wcf服务遇到的问题

    如果没有上图所列出的asp.net 40,请在cmd中运行:C:\Windows\Microsoft.NET\Framework\V4.0.30319\aspnet_regiis -i 注:C:\Wi ...

  6. About AcitveDirectory EventLog

    参考微软文档整理的常用EVENTID: Account Logon Account Management Policy Change Event ID Event message 分類 類別 4670 ...

  7. ios cocos2d 使用 sneakyInput 插件

    昨晚看了篇使用sneakyInput插件实现模拟手柄的代码,不过我加上后出现了很多问题.最后只看如何实现,没有自己动手去操作.今天终于吧问题都解决了.记录下来.也供别人参考. 首先要先加入libz.d ...

  8. python学习之路-第七天-python面向对象编程简介

    面向对象编程 在python中,同样是类和对象作为重要的组成部分. 而且在python中基本数据类型如int都是有封装类的,都有自己的方法,应该是和java里面的Integer类似吧 类包括域和方法: ...

  9. Django总结及Form组件

    一.model常用操作 1.13个API查询:all,filter,get ,values,values_list,distinct,order_by ,reverse , exclude(排除),c ...

  10. restful API(转自阮一峰)

    RESTful API 设计指南   网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......). 因此,必须有一种统一的机制,方便不 ...