基于开源库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源码的目录如下:
- ├── 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
基于开源库jsoncpp的json字符串解析的更多相关文章
- Java基础-处理json字符串解析案例
Java基础-处理json字符串解析案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 作为一名开发人员,想必大家或多或少都有接触到XML文件,XML全称为“extensible ...
- jsoncpp构造json字符串和json数组
jsoncpp构造json字符串和json数组 参考文章:Jsoncpp的简单使用 下载json文件夹放在c++项目的include目录下,在CMakeLists中include进去,然后就可以在代码 ...
- 前台的js对象数组传到后台处理。在前台把js对象数组转化为json字符串,在后台把json字符串解析为List<>
前台的js对象数组传到后台处理.在前台把js对象数组转化为json字符串,在后台把json字符串解析为List<>
- VBScript把json字符串解析成json对象的2个方法
这篇文章主要介绍了VBScript把json字符串解析成json对象的2个方法,本文通过MSScriptControl.ScriptControl和jscript实现,需要的朋友可以参考下 asp/v ...
- 复杂JSON字符串解析,可以少走弯路
发现一个好文章:装载至http://www.verejava.com/?id=17174254038220 package com.json5; import org.json.JSONArra ...
- 第三方库 jsoncpp 读写json
一.摘要 JSON 的全称为:JavaScript Object Notation,顾名思义,JSON 是用于标记 Javascript 对象的,JSON 官方的解释为:JSON 是一种轻量级的数据传 ...
- JSON字符串解析成JSON数据格式
在JS中将JSON的字符串解析成JSON数据格式,一般有两种方式: 1.一种为使用eval()函数. 2. 使用Function对象来进行返回解析. 使用eval函数来解析,并且使用jquery的ea ...
- JSON字符串解析
有时保存在数据库的数据是一串json字符串,需要进行读取的时候就需要解析操作. 简单介绍两种: 1.net.sf.json.* 2.com.alibaba.fastjson.* 需要的包自行下载. 第 ...
- Json字符串解析原理、超大json对象的解析
概述 附上完整的代码:https://pan.baidu.com/s/1dEDmGz3(入口类是Json)JSON:JavaScript 对象表示法(JavaScript Object Notatio ...
随机推荐
- LeetCode 学习
1.整数反转 题目:给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 思路:把最后的一位提取出来,放到新的容器前面,反复进行上面的操作,同时也要判断是否会导致溢出 class ...
- 巨蟒python全栈开发flask7 语音识别升级版&&mongoDB
1.web简陋版玩具 首先,复制上一节课的内容,将其中的语音文件删除掉, 放入三个文件,然后,我们需要在app写入下面的内容 下图是需要修改的地方: Recorder_ok.js是一个web录音的工具 ...
- IO流入门-第九章-BufferedReader_BufferedWriter复制
利用BufferedReader和BufferedWriter进行复制粘贴 import java.io.*; public class BufferedReader_BufferedWriterCo ...
- 使用Docker创建Elasticsearch服务
一.Docker是什么? Docker是一个开源工具,能将一个WEB应用封装在一个轻量级,便携且独立的容器里,然后可以运行在几乎任何服务环境下.Docker的容器能使应用跑在任何服务器上并且表现一致. ...
- 标准编译安装(cmake make)
为什么要编译安装?因为根据需求可以个性化定制功能. 关键是阅读cmakelist,看都有哪些依赖,都有哪些选项可用,哪些选项是自己可以配置的. 一般流程: mkdir build cd build c ...
- Linux使用SecureCRT上传下载
操作远程 Linux 系统,很多时候选用 SecureCRT 软件,在 SecureCRT 环境下,使用 lrzsz 工具可以很方便的完成文件的上传下载. 这里使用的 Ubuntu Linux 安装: ...
- ViewConfiguration 和 ViewConfigurationCompat
Contains methods to standard constants used in the UI for timeouts, sizes, and distances. 一.几个常用的方法 ...
- MTK平台环境搭建---Ubuntu Linux 下执行sudo apt-get install提示“现在没有可用的软件包……
问题描述: sudo apt-get install openssh-server 正在读取软件包列表... 完成正在分析软件包的依赖关系树 Reading state information... ...
- 【算法题12 解码方法decode way】
1.来源LeetCode91 一条包含字母 A-Z 的消息通过以下方式进行了编码: 'A' -> 1 'B' -> 2 ... 'Z' -> 26 给定一个只包含数字的非空字符串,请 ...
- Python基础学习之 函数
阅读目录 第一篇: 函数初识 第二篇: 函数命名空间 作用域 闭包 第三篇: 装饰器 第四篇: 装饰器 面试题错误点 第五篇: 迭代器生成器 第六篇: 生成器进阶 第七篇: 递归 第八篇 ...