自编适用于嵌入式单片机Json封包与解析的程序

@[TOC]**

自编适用于嵌入式单片机Json封包与解析的程序

**

说明:

由于网上提供的标准JSON库,对向单片机这类的小设备占用资源过多,很不实际,所以用C语言自编,在平台STM32F103和Keil5上运行测试本程序。

设计思想:
创建一个数组,将JSON符号和键值对,按JSON标准格式直接写入数组中进行封包,解析同理,通过直接在JSON数据包中查找的方式,找到键所对应的值,不另开内存暂存。
现附上源码:
一,头文件
#ifndef __myJson_H
#define __myJson_H

#include “main.h”

#define my_u8 uint8_t
#define my_u16 uint16_t
#define my_u32 uint32_t

//------------------------------------Json解码,占很少内存------------------------------------------------------
enum Vile_type
{
JsonVile_type_NuLL = 0,//无数据
JsonVile_type_Number,//10进制数据
JsonVile_type_S,//字符串
JsonVile_type_C,//字符(无双引号)
JsonVile_type_Bool,//布尔型
JsonVile_type_Null,//Null型
};//没有对Json对象得取值

typedef struct Json_GetVile
{
my_u8 Vile_type;//得到的值类型
float Vile_Number;//10进制数据
my_u8 *pSC_Null;//串型数据地址或者Null 根据Vile_type存储响应的数据
my_u16 SC_Lenth_Bool;//数据长度或者Bool
}myJson_GetVile_t;

//在Json数据包中得到键pKey_Str的地址 对于有多个子节点的,缩短查找时间,相当于取一个Json对象
my_u8 *myJson_GetFather_Address(my_u8 *pJson_Pack,my_u16 PackLenth,char *pKey_Str);

//在Json数据包中得到键pKey_Str的值
myJson_GetVile_t *myJson_GetVile(my_u8 *pJson_Pack,char *pKey_Str);//用完free

//------------------------------------Json封包,占很少内存------------------------------------------------------
typedef struct JsonPack //对外接口
{
my_u8 *pJsonPack;//指向封包数组
my_u16 JsonPack_Lenth;//封包数组中字符串的长度
}JsonPack_t;

//对Json数据进行封包,
void myJson_Pack(JsonPack_t *JsonPack,char *pForMart,char *pForMart_Str,char **pForMart_ArryS,char **pForMart_ArryC,float *pForMart_ArryNumber);//
//Json格式化输出方便调试
void myJson_ForMart_Printf(JsonPack_t *JsonPack);//用Json格式输出 方便查看

#endif

二,源文件:
#include “myJson.h”
#include “stdlib.h”
1.共用工具源文件:
/*******************************************
程序功能:计算pStr字符串长度,返回pStr字符串长度
@pStr:被计算的字符串,可以包含0,0的连续个数<=10
@pStr_Lenth:被计算字符串分配空间长度,可以用sizeof关键字,若被计算的字符串不包含0,pStr_Lenth =0
说明:
*******************************************/
my_u16 myStrlen_Inc0(my_u8 *pStr,my_u16 pStr_Lenth)//计算字符串长度 数组包含0也无防
{
my_u16 Lenth = 0;
my_u8 Lenth_0 = 0;

if(!pStr_Lenth)
{
  while(*pStr !='\0')
  {pStr++;Lenth++;}		
return Lenth;	
}

while(Lenth != pStr_Lenth)
{
if(*pStr ==’\0’)
{
Lenth_0 ++;
if(((Lenth +Lenth_0) == pStr_Lenth)//数组最大个数
||(Lenth_0 == 10))//连续10个0表示字符串结束
return Lenth;
}
else
{
if(Lenth_0){Lenth += Lenth_0;Lenth_0 = 0;}
Lenth ++;
}
pStr ++;
}

return Lenth;
}

/*******************************************
程序功能:在pStr_Source字符串中查找pObjStr字符串,匹配成功返回最后一个查找字符的地址,否则返回NULL
@pStr_Source:被查找字符串,可以包含0 无0下面长度可填0
@Source_Lenth:源数组分配空间长度,可以用sizeof关键字
@pObjStr:查找的字符串 无0下面长度可填0
@ObjStr_Lenth:查找的字符串的长度
说明:不区分大小写
******************************************/
my_u8
String_Cmp(my_u8 *pStr_Source,my_u16 Source_Lenth,my_u8 *pObjStr,my_u16 ObjStr_Lenth)//
{
my_u8 StrEqu_Lenth = 0;//匹配度
my_u8 Str_Source = 0;
my_u8 Str = 0;

my_u8 pStr_Lenth = myStrlen_Inc0(pObjStr,ObjStr_Lenth);
Source_Lenth = myStrlen_Inc0(pStr_Source,Source_Lenth);
while(Source_Lenth --)
{
	Str_Source = *pStr_Source;
	Str = *pObjStr;
	if((*pStr_Source >= 'A')&&(*pStr_Source <= 'Z'))//转小写
	  Str_Source = *pStr_Source +32;
	if((*pObjStr >= 'A')&&(*pObjStr <= 'Z'))//转小写
		Str = *pObjStr +32;
			
	if(Str_Source != Str)//不匹配
	{
		if(StrEqu_Lenth)
		{
			Source_Lenth++;//多比较一次
			pStr_Source --;//当前字符是不是匹配的头字符
		}			 
	  pObjStr -= StrEqu_Lenth;
	  StrEqu_Lenth = 0;
	}		
	else{pObjStr ++;StrEqu_Lenth ++;}
  						
	if(pStr_Lenth == StrEqu_Lenth) return pStr_Source;
pStr_Source ++;			
}
	
return NULL;

}

/*******************************************
程序功能:将字符串pObjStr插入到字符串pStr_Source中字符串pCmStr的后面,成功返回1
@pStr_Source:源数组,可以包含0
@Source_Lenth:源数组分配空间长度,可以用sizeof关键字
@pCmStr:被插入字符串,不能包含0
@pObjStr:要插入的数组,可以包含0
@ObjStr_Lenth:数组分配空间长度,可以用sizeof关键字
说明:1.源数组的长度要能够包含插入的数组的长度
*******************************************/
my_u8 Arry_InsBack(my_u8 *pStr_Source,my_u16 Source_Lenth,my_u8 *pCmStr,my_u8 *pObjStr,my_u16 ObjStr_Lenth)
{
my_u16 Lenth = myStrlen_Inc0(pObjStr,ObjStr_Lenth);
pCmStr =String_Cmp(pStr_Source,Source_Lenth,pCmStr);
if(pCmStr ==NULL) return 0;
pCmStr ++;//后面插入

my_u16 offset = Lenth;
while(Lenth)
{
  *(pCmStr +offset) = *pCmStr;//源数据后移
  *pCmStr = *pObjStr;
	pCmStr ++;pObjStr ++;Lenth --;
	if(pCmStr >(pStr_Source +Source_Lenth)) return 0;
}
return 1;

}

/*******************************************
程序功能:将数组pObjStr写入到源数组pStr_Source中的当前位置,成功返回1
@pStr_Source:源数组
@pObjStr:要插入的数组
@ObjStr_Lenth:插入的数组的长度
说明:1.源数组的长度要能够包含插入的数组的长度
*******************************************/
void Arry_WriteChar(my_u8 *pStr_Source,my_u8 *pObjStr,my_u16 ObjStr_Lenth)
{
my_u16 Lenth = myStrlen_Inc0(pObjStr,ObjStr_Lenth);

while(Lenth--)
{
	*pStr_Source = *pObjStr;
	pStr_Source ++;pObjStr ++;
}

}

//以下2个函数,将数字型字符串转换成float数据
uint8_t is_digit(char ch)//判断是不是数字
{
if(ch>=‘0’&&ch<=‘9’)
return 1;
else
return 0;
}

float Floatnum(char s)//将字符数字转换成10进制数
{
float power,value;
uint8_t i=0,sign;
sign=(s[i]’-’)?-1:1;
if(s[i]
’-’||s[i]==’+’)//要是有符号位就前进一位
i++;
for(value=0.0;is_digit(s[i]);i++)//计算小数点前的数字
value=value
10.0+(s[i]-‘0’);
if(s[i]==’.’)
i++;
for(power=1.0;is_digit(s[i]);i++)//计算小数点后的数字
{
value=value10.0+(s[i]-‘0’);
power
=10.0;
}
return sign*value/power;
}

2.JSON解析源文件
/*******************************************
程序功能:在Json数据包中得到键pKey_Str的地址,以便对其有多个子节点的,缩短查找时间,类似于取一个Json对象
@pJson_Pack:被查找Json数据包
@PackLenth:Json数据包的长度,可以是分配数组长度
@pKey_Str:被查找的Json键
@return:返回Json键在Json数据包中的地址
说明:不区分大小写
*******************************************/
my_u8 *myJson_GetFather_Address(my_u8 pJson_Pack,my_u16 PackLenth,char pKey_Str)
{
my_u8
pKey_Str_Address = String_Cmp(pJson_Pack,PackLenth,(my_u8
)pKey_Str,0);//
if(pKey_Str_Address == NULL) return NULL;

return pKey_Str_Address;
}

/*******************************************
程序功能:在Json数据包中得到键pKey_Str的值
@pJson_Pack:被查找Json数据包
@pKey_Str:被查找Json键
@return:返回myJson_GetVile_t类型的malloc地址
说明:用完free
*******************************************/
myJson_GetVile_t *myJson_GetVile(my_u8 *pJson_Pack,char *pKey_Str)//在Json字符串包中得到键pKey的值–10进制数
{
myJson_GetVile_t GetVile = (myJson_GetVile_t)malloc(sizeof(myJson_GetVile_t));
GetVile->Vile_type = JsonVile_type_NuLL;//无数据

my_u8* pKey_Str_Address = String_Cmp(pJson_Pack,4096,(my_u8*)pKey_Str,0);//
my_u8* pVile_Str_Address = NULL;
my_u16 Vile_Str_Lenth = 0;	
if((pKey_Str_Address == NULL)||(GetVile == NULL)) return GetVile;
	
 while(1) //计算有效键值的地址及长度
 {
	 pKey_Str_Address ++;
   if((*pKey_Str_Address ==',')||(*pKey_Str_Address =='}')||(*pKey_Str_Address ==']')) break;
	 
	 if(Vile_Str_Lenth ==0)//有的字符串里面含有空格,和冒号
	 {
	   if(*pKey_Str_Address ==':') {pVile_Str_Address = pKey_Str_Address;}//键值对分割符
	   else if((*pVile_Str_Address ==':')&&(*pKey_Str_Address !=' '))//去掉最前面的空格
	      {pVile_Str_Address = pKey_Str_Address;}//找到第一个有效字符
				
		 if((pVile_Str_Address !=NULL)&&(*pVile_Str_Address !=':')) Vile_Str_Lenth =1;
	 }
	 else
		 Vile_Str_Lenth ++;
 }
if(!Vile_Str_Lenth) return GetVile;
 
pKey_Str_Address = pVile_Str_Address +Vile_Str_Lenth;
while(1)//去掉最后面的空格
{
   if(*pKey_Str_Address != ' ') break;
	 Vile_Str_Lenth --;pKey_Str_Address --;
}	 	 
GetVile->SC_Lenth_Bool = Vile_Str_Lenth;
GetVile->pSC_Null = pVile_Str_Address;

//------------------ 取Number型数据----------------
pKey_Str_Address = pVile_Str_Address;
while(Vile_Str_Lenth–)//判断是否Number型数据
{
if((pKey_Str_Address !=’.’)&&((pKey_Str_Address <‘0’)||(pKey_Str_Address >‘9’))) break;
pKey_Str_Address ++;
if(!Vile_Str_Lenth) break;
}
pKey_Str_Address = pVile_Str_Address;
if(Vile_Str_Lenth == 0) //
{
GetVile->Vile_Number = Floatnum((char
)pKey_Str_Address);//转换成十进制数
GetVile->Vile_type = JsonVile_type_Number;//十进制数数据
return GetVile;
}
//------------------ 取bool型数据-------------------
if(String_Cmp(pKey_Str_Address,6,(my_u8
)“true”,0) != NULL)
{
GetVile->SC_Lenth_Bool = 1;//转换成十进制数
GetVile->Vile_type = JsonVile_type_Bool;//Bool数据
return GetVile;
}
else if(String_Cmp(pKey_Str_Address,7,(my_u8
)“false”,0) != NULL)
{
GetVile->SC_Lenth_Bool = 0;//转换成十进制数
GetVile->Vile_type = JsonVile_type_Bool;//Bool数据
return GetVile;
}
//------------------ 取Null型数据-------------------
if(String_Cmp(pKey_Str_Address,6,(my_u8*)“Null”,0) != NULL)
{
GetVile->pSC_Null = NULL;//转换成地址
GetVile->Vile_type = JsonVile_type_Null;//Bool数据
return GetVile;
}
//------------------ 取字符串型数据-------------------
if(*pKey_Str_Address ==’"’) GetVile->Vile_type = JsonVile_type_S;//字符串数据
else GetVile->Vile_type = JsonVile_type_C;//字符串数据(无双引号)
return GetVile;
}

3.JSON封包源码
my_u16 JsonStr_Lenth(char *Str)//在字符串中取字符串
{
my_u16 Lenth = 0;
while(1)
{
if((*Str ==’,’)||(*Str ==’:’)||(*Str ==’\0’)) break;//
Str ++;Lenth ++;
}
return Lenth;
}

my_u16 Add_Str(JsonPack_t *JsonPack,char *Str_Key)//增加Json字符串 有双引号
{
my_u16 Lenth = JsonStr_Lenth(Str_Key);//键字符串长度
my_u8 *AdessOffset = JsonPack->pJsonPack +JsonPack->JsonPack_Lenth;

*AdessOffset = '\"';//当前位置  
*(AdessOffset +1) = '\"';
JsonPack->JsonPack_Lenth += Lenth +2;

Arry_InsBack(AdessOffset,2048,(my_u8*)""",(my_u8*)Str_Key,Lenth);//写入键字符串

return Lenth;
}

my_u16 Add_Char(JsonPack_t *JsonPack,char *KeyVile_Char)//增加Json字符串 无双引号
{
my_u16 Lenth = JsonStr_Lenth(KeyVile_Char);
my_u8 *AdessOffset = JsonPack->pJsonPack +JsonPack->JsonPack_Lenth;

JsonPack->JsonPack_Lenth += Lenth;
Arry_WriteChar(AdessOffset,(my_u8*)KeyVile_Char,Lenth);
 
return Lenth;

}

my_u16 Add_Number(JsonPack_t *JsonPack,float Number)//增加Json数值键值
{
char strff[21] = {0};
my_u8 AdessOffset = JsonPack->pJsonPack +JsonPack->JsonPack_Lenth;
my_u16 Lenth = 0;
sprintf(strff,"%.4f",Number);//4位小数 float转换成字符 补齐小数位
Lenth = myStrlen_Inc0((my_u8
)strff,sizeof(strff));//计算字符串长度 数组包含0也无防

while(Lenth --)//去掉尾数0
{
  if(strff[Lenth] !='0') break;
	strff[Lenth] = 0;
}
if(strff[Lenth] =='.') strff[Lenth] = 0;
else Lenth ++;

JsonPack->JsonPack_Lenth += Lenth;
Arry_WriteChar(AdessOffset,(my_u8*)strff,Lenth);

return Lenth;
}

my_u8 Add_Identifier(JsonPack_t *JsonPack,const char Identifier)//增加Json标识符 {}[]:,
{
my_u8 *AdessOffset = JsonPack->pJsonPack +JsonPack->JsonPack_Lenth;
*(AdessOffset) = Identifier;//当前位置
JsonPack->JsonPack_Lenth += 1;

return 1;

}

/*******************************************
程序功能:对Json数据进行封包
@JsonPack:Json结构体
@pForMart:对数据进行Json格式化定义–{s:s,s:i,{s:s,[s:i]}} s-字符串 S-数组中的字符串 c-字符串(无双引号) C-数组中的字符串(无双引号) i-变量(数组中的float值)
@pForMart_Str: 与Formart对应的字符串,用分号或逗号隔开
@pForMart_ArryS:与Formart对应的字符串,这个字符串存储在数组中,用pForMart_ArryS来指向它
@pForMart_ArryC:与Formart对应的字符串(无双引号),这个字符串存储在数组中,用pForMart_ArryS来指向它
@pForMart_ArryNumber:与Formart对应的float数据,存储在数组中,用pForMart_ArryNumber来指向它
说明:
*******************************************/
void myJson_Pack(JsonPack_t *JsonPack,char *pForMart,char *pForMart_Str,char **pForMart_ArryS,char **pForMart_ArryC,float *pForMart_ArryNumber)//
{
my_u8 Number_i = 0;
my_u8 Str_S_i = 0;
my_u8 Str_C_i = 0;

while(1)
{
	if(*pForMart =='S')//字符串数组
	{
		Add_Str(JsonPack,*(pForMart_ArryS +Str_S_i));//增加键
		Str_S_i ++;
	}		
  else if(*pForMart =='s')
	{
		pForMart_Str += Add_Str(JsonPack,pForMart_Str) +1;//增加键	
	}
else if(*pForMart =='C')//字符串数组
	{
		Add_Str(JsonPack,*(pForMart_ArryC +Str_C_i));//增加键
		Str_C_i ++;
	}		
	else if(*pForMart =='c')
	{
		pForMart_Str += Add_Char(JsonPack,pForMart_Str) +1;//增加键-字符键值	没有双引号 
	}
	else if(*pForMart =='i')
	{
		Add_Number(JsonPack,*(pForMart_ArryNumber +Number_i));//增加键-数值键值
		Number_i ++;
	}		
	else if((*pForMart =='{')||(*pForMart =='}')||(*pForMart =='[')||(*pForMart ==']')||(*pForMart ==',')||(*pForMart ==':'))
	{			
		Add_Identifier(JsonPack,*pForMart);//增加标识符 {}[],
	}

  pForMart ++;
	
	 if(*pForMart =='\0') return;	
} 

}

//以下两个函数对JSON数据包进行格式化打印输出,主要起方便调试阅读的功能
void Printf_nSpace(my_u8 space_N)
{
while(space_N–)
printf(" ");//空1个字符
}

void myJson_ForMart_Printf(JsonPack_t *JsonPack)//Json格式化输出方便调试 Json数据包的有效数据长度不能少
{
my_u8 space_Nadd = 0;//打印空N格
my_u16 Dat_Lenth = JsonPack->JsonPack_Lenth;
my_u8 *pForMart = JsonPack->pJsonPack;
my_u8 printf_char = 0;

printf("\n");//换行
while(1)
{				
  if((*pForMart =='{')||(*pForMart =='['))
	{
		if(*(pForMart -1) == ':') 
		{
			printf("\n");//换行
		  Printf_nSpace(space_Nadd);//空space_N格
		}
		printf_char = *pForMart;
		printf("%s\n",&printf_char);//换行
		space_Nadd += 2;
	  Printf_nSpace(space_Nadd);//空space_N格
	}	    
	else if(*pForMart ==',')
	{
		printf_char = *pForMart;
		printf("%s\n",&printf_char);//换行
	  Printf_nSpace(space_Nadd);//空space_N格
	}
  else if((*pForMart =='}')||(*pForMart ==']'))
	{
		printf("\n");//换行 空两格
		space_Nadd -= 2;
	  Printf_nSpace(space_Nadd);//空space_N格
		printf_char = *pForMart;
		printf("%s",&printf_char);//
	} 

	pForMart ++;Dat_Lenth--;if(!Dat_Lenth) return;
	while(Dat_Lenth--)
	{
		if((*pForMart =='{')||(*pForMart =='}')||(*pForMart =='[')||(*pForMart ==']')||(*pForMart ==','))
		{Dat_Lenth ++;break;}//
		printf_char = *pForMart;
	  printf("%s",&printf_char);//一次只打印1个字符
		pForMart ++;				
	}
	if(!Dat_Lenth) return;
}	

}

下图是运行测试结果:
在这里插入图片描述
下面两张图片是对从阿里云下发的JSON数据进行解析:
在这里插入图片描述
在这里插入图片描述

自此,自编JSON封包解析程序达到设计要求。
完,若有不足,敬请指教,谢谢观看!

附,自编json源文件包,https://download.csdn.net/download/mymycsdn321/20664315

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值