C++JSON解析器

3 篇文章 0 订阅
2 篇文章 0 订阅

2012年,在公司项目刚接触到要使用JSON时,几个前端项目都是用MFC开发的,没找到合适的JSON解析库。

索性自己开发一个简洁实用移植性强的json解析工具,主要达到以下目标:

1. 能够解析JSON字符串

2. 能够生成JSON字符串

3. 在项目中不是一个纯粹的JSON工具,可作为数据结构来使用

4. 内存自动释放

5. 路径表达式获取或设置 json结构中的某个字段

6. 能便捷的增加json字段


工具只包含两个文件:

gxx_base.h, gxx_base.cpp

点击下载源代码
如代码中问题和bug,欢迎指正。


请大家见谅使用gxx(我姓名的缩写)作为文件的前缀,这样做的原因是:个人原创工具类,也是为了和工程中其他文件做区分避免混淆。

为什么名字为gxx_base而不是gxx_json呢?
笔者曾经问过自己同样的问题,答案是:它不是纯粹的json解析器,它是一个很实用的数据结构容器。

实际上,从2012年至今, 在公司很多项目中笔者都使用到gxx_base里提供的工具, 经过5年的维护修改,现在已经很稳定了,想在分享给有需要的猿同胞。

下面开始进入正题:


引入到工程中,会报如下错误:

error C3861: “GXX_TRACE”: 即使使用参数相关的查找,也未找到标识符

解决方法:   打开 gxx_base.h, 然后重新定义自己的 GXX_PRINT宏, GXX_PRINT宏用来输出日志信息的, 请实现自定义的日志信息输出


如何解析 JSON字符串

示例1:解析下面这串 json,读取abc数组,读取key1对应的值

{"abc":[1,2,3,{"key1":456,"key2":[4,5,6]}]}

#include "gxx_base.h"
int _tmain(int argc, _TCHAR* argv[])
{
	// gxx_base中所有对象的创建都需要用create方法
	GxxDictionaryPtr jsonParse = GxxDictionary::create();
	try{
		jsonParse->initWithJsonText("{\"abc\":[1,2,3,{\"key1\":456,\"key2\":[4,5,6]}]}");
		
		// 取出abc
		GxxArrayPtr abcVal = jsonParse->arrayValueForKey("abc");
		if (abcVal)
			printf("abc=%s\n", abcVal->toJsonText(false).c_str());

		// 取出key1
		// 第一种方式
		GxxDictionaryPtr abc3 = abcVal->dictionaryValueAtIndex(3);
		if (abc3) {
			std::string key1 = abc3->stringValueForKey("key1");
			printf("key1=%s\n", key1.c_str());
		}
		// 第二中方式, 使用路劲表达式,key值不存在返回空字符串,
		// 路径表达式请参考 valueForKeyPath注释
		std::string key1 = jsonParse->stringValueForKeyPath("abc[3].key1");
		printf("路径表达式,key1=%s\n", key1.c_str());
	}
	catch(GxxException& e) {
		printf("json 解析异常\n");
	}
	getchar();
	return 0;
}


示例2:解析下面的json串,读取学号为 002学生的信息。

{
    "schoolName": "清华大学",
    "students": [
        {
            "id": "001",
            "name": "张三",
            "age": "20"
        },
        {
            "id": "002",
            "name": "李四",
            "age": "23"
        },
        {
            "id": "003",
            "name": "王五",
            "age": "22"
        }
    ]
}

#include "gxx_base.h"
int _tmain(int argc, _TCHAR* argv[])
{
	GxxDictionaryPtr jsonParse = GxxDictionary::create();
	try{
		jsonParse->initWithJsonText("{\"schoolName\":\"清华大学\", \"students\":[{\"id\":\"001\",\"name\":\"张三\",\"age\":\"20\"},{\"id\":\"002\",\"name\":\"李四\",\"age\":\"23\"},{\"id\":\"003\",\"name\":\"王五\",\"age\":\"22\"}]}");
		
		// 第一种方式, 取出students
		GxxArrayPtr students = jsonParse->arrayValueForKey("students");
		if (students) {
			for (int i = 0; i < students->count(); i++) {
				GxxDictionaryPtr student = students->dictionaryValueAtIndex(i);
				if (student->stringValueForKey("id") == "002") {
					printf("第一种方式,找到002的信息:%s\n", student->toJsonText().c_str());
					break;
				}
			}
		}
		// 第二种方式,表达式获取
		// 取出姓名可用 "students[@id=002].name"
		GxxDictionaryPtr student = jsonParse->dictionaryValueForKeyPath("students[@id=002]");
		if (student) {
			printf("第二种种方式,找到002的信息:%s\n", student->toJsonText().c_str());
		}

		// 第三种方式,重建一个新的字典, 使用场景:当需要频繁查找时
		// studentsDir中的每个学生信息和students中的每个学生信息的内存不发生变化
		GxxDictionaryPtr studentsDir = students->makeDictionaryByKey("id");
		if (studentsDir) {
			GxxDictionaryPtr student = studentsDir->dictionaryValueForKey("002");
			if (student) {
				printf("第三种方式,找到002的信息:%s\n", student->toJsonText().c_str());
				// 002的年龄有误,要从23岁改成22岁
				student->setValueForKey(22, "age");

				// 亲可以尝试,在 用第一种或第二种方式,看看002的年龄是否是 22岁.
				printf("002更改后的年龄:%d", jsonParse->intValueForKeyPath("students[@id=002].age"));
			}
		}
	}
	catch(GxxException& e) {
		printf("json 解析异常\n");
	}
	getchar();
	return 0;
}


#ifndef __GXX_JSON__H__
#define __GXX_JSON__H__

#include 
#include 
#include 

#ifndef G2X_CLASSES
#define G2X_CLASSES
#endif

#ifdef WINVER
#define GXX_PRINT(x) {do{GXX_TRACE(x);} while (0);}
#else 
#define GXX_PRINT(x) {do{GXX_TRACE("%s",x);} while (0);}
#endif

#define gxx_int_t(x) GxxValue::create((long)(x))
#define gxx_long_t(x) GxxValue::create((long)(x))
#define gxx_ulong_t(x) GxxValue::create((unsigned long)(x))
#define gxx_int64_t(x) GxxValue::create((long long)(x))
#define gxx_float_t(x) GxxValue::create((double)(x))
#define gxx_bool_t(x) GxxValue::create((long)(x?1:0))

class GxxException {
public:
	GxxException(const char* errorInfo) {
		G2X_CLASSES(0);
		error = errorInfo;
	}
	const char* errorInfo() const {
		return error.c_str();
	}
private:
	std::string error;
};

template
class GxxAutoPtr
{
public:
	typedef _Ty element_type;

	/*explicit*/ GxxAutoPtr(_Ty* _Ptr = 0)
		: _Myptr(_Ptr)
	{
		if (_Ptr) _Myptr->retain();
	}
	GxxAutoPtr(const GxxAutoPtr<_ty>& _Right)
	{
		if (_Myptr == _Right.get()){
			if (_Myptr) _Myptr->retain();
		}else{
			_Myptr = _Right.get();
			if (_Myptr) _Myptr->retain();
		}
	}
	template
		GxxAutoPtr(GxxAutoPtr<_other>& _Right)
	{
		if (_Myptr == _Right.get()){
			if (_Myptr) _Myptr->retain();
		}else{
			_Myptr = _Right.get();
			if (_Myptr) _Myptr->retain();
		}
	}
	~GxxAutoPtr()
	{
		if (_Myptr) _Myptr->release();
	}
	_Ty& operator*() const
	{	// return designated value
		return (*_Myptr);
	}

	_Ty *operator->() const
	{	// return pointer to class object
		return (&**this);
	}

	_Ty* get() const
	{
		return _Myptr;
	}

	template
		operator GxxAutoPtr<_other>()
	{
		return (GxxAutoPtr<_other>(*this));
	}
	operator _Ty* () const
	{
		return _Myptr;
	}

	GxxAutoPtr<_ty>& operator = (_Ty* _Ptr)
	{
		if (_Myptr == _Ptr)
			return *this;
		if (_Myptr) _Myptr->release();
		_Myptr = _Ptr;
		if (_Myptr) _Myptr->retain();

		return *this;
	}

	GxxAutoPtr<_ty>& operator = (GxxAutoPtr<_ty>& _Right)
	{
		if (_Myptr == _Right.get())
			return *this;
		if (_Myptr) _Myptr->release();
		_Myptr = _Right.get();
		if (_Myptr) _Myptr->retain();

		return *this;
	}

private:
	_Ty* _Myptr;
};

class G2X_CLASSES GxxKey {
public:
	GxxKey() {
		_key = 0;
	}
	~GxxKey() {
		if (_key) 
			delete _key;
		_key = 0;
	}
	GxxKey(const char* _right) {
		_key = 0;
		reset(_right);
	}
	GxxKey(const GxxKey& _right) {
		_key = 0;
		reset( _right );
	}
	const char* resize(unsigned int size) {
		if (_key)
			delete []_key;
		_key = new char[size+1];
		memset(_key, 0, size + 1);
		return _key;
	}
	char& operator [](int i) {
		return *(_key+i);
	}
	
	operator const char* () const{
		return _key;
	}
	
private:
	void reset(const char* _right) {
		if (_key)
			delete []_key;
		int len = (int)strlen(_right);
		_key = new char[len+1];
		memcpy(_key, _right, len + 1);
	}

private:
	char *_key;
};

inline
bool operator == (const GxxKey& _left, const GxxKey& _right) {
	return strcmp(_left, _right) == 0;
}
inline
bool operator != (const GxxKey& _left, const GxxKey& _right) {
	return strcmp(_left, _right) != 0;
}
inline
bool operator < (const GxxKey& _left, const GxxKey& _right) {
	return strcmp(_left, _right) < 0;
}
inline
bool operator > (const GxxKey& _left, const GxxKey& _right) {
	return strcmp(_left, _right) > 0;
}
inline
bool operator <= (const GxxKey& _left, const GxxKey& _right) {
	return strcmp(_left, _right) <= 0;
}
inline
bool operator >= (const GxxKey& _left, const GxxKey& _right) {
	return strcmp(_left, _right) >= 0;
}

typedef std::string CGxxValueString;

#define GXX_CREATE_FUNC(classTy) \
protected:\
	classTy(){}\
public:\
	static GxxAutoPtr create()\
	{\
		classTy* object = (new classTy);\
		if (!object->init())\
		{\
			object->release();\
			return (GxxAutoPtr((classTy*)0));\
		}\
		return (GxxAutoPtr(object));\
	}

class G2X_CLASSES GxxObject;
class G2X_CLASSES GxxDictionary;
class G2X_CLASSES GxxArray;
class G2X_CLASSES GxxString;
class G2X_CLASSES GxxValue;
class G2X_CLASSES GxxValueMap;

typedef GxxAutoPtr GxxObjectPtr;
typedef GxxAutoPtr GxxDictionaryPtr;
typedef GxxAutoPtr GxxArrayPtr;
typedef GxxAutoPtr GxxStringPtr;
typedef GxxAutoPtr GxxValuePtr;
typedef GxxAutoPtr GxxValueMapPtr;

class G2X_CLASSES GxxObject
{
protected:
	GxxObject();

public:
	virtual ~GxxObject();

	virtual void print() {};
	
	void retain();
	void release();

protected:
	virtual bool init() { return true; }
	virtual void objectReleased() {}
	
public:
	virtual std::string describe(bool isUtf8=false) { return std::string(""); }
	void _print(const char* x);
	void _println(const char* x);

private:
	int retainCount;
};



class G2X_CLASSES GxxDictionary : public GxxObject
{
	GXX_CREATE_FUNC(GxxDictionary);
protected:
	virtual bool init();
	virtual void objectReleased();
public:
	/* 用json格式的字符串初始化字典 */
	bool initWithJsonText(const char* jsonText, bool isUtf8=false);
	std::string toJsonText(bool isUtf8=false);
	virtual std::string describe(bool isUtf8=false);

	// 返回把字典转为json格式的字符串
	std::string describe_d(int depth, bool bFormat,bool isUtf8);
	GxxArrayPtr names();
	GxxArrayPtr sortedNames();

	int count();
	virtual void print();
	bool isKeyExist(const char* key);
	GxxValue* valueForKey(const char* key);

	/* 不区分key大小写的方式读取对应的值(本方法效率很低) */
	GxxValue* valueForKeyNoCase(const char* key);
	GxxValue* operator[](const char* key);

	
	int intValueForKey(const char* key, int defaultValue = 0);
	bool boolValueForKey(const char* key, bool defaultValue = false);
	float floatValueForKey(const char* key, float defaultValue = 0);
	std::string stringValueForKey(const char* key);
	GxxArray* arrayValueForKey(const char* key);
	GxxDictionary* dictionaryValueForKey(const char* key);
	GxxObject* otherValueForKey(const char* key);

	void setValueForKey(GxxValuePtr& pValue, const char* key);
	void setValueFromOtherKey(GxxDictionaryPtr& otherDir, const char* key);
	void setValueFromOtherKey(GxxDictionaryPtr& otherDir, const char* key, const char* newKey);
	void setValueForKey(int nValue, const char* key);
	void setValueForKey(const char* szValue, const char* key);
	void setValueForKey(const std::string& strValue, const char* key);
	void setValueForKey(float fValue, const char* key);
	void setValueForKey(GxxArrayPtr& arrValue, const char* key);
	void setValueForKey(GxxDictionaryPtr& dirValue, const char* key);

	/*
	通过keypath 快速查找json中某个key下的值
	例如如下举例:
	GxxDictionaryPtr dr = GxxDictionary::create();
	dr->initWithJsonText("{\"abc\":[1,2,3,{\"key1\":456,\"key2\":[4,5,6]}]}");

	// 取出abc对应的value
	GxxValuePtr pVal1 = dr->valueForKeyPath("abc");
	if (pVal1) MY_TRACE(pVal1->describe().c_str());

	// abc的value是一个数组,取出abc数组中的第二个元素, [下标从0开始]
	GxxValuePtr pVal2 = dr->valueForKeyPath("abc[1]");
	if (pVal2) MY_TRACE(pVal2->describe().c_str());

	// abc的value是一个数组,取出abc数组中的第四个元素, [下标从0开始]
	GxxValuePtr pVal3 = dr->valueForKeyPath("abc[3]");
	if (pVal3) MY_TRACE(pVal3->describe().c_str());

	// abc的value是一个数组,它的第四个元素又是一个字典, 取出字典里 key2对应的value
	GxxValuePtr pVal4 = dr->valueForKeyPath("abc[3].key2");
	if (pVal4) MY_TRACE(pVal4->describe().c_str());

	// key2对应的value是一个数组,取出它的第一个元素
	GxxValuePtr pVal5 = dr->valueForKeyPath("abc[3].key2[0]");
	if (pVal5) MY_TRACE(pVal5->describe().c_str());
	*/
	GxxValue* valueForKeyPath(const char* keyPath);

	/*
	在指定的路径上设置value,这里的keyPath和 valueForKeyPath的keyPath参数有所不同,
	前者的keyPath中不能包含[]下标.
	GxxDictionaryPtr dr = GxxDictionary::create();
	dr->initWithJsonText("{\"config\":{\"key1\":456,\"key2\":[4,5,6]}}");

	// 在config下添加一个为key3的value, config下没有key3,setValueForKeyPath会自动创建key3
	dr->setValueForKeyPath(GxxValue::create("my key is key3"),"config.key3");
	// 重新设置key3的值, key3已存在,它的value被覆盖
	dr->setValueForKeyPath(GxxValue::create("your key is key3"),"config.key3");
	*/
	void setValueForKeyPath(GxxValuePtr& pValue, const char* keyPath);

	int intValueForKeyPath(const char* keyPath, int defaultValue = 0);
	bool boolValueForKeyPath(const char* keyPath, bool defaultValue = false);
	float floatValueForKeyPath(const char* keyPath, float defaultValue = 0);
	std::string stringValueForKeyPath(const char* keyPath);
	GxxArray* arrayValueForKeyPath(const char* keyPath);
	GxxDictionary* dictionaryValueForKeyPath(const char* keyPath);
	GxxObject* otherValueForKeyPath(const char* keyPath);

	void removeKey(const char* key);
private:
	

private:
	GxxValueMapPtr keyValues;
};

class G2X_CLASSES GxxArray : public GxxObject
{
	GXX_CREATE_FUNC(GxxArray);
protected:
	virtual void objectReleased();

public:
	static GxxAutoPtr createWithObj(GxxValuePtr valPtr1,GxxValuePtr valPtr2=NULL,GxxValuePtr valPtr3=NULL);
	static GxxAutoPtr createWithObj(GxxDictionaryPtr dicPtr1,GxxDictionaryPtr dicPtr2=NULL,GxxDictionaryPtr dicPtr3=NULL);
	bool initWithJsonText(const char* jsonText, bool isUtf8=false);
	std::string toJsonText(bool isUtf8);

	virtual std::string describe(bool isUtf8=false);
	virtual void print();

	// 返回把数组转为json格式的字符串
	std::string describe_d(int depth, bool bFormat, bool isUtf8=false);

	/**
	 * 插入value在具体的某个位置
	 * @param pValue : 
	 * @param iIndex : 插入的位置, =0表示插入在最前面,-1表示插入在最后面(等同于addValue)
	 * @see addValue
	 * @return void
	 */
	void insertValue(const GxxValuePtr& pValue, int iIndex);
	/**
	 * 添加value在数组的最后面
	 * @param pValue :
	 * @return void
	 */
	void addValue(const GxxValuePtr& pValue);
	void addValue(const GxxArrayPtr& arrVal);
	void addValue(const GxxDictionaryPtr& dirVal);
	void addValuesFrom(const GxxArrayPtr& otherArray);
	void setValue(GxxValuePtr& pValue, int iIndex);
	void removeValue(int iIndex);
	void removeAllValues();
	GxxValue* valueAtIndex(int iIndex);
	int intValueAtIndex(int iIndex, int defaultValue = 0);
	bool boolValueAtIndex(int iIndex, bool defaultValue = false);
	std::string stringValueAtIndex(int iIndex);
	GxxArray* arrayValueAtIndex(int iIndex);
	GxxDictionary* dictionaryValueAtIndex(int iIndex);
	GxxObject* otherValueAtIndex(int iIndex);
	/**
	 * 使用数组中的字典元素的某个key的value做为新字典的key,新字典的key的value为 数组中的字典对象
	 * 例如: [{"A":"001","B":10000},{"A":"002","B":12000},{"A":"003","B":14000}], 这是一个公司3个员工的 员工编号和员工薪水记录数组
	 *   将它制造成一个字典,转为换: {"001":{"A":"001","B":10000},"002":{"A":"002","B":12000},"003":{"A":"003","B":14000}}
	 *   这样,读取某个员信息时,可以直接使用 员工编号,快速读取 员工信息了
	 *	 当key-value重复时,后面的值覆盖前面的值
	 * @param useValueOfKey : 使用字典元素的某个key
	 * @return ...
	 */
	GxxDictionaryPtr makeDictionaryByKey(const char* useValueOfKey);
	int count();
	
private:
	typedef std::vector ArrayValue;
	ArrayValue arrayValues;
};

class G2X_CLASSES GxxString : public GxxObject
{
	GXX_CREATE_FUNC(GxxString);
public:
	static GxxStringPtr create(const char* str);
	virtual void print();
	virtual std::string describe(bool isUtf8=false) { return _string; }

	const char* getString();

private:
	std::string _string;
};



class G2X_CLASSES GxxValue : public GxxObject
{
	GXX_CREATE_FUNC(GxxValue);
public:
	static GxxValuePtr create(const GxxDictionaryPtr& ptrValue);
	static GxxValuePtr create(const GxxArrayPtr& ptrValue);
	static GxxValuePtr create(GxxStringPtr& ptrValue);
	static GxxValuePtr create(const char* pValue);
	static GxxValuePtr create(const GxxObjectPtr& ptrOtherValue);
	static GxxValuePtr create(unsigned long uValue);
	static GxxValuePtr create(long intValue);
	static GxxValuePtr create(long long int64Value);
	static GxxValuePtr create(double floatValue);


	virtual bool init(){
		_init();
		return true;
	}
	virtual void print();
	virtual std::string describe();

	GxxDictionary* getDictionary(){return ptrDictionaryData;}
	GxxArray* getArray(){return ptrArrayData;}
	GxxString* getString(){return ptrStringData;}
	GxxObject* getOther(){return ptrOtherData;}
	const char* stringValue();
	int intValue();
	float floatValue();
	double doubleValue();

protected:
	virtual void objectReleased();

private:
	void _init();
private:
	 
	GxxDictionaryPtr ptrDictionaryData;
	GxxArrayPtr ptrArrayData;
	GxxStringPtr ptrStringData;
	GxxObjectPtr ptrOtherData;
};

class G2X_CLASSES GxxValueMap : public GxxObject
{
	GXX_CREATE_FUNC(GxxValueMap);
public:
	struct Pair
	{
		GxxKey key;
		GxxValuePtr value;
	};
	typedef std::map TyMap;
	typedef TyMap::iterator Iterator;

	int count();
	void PutValue(const GxxKey& _key, const GxxValuePtr& _value);
	GxxValuePtr ValueForKey(const GxxKey& _key);
	void RemoveKey(const GxxKey& _key);

	Iterator FirstValue();
	bool IsLastValue(Iterator& it);
	void NextValue(Iterator& pos);

protected:
	virtual bool init();
	virtual void objectReleased();

private:
	TyMap* __pMap;
};

typedef void (GxxObject::*GxxNotifyHandleFunc)(void);
typedef void (GxxObject::*GxxNotifyHandleFuncWithData)(GxxDictionaryPtr dataPtr);

struct GxxNotification
{
	GxxObject* observerPtr;
	GxxNotifyHandleFunc func;
	GxxNotifyHandleFuncWithData funcWithData;
};

class G2X_CLASSES GxxNotifyCenter : public GxxObject
{
	GXX_CREATE_FUNC(GxxNotifyCenter);
public:;
	   typedef std::vector ArrayNofitication;
	   typedef ArrayNofitication::iterator ArrayIterator;

	   typedef std::map MapNotifications;
	   typedef MapNotifications::iterator MapIterator;

public:
	static GxxNotifyCenter* defaultCenter();

	void AddObserver(GxxObject* pObserverObj, const char* keyNotify, GxxNotifyHandleFunc handleFunc);
	void AddObserver(GxxObject* pObserverObj, const char* keyNotify, GxxNotifyHandleFuncWithData handleFunc);

	void RemoveObserver(GxxObject* pObserverObj, const char* keyNotify = 0);

	void PostNotify(const char* keyNotify, GxxDictionary* data = 0);

private:
	void _addObserver(const GxxNotification& noti, const char* keyNotify);
	GxxNotification* _findObserver(GxxObject* pObserverObj, const char* keyNotify);

private:
	MapNotifications mapNotifications;


};


#endif


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值