栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言实现JSON字符串解码与编码(三)源代码

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言实现JSON字符串解码与编码(三)源代码

申请/释放空间

因为JSON对象与字符串需要在堆上申请/释放空间,故定义2个函数指针变量来存在函数地址。

static void* (*JSON_malloc)(size_t _Size);//申请空间的函数指针
static void (*JSON_free)(void* _Block);//释放空间的函数指针

通过调用JSONInit()函数来初始化这两个函数指针

void JSONInit(void* (*JSONmalloc)(size_t _Size), void (*JSONfree)(void* _Block))
{
	JSON_malloc = JSONmalloc;
	JSON_free = JSONfree;
}
解码

因为功能函数过多,这里仅介绍几个重要的函数。

解码JSON

传入需要解码的JSON字符串,与对应的数据模型,即可解码。

  1. 检查参数
  2. 检查申请/释放空间函数指针是否已经赋值
  3. 根对象是否为空
  4. 调用解析对象功能函数开始解析JSON字符串
void* DecodeJSON(char* jsonStr, PJSON_MODEL_t model, unsigned int modelCount, char removeInvalidChars)
{
	void* root = NULL;

	
	JSONErrorCode = JSON_SUCCESS;

	
	if (jsonStr == NULL || model == NULL || modelCount == 0)
	{
		JSONErrorCode = PARAM_IS_EMPTY;//参数为空失败
		return NULL;
	}

	if (JSON_malloc == NULL || JSON_free == NULL)
	{
		JSONErrorCode = JSON_NOT_INIT;//未初始化
		return NULL;
	}

	if (removeInvalidChars)
	{
		
		strTrim(jsonStr);
	}

#if (JSON_DEBUG == 1)
	printf("解码的JSON字符串长度为:%zun", strlen(jsonStr));
	printf("解码的JSON字符串为:%sn", jsonStr);
#endif // (JSON_DEBUG == 1)

	
	if (*(jsonStr + 1) == '}')
	{
		JSONErrorCode = DECODE_ROOT_OBJECT_NULL;//根对象是不是空对象
		return NULL;
	}

	
	root = DecodeObject(jsonStr, model, modelCount);

	return root;
}
解析对象
  1. 检查函数参数
  2. 检查对象为空
  3. 获取根对象占用的字节大小
  4. 为对象申请空间
  5. 变量对象的数据模型,依次解析JSON字符串
  6. 检查错误代码,出错则释放对象,函数返回NULL
static void* DecodeObject(const char* jsonStr, PJSON_MODEL_t model, unsigned int modelCount)
{
	void* obj = NULL;
	unsigned short objectSize = 0;
	const char* value = jsonStr;
	const char* nextValue = NULL;

	
	if (jsonStr == NULL || model == NULL || modelCount == 0)
	{
		JSONErrorCode = PARAM_IS_EMPTY;//字符串为空 失败
		return NULL;
	}

	
	if (*(value + 1) == '')
	{
		JSONErrorCode = DECODE_OBJECT_IS_EMPTY;//对象为空
		return NULL;
	}
	value++;//跳过字符 {
	nextValue = value;

	
	for (unsigned i = 0; i < modelCount; i++)
	{
		if (model[i].type == JSON_TYPE_OBJECT)
		{
			objectSize = model[i].value.objectSize;
			break;
		}
	}

	obj = JSON_malloc(objectSize);//申请空间
	if (obj == NULL)
	{
		JSONErrorCode = DECODE_OBJECT_FAIL_1;//为对象申请空间失败
		return NULL;
	}
	memset(obj, 0, objectSize);

#if (JSON_DEBUG == 1)
	printf("对象申请空间%pn", obj);
#endif // (JSON_DEBUG == 1)

	
	for (unsigned int i = 1; i < modelCount; i++)
	{
		
		if ((model[i].type == JSON_TYPE_OBJECT || model[i].type == JSON_TYPE_ARRAY))
		{
			value = JSONSkipChildJsonStr((char**)&nextValue, model[i].type);
			if (value == NULL)
			{
				JSONErrorCode = NOU_FIND_CHILD_ARRAY_OBJECT_END;//未找到子对象/数组的JSON字符串末尾
			}
		}
		else
		{
			
			value = strtok_s(NULL, ",", (char**)&nextValue);
		}

		switch (model[i].type)
		{
		case JSON_TYPE_BOOL:
			*(JSON_BOOL_t*)((char*)obj + model[i].offset) = DecodeBool(value, &model[i], 1);
			break;
		case JSON_TYPE_CHAR:
			*(char*)((char*)obj + model[i].offset) = (char)DecodeNumberOrDouble(value, &model[i], 1);
			break;
		case JSON_TYPE_SHORT:
			*(short*)((char*)obj + model[i].offset) = (short)DecodeNumberOrDouble(value, &model[i], 1);
			break;
		case JSON_TYPE_INT:
			*(int*)((char*)obj + model[i].offset) = (int)DecodeNumberOrDouble(value, &model[i], 1);
			break;
		case JSON_TYPE_UCHAR:
			*(unsigned char*)((char*)obj + model[i].offset) = (unsigned char)DecodeNumberOrDouble(value, &model[i], 1);
			break;
		case JSON_TYPE_USHORT:
			*(unsigned short*)((char*)obj + model[i].offset) = (unsigned short)DecodeNumberOrDouble(value, &model[i], 1);
			break;
		case JSON_TYPE_UINT:
			*(unsigned int*)((char*)obj + model[i].offset) = (unsigned int)DecodeNumberOrDouble(value, &model[i], 1);
			break;
		case JSON_TYPE_FLOAT:
			*(float*)((char*)obj + model[i].offset) = (float)DecodeNumberOrDouble(value, &model[i], 1);
			break;
		case JSON_TYPE_DOUBLE:
			*(double*)((char*)obj + model[i].offset) = (double)DecodeNumberOrDouble(value, &model[i], 1);
			break;
		case JSON_TYPE_STRING:
			*(char**)((char*)obj + model[i].offset) = DecodeString(value, &model[i], 1);
			break;
		case JSON_TYPE_OBJECT:
			
			
			value = CheckKeyName(value, &model[i]);
			if (value == NULL)
			{
				JSONErrorCode = DECODE_OBJECT_FAIL;//键名不一致解析失败
				//释放对象申请的空间
				FreeJSONObject(obj, model, modelCount);
				return NULL;
			}

			
			void* childObj = NULL;
			childObj = DecodeObject(value, model[i].value.child.model, model[i].value.child.count);
			if (childObj == NULL)//解析子对象失败
			{
				if (JSONErrorCode == DECODE_OBJECT_IS_EMPTY)//是不是空对象
				{
					JSONErrorCode = JSON_SUCCESS;//复位错误代码
				}
				else
				{
					JSONErrorCode = DECODE_OBJECT_FAIL_2;//解析子对象失败
					return NULL;
				}
			}
			*(char**)((char*)obj + model[i].offset) = childObj;
			break;
		case JSON_TYPE_ARRAY:
			DecodeArray(value, &model[i], (char*)obj + model[i].offset, 1);
			if (JSONErrorCode == DECODE_ARRAY_IS_EMPTY)//是不是空数组
			{
				JSONErrorCode = JSON_SUCCESS;//复位错误代码
			}
			break;
		default:
			break;
		}

		
		if (JSONErrorCode != JSON_SUCCESS)
		{
			//释放对象申请的空间
			FreeJSONObject(obj, model, modelCount);
			return NULL;
		}
	}

	return obj;
}
解析实数
  1. 检查字符串是否可读
  2. 转换实数
static double DecodeNumberOrDouble(const char* jsonStr, PJSON_MODEL_t model, char decodeKeyName)
{
	double d = 0.0;
	const char* value = jsonStr;
	const char* endStr = NULL;

	if (value == NULL)//检查字符串是否可读
	{
		return 0.0;
	}

	if (decodeKeyName)
	{
		value = CheckKeyName(jsonStr, model);
		if (value == NULL)
		{
			JSONErrorCode = DECODE_NUMBER_DOUBLE_FAIL; //解析整数/实数失败
			return 0.0;
		}
	}

	d = strtod(value, (char**)&endStr);
	if (*endStr != 'n' && *endStr != '' && *endStr != '}')//如果不是 null   } 则解析失败
	{
		JSONErrorCode = DECODE_NUMBER_DOUBLE_FAIL; //解析整数/实数失败
	}

	return d;
}
释放对象
  1. 遍历对象的数据模型
  2. 如果是实数类型,则继续
  3. 字符串类型则释放空间
  4. 对象类型则递归调用此函数
  5. 数组类型则根据数组元素类型来释放空间
void FreeJSONObject(void* obj, PJSON_MODEL_t model, unsigned int modelCount)
{
	void* addr = NULL;

	
	if (obj == NULL || model == NULL || modelCount == 0)
	{
		JSONErrorCode = PARAM_IS_EMPTY;//参数为空失败
		return;
	}

	if (JSON_malloc == NULL || JSON_free == NULL)
	{
		JSONErrorCode = JSON_NOT_INIT;//未初始化
		return;
	}

	for (unsigned int i = 0; i < modelCount; i++)
	{
		switch (model[i].type)
		{
		case JSON_TYPE_BOOL:
		case JSON_TYPE_CHAR:
		case JSON_TYPE_SHORT:
		case JSON_TYPE_INT:
		case JSON_TYPE_UCHAR:
		case JSON_TYPE_USHORT:
		case JSON_TYPE_UINT:
		case JSON_TYPE_FLOAT:
		case JSON_TYPE_DOUBLE:
			break;
		case JSON_TYPE_STRING:
			addr = *(char**)((char*)obj + model[i].offset);//字符串的地址
			if (addr)
			{
#if (JSON_DEBUG == 1)
				printf("释放字符串%p  %sn", addr, addr);
#endif // (JSON_DEBUG == 1)

				JSON_free(addr);
			}
			break;
		case JSON_TYPE_OBJECT:
			if (model[i].keyName == NULL)
			{
				continue;
			}
			addr = *(char**)((char*)obj + model[i].offset);//对象的地址
			if (addr)
			{
				FreeJSONObject(addr, model[i].value.child.model, model[i].value.child.count);
			}
			break;
		case JSON_TYPE_ARRAY:
			switch (model[i].value.array.type)
			{
			case JSON_TYPE_BOOL:
			case JSON_TYPE_CHAR:
			case JSON_TYPE_SHORT:
			case JSON_TYPE_INT:
			case JSON_TYPE_UCHAR:
			case JSON_TYPE_USHORT:
			case JSON_TYPE_UINT:
			case JSON_TYPE_FLOAT:
			case JSON_TYPE_DOUBLE:
				break;
			case JSON_TYPE_STRING:
				for (unsigned int j = 0; j < model[i].value.array.count; j++)
				{
					addr = *(char**)((char*)obj + model[i].offset + j * model[i].value.array.size);
					if (addr)
					{
#if (JSON_DEBUG == 1)
						printf("释放字符串%p  %sn", addr, addr);
#endif // (JSON_DEBUG == 1)

						JSON_free(addr);
					}
				}
				break;
			case JSON_TYPE_OBJECT:
				for (unsigned int j = 0; j < model[i].value.array.count; j++)
				{
					addr = *(char**)((char*)obj + model[i].offset + j * model[i].value.array.size);
					if (addr)
					{
						FreeJSONObject(addr, model[i].value.array.child.model, model[i].value.array.child.count);
					}
				}
				break;
			default:
				break;
			}
			break;
		default:
			break;
		}
	}

#if (JSON_DEBUG == 1)
	printf("释放对象%pn", obj);
#endif // (JSON_DEBUG == 1)
	JSON_free(obj);
}
编码 JSON编码
  1. 先计算根对象需要的内存空间大小
  2. 调用编码对象功能函数编码JSON字符串
char* EncodeJSON(void* obj, PJSON_MODEL_t model, unsigned int modelCount)
{
	char* encodeJSONStr = NULL;
	char* str = NULL;
	BYTES_t bytes = 0;

	
	JSONErrorCode = JSON_SUCCESS;

	if (obj == NULL || model == NULL || modelCount == 0)
	{
		JSONErrorCode = PARAM_IS_EMPTY;//函数参数无效
		return NULL;
	}

	if (JSON_malloc == NULL || JSON_free == NULL)
	{
		JSONErrorCode = JSON_NOT_INIT;//未初始化
		return;
	}

	
	bytes = GetObjectNeedBytes(obj, model, modelCount);
	if (bytes == 0)
	{
		return NULL;
	}

#if (JSON_DEBUG == 1)
	printf("编码的JSON字符串长度为%un", bytes);
#endif // (JSON_DEBUG == 1)

	
	bytes++;
	encodeJSONStr = JSON_malloc(bytes);
	if (encodeJSONStr == NULL)
	{
		JSONErrorCode = ENCODE_FAIL;//申请空间失败
		return NULL;
	}
	memset(encodeJSONStr, 0, bytes);

#if (JSON_DEBUG == 1)
	printf("编码的JSON字符串长度申请空间%pn", encodeJSONStr);
#endif // (JSON_DEBUG == 1)

	
	str = encodeJSONStr;
	str = EncodeObject(obj, model, modelCount, str);
	*str = '';//添加字符串结束标志

#if (JSON_DEBUG == 1)
	printf("编码的JSON字符串为%sn", encodeJSONStr);
#endif // (JSON_DEBUG == 1)

	return encodeJSONStr;
}
demo

JSON字符串如下

{
  "id": "0011223344",
  "name": "张三",
  "phone": "111-22223333",
  "addr": "天安门广场",
  "grade": "小学四年级",
  "score": {
	"math": 99.5,
	"chinese": 85.5,
	"english": 86,
	"science": 86.5,
	"history": 92
  }
}

对应的结构体定义如下

typedef struct score
{
	float math;
	float chinese;
	float english;
	float science;
	float history;
}score_t, * Pscore_t;


typedef struct stu
{
	char* id;
	char* name;
	char* phone;
	char* addr;
	char* grade;
	Pscore_t score;
}stu_t, * Pstu_t;

相应的数据模型

 
JSON_MODEL_t scoreModel[] =
{
	JSON_ROOT_OBJECT(score_t),
	JSON_FLOAT(score_t, math),
	JSON_FLOAT(score_t, chinese),
	JSON_FLOAT(score_t, english),
	JSON_FLOAT(score_t, science),
	JSON_FLOAT(score_t, history)
};


JSON_MODEL_t stuModel[] =
{
	JSON_ROOT_OBJECT(stu_t),
	JSON_STRING(stu_t, id),
	JSON_STRING(stu_t, name),
	JSON_STRING(stu_t, phone),
	JSON_STRING(stu_t, addr),
	JSON_STRING(stu_t, grade),
	JSON_OBJECT(stu_t, score, scoreModel, sizeof(scoreModel) / sizeof(JSON_MODEL_t))
};

解码/编码

	JSONInit(malloc, free);

	char jsonStr[] = "
	{
		"id": "0011223344",
			"name" : "张三",
			"phone" : "111-22223333",
			"addr" : "天安门广场",
			"grade" : "小学四年级",
			"score" : {
			"math": 99.5,
				"chinese" : 85.5,
				"english" : 86,
				"science" : 86.5,
				"history" : 92
		}
	}
		";
	
	Pstu_t stu = DecodeJSON(jsonStr, stuModel, sizeof(stuModel) / sizeof(JSON_MODEL_t), 1);

	if (stu == NULL)
	{
		printf("stu解码失败 errorCode = %dn", JSONErrorCode);
		return;
	}

	if (stu->id == NULL)
	{
		printf("学号为空n");
	}
	else
	{
		printf("学号为%sn", stu->id);
	}

	if (stu->name == NULL)
	{
		printf("姓名为空n");
	}
	else
	{
		printf("姓名为%sn", stu->name);
	}

	if (stu->phone == NULL)
	{
		printf("手机号为空n");
	}
	else
	{
		printf("手机号为%sn", stu->phone);
	}

	if (stu->addr == NULL)
	{
		printf("住址为空n");
	}
	else
	{
		printf("住址为%sn", stu->addr);
	}

	if (stu->grade == NULL)
	{
		printf("年级为空n");
	}
	else
	{
		printf("年级为%sn", stu->grade);
	}

	if (stu->score == NULL)
	{
		printf("成绩为空n");
	}
	else
	{
		printf("数学:%.2f  语文:%.2f  英语:%.2f  科学:%.2f  历史:%.2fn",
			stu->score->math, stu->score->chinese, stu->score->english, stu->score->science, stu->score->history);
	}
	printf("nn");

	
	char* str = EncodeJSON(stu, stuModel, sizeof(stuModel) / sizeof(JSON_MODEL_t));

	if (str == NULL)
	{
		printf("编码失败n");
		return;
	}

	printf("%sn", str);


	
	FreeJSONString(str);
	FreeJSONObject(stu, stuModel, sizeof(stuModel) / sizeof(JSON_MODEL_t));

输出结果

C语言实现JSON字符串解码与编码(一)大致思路

C语言实现JSON字符串解码与编码(二)头文件介绍

C语言实现JSON字符串解码与编码(三)源代码

源代码下载链接

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/836035.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号