C++JSON解析器

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章