基于开源库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



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值