Json学习--简单解析

17 篇文章 1 订阅

Json学习

 按照通常学习的思路,将对Json的学习分为4步,如下:

 一、了解Json格式;

二、解析Json格式;

三、创建Json格式;

四、使用标准接口;  

一、了解Json格式;        

         JSON 是基于纯文本的数据格式,我们可以用 JSON 传输一个简单的 String,Number,Boolean,也可以传输一个数组,或者一个复杂的 Object 对象。Json可以理解为一种规范化的键值对(key:value)描述方法,同 XML 相比,JSON 提供了更好的简单性和灵活性。 

         对于JSON的定义,在网上能找到许多,在其官方网站http://www.json.org.cn/ 有详细的介绍。    

二、解析Json格式; 

         光看看Json的定义,还是远远不够的,下面就来动一下手,用C语言写个程序来解读一下Json字符串。 

1,  写一个简单的C程序,编译通过;

         我是在Linux下编程的,但是对于C与Json,都是与平台无关的,所以windows平台上编程也是一样适用的。 

2,实现读文件功能;

         Json使用的通常情况,分为两种,一个是做为接口,在两个进程之间传递信息;一个是做为存储信息,在程序启动之初读取后做初始化使用。

         为了便于测试,我这里是手工写好一个符合Json格式的文本文件,然后进行读取解析。 

3,按json格式读取一个值;               

         这里主要是实现对key的解析,以及对value的解析。value又分为几种情况,我只考虑3种情况,string,int,float,这样,对于简单的应用,也是足够使用了的。

         解析第一个Json字符串,如下:

{"firstName":"Brett"}

         或者如下,一个数字的例子:

{"age":8} 

4,读取一个结构体;  

要读取的内容如下:

{"firstName":" Brett ","lastName":"Jason","email":"bbbb@126.com","age":8,"height":1.67}

要读取的内容是一个对象,我们需要定义一个与之匹配的结构体,如下:

typedef struct

{

         charfirstName[32];

         charlastName[32];

         charemail[64];

         intage;

         floatheight;

}people;

         需要注意,结构体中的成员在Json串中出现的顺序,不一定与结构体中的成员定义顺序一致(例如,age可能出现在第一个位置)。说到这里,其实就是提出了一个问题,在我们写的程序中,需要考虑哪些异常情况?例如,结构体中成员出现的顺序乱,或者某个成员不存在,或者多了个“{”或“,”等,哪些异常情况需要支持,哪些不需要支持,只需要报错就好了。

         异常的情况比较多,不容易一次考虑全,可以参考下别人是怎么做的。建议使用网上的Json在线解析工具做一些异常测试,再来决定如何处理。网上的在线解析工具,可以参考这个:

http://json.cn/ 

5,读取数组;               

         我是用了一个比较复杂的数组,成员为结构体的数组,如下:

{

"people":[

{"firstName":"z","lastName":"Jason","email":"bbbb@126.com","height":1.67},

{"lastName":"jadena","email":"aaaa@126.com","age":8,"height":1.17},

{"email":"cccc@126.com","firstName":"z","lastName":"Juliet","age":36,"height":1.55}

]

}

注意看下,这个数组中,其成员结构体应该还是同上面定义的结构体people一致,但是,其中某些项是缺少的,某些成员的出现顺序是错乱的,这也是对我们程序的一种测试。 

对于结构体为成员的数组,需要考虑的东西就比较多了,我大体列了几项:

1,  如何实现某个key的重复出现的解析?

首先看看“lastName”,它是在每个对象中出现一次的,也就是说,第一个“lastName”赋值给第一个对象,第二个“lastName”赋值给第二个对象,如此类推。

2,  对于缺少的成员,如何处理?

例如“firstName”,在第二个对象中就缺少了,此时,绝不能搜索第三个对象中的“firstName”来填充第二个对象。这里就出来一个问题,怎么判断第二个对象的结束?

每个对象都是有边界的,由“{”开始,到“}”结束。对于第二个对象,若搜索到结束处,还没有“firstName”,那么,就认为是读取不到该值了。此时,并不是认为Json串有格式问题,而是给相应值赋上默认值,继续往后解析。

3,  如何界定数组的结束?

每个数组都是有边界的,由“[”开始,到“]”结束。

4,  对于更复杂的情况,例如,数组的成员是结构体,在结构体中又有数组,该如何解析呢?     

两种方法:

1)先定义一个解析的规则,或者说模板,然后照着模板来解析。对于解析规则,要考虑到兼容性:   

                   若添加了新项,旧的解析规则应该能工作,只是不解析新添加成员;

                   对于旧json串,新的解析规则应该能工作,只是新添加成员不能赋值;

2)使用一种标准的解析方法,能够实现互相嵌套解析。

目前,我使用了第一种方案,因为这样对于编程来说要简单一些。如果想做一个通用接口,还是应该选择第二种方案来做。     

6,整体Json字符串的有效性判断;                   

         整体判断是否符合json串的规则,我整理了几项:

1,“{”与“}”的个数,应该是匹配的(需要去掉字符串值中的{});

2,“[”与“]”应该匹配(需要去掉字符串值中的[]);

3,“"”是成对的(需要去掉字符串内容中的");

4,每个键值对中有一个“:”;

5,两个同级相邻的键值对(或者数组元素、对象)之间是“,”;

6,判断过程中要考虑字符串的规则,尤其是特殊字符;

7,判断过程中要考虑数字的规则;

         在代码实现中,我使用了前3项来进行有效性判断,并不完整,但是也能做一个初步的判断了。          

7,效率问题;

         关于效率问题,其实是与实现方案密切相关的,我在编程过程中考虑过3种方案:

1,  在整个Json串中进行逐个key的搜索;

----效率不高,实现逻辑比较简单。这是我第一次选择的方案,但是存在问题:若数组内某个对象缺少某个成员的赋值,则该key值不存在,会导致搜索下一个对象的,从而导致赋值错误。 

2,  从json串的头开始解析,循序往后;

----效率高,但是这个解析方法的实现,比较复杂。里面还涉及递归调用的问题,我还没有考虑明白,暂时不采用。

 3,  对每个结构体内容的逐个搜索;

对于一个结构体,知道开始与结束,就有了边界,可以解决第1个方案中的成员缺少问题。这也是我目前采用的方案,效率介于以上两个方案之间。

   

说明:

本文所附带例程,只是一个学习之作,对于初学Json的同学,可以有些借鉴参考的作用。但是,对于异常处理、字符串中的特殊字符的处理等,都不完善,解析方法也不是做成一个通用的接口,只能根据具体的协议类型,来定制一个解析函数,在使用过程中受限较多,所以,并不能真正用于软件工程开发中。

真正用于软件工程开发中的Json接口,C语言版本的大家可以参考CJSON,下载地址为http://sourceforge.net/projects/cjson/。至于其他语言的,可以到 http://www.json.org.cn/ 中去寻找相应的实现。

  

附带例程:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>


#define PRINT(msg...) do {printf("lintax: "); printf(msg);}while(0)
typedef struct
{
	int id;
	char firstName[32];
	char lastName[32];
	char email[64];
	int age;
	float height;
}people;



//在缓冲buf 中寻找字符串str
//this func could find something in bin (not only in str)
int find_str_in_buf(char * buf,int len,char * str,int len_str)
{
	int pos_buf=0;
	char * buf_tmp=buf;
	int i,num;

	if((buf==NULL)||(str==NULL))
	{
		return -1;
	}

	while(pos_buf+len_str<=len)
	{
		num=0;
		for(i=0;i<len_str;i++)
		{
			if(buf_tmp[i]==str[i])
			{
				num++;
			}
			else
			{
				break;
			}
		}
		if(num==len_str)
		{
			return pos_buf;
		}
		pos_buf++;
		buf_tmp++;
	}
	return -1;

}




//parse json string

//judge whether the string meet the Json standards
//Json conditions:
//{}匹配
//[]匹配
//"是成对的,去掉字符串内容中的"
每个键值对中有一个:
两个键值对(数组元素,对象)之间是,
字符串的规则
数字的规则
int judge_json_format(char * json_str, int str_len)
{

	int pos_str=0;
	int num_brace_left=0,num_brace_right=0;
	int num_bracket_left=0,num_bracket_right=0;
	int num_quote=0;
	int is_quote_left=0;
	int num_solidus=0;

	if ( (json_str==NULL)||(str_len<=0) )
	{
		return -1;
	}

	//跳过开头的空格与回车,寻找第一个{
	char char_tmp='\0';
	do
	{
		char_tmp=*(json_str+pos_str);
		if(( char_tmp==' ') ||( char_tmp=='\t') ||( char_tmp=='\n') ||( char_tmp=='\r') )
		{
			pos_str++;
		}
		else if( char_tmp=='{')
		{
			pos_str++;
			break;
		}
		else
		{
			PRINT("find the first { failed\n");
			return -1;
		}
	}
	while(char_tmp!='{');
	num_brace_left++;
	PRINT("find the first { ,pos_str=%d,num_brace_left=%d\n",pos_str,num_brace_left);


	//count the "[]{}
	do
	{
		char_tmp=*(json_str+pos_str);
		switch(char_tmp)
		{
			case '\\':
				num_solidus++;
				pos_str++;//跳过转义字符
				PRINT("pos_str=%d    ",pos_str);
				PRINT("num_solidus=%d\n",num_solidus);
				break;
			case '{':
				if(is_quote_left==0)
				{
					num_brace_left++;
					PRINT("pos_str=%d    ",pos_str);
					PRINT("num_brace_left=%d,num_brace_right=%d\n",num_brace_left,num_brace_right);
				}
				break;
			case '}':
				if(is_quote_left==0)
				{
					num_brace_right++;
					PRINT("pos_str=%d    ",pos_str);
					PRINT("num_brace_left=%d,num_brace_right=%d\n",num_brace_left,num_brace_right);
				}
				break;
			case '[':
				if(is_quote_left==0)
				{
					num_bracket_left++;
					PRINT("pos_str=%d    ",pos_str);
					PRINT("num_bracket_left=%d,num_bracket_right=%d\n",num_bracket_left,num_bracket_right);
				}
				break;
			case ']':
				if(is_quote_left==0)
				{
					num_bracket_right++;
					PRINT("pos_str=%d    ",pos_str);
					PRINT("num_bracket_left=%d,num_bracket_right=%d\n",num_bracket_left,num_bracket_right);
				}
				break;
			case '\"':
				num_quote++;
				is_quote_left=1-is_quote_left;
				//PRINT("pos_str=%d    ",pos_str);
				//PRINT("num_quote=%d\n",num_quote);
				break;
			default:
				break;
		}
		pos_str++;
	}
	while((char_tmp!='\0')||(pos_str<str_len));

	PRINT("num_brace_left=%d,num_brace_right=%d\n",num_brace_left,num_brace_right);
	PRINT("num_bracket_left=%d,num_bracket_right=%d\n",num_bracket_left,num_bracket_right);
	PRINT("num_quote=%d\n",num_quote);

	if(num_brace_left!=num_brace_right)
	{
		PRINT("failed : num_brace_left=%d,num_brace_right=%d\n",num_brace_left,num_brace_right);
		return -1;
	}

	if(num_bracket_left!=num_bracket_right)
	{
		PRINT("failed : num_bracket_left=%d,num_bracket_right=%d\n",num_bracket_left,num_bracket_right);
		return -1;
	}

	if((num_quote%2)!=0)
	{
		PRINT("failed : num_quote=%d\n",num_quote);
		return -1;
	}

	return 0;
}


//读取 key": 都是一样的,提取为一个函数
int find_value_from_json_str(char * json_str, int str_len, char * str_key, int len_key)
{
	int pos_str=0;

	if ( (json_str==NULL)||(str_key==NULL) )
	{
		return -1;
	}

	//1,find key
	int pos=find_str_in_buf(json_str+pos_str, str_len, str_key, len_key);
	//PRINT("%s: pos_str=%d, pos=%d\n",__func__,pos_str, pos);
	//PRINT("str is :%s\n",json_str+pos_str);
	if(pos>=0)
	{
	 	pos_str+=pos;
	}
	else
	{
		PRINT("find key failed\n");
		return -1;
	}

	//2,find the key end "
	//跳过key的长度
	pos_str+=len_key;
	pos=find_str_in_buf(json_str+pos_str, str_len-pos_str, "\"", 1);
	//PRINT("%s: find the key end \"  pos_str=%d, pos=%d\n",__func__,pos_str, pos);
	//PRINT("str is :%s\n",json_str+pos_str);
	if(pos>=0)
	{
	 	pos_str+=pos;
	}
	else
	{
		PRINT("find the key end \" failed\n");
		return -1;
	}

	//3,find :
	pos_str+=pos+1;
	pos=find_str_in_buf(json_str+pos_str, str_len-pos_str, ":", 1);
	//PRINT("%s: find : pos_str=%d, pos=%d\n",__func__,pos_str, pos);
	//PRINT("str is :%s\n",json_str+pos_str+1);
	if(pos>=0)
	{
	 	pos_str+=pos;
	}
	else
	{
		PRINT("find : failed\n");
		return -1;
	}

	//PRINT("after find , to return: %d\n", pos_str+1);
	return (pos_str+1);

}

int get_int_from_json_str(char * json_str, int str_len, char * str_key, int len_key, int *value)
{
	int pos_str=0;

	if ( (json_str==NULL)||(str_key==NULL)||(value==NULL))
	{
		return -1;
	}

	//1,find value pos
	pos_str=find_value_from_json_str(json_str, str_len, str_key, len_key);

	if(pos_str<0)
	{
		PRINT("find value failed\n");
		return -1;
	}

	//2,change the string to int
	int value_int=atoi(json_str+pos_str);
	*value=value_int;

	//PRINT("after memcpy str_value, to return: %d\n", pos_str);
	return (pos_str);
}


int get_float_from_json_str(char * json_str, int str_len, char * str_key, int len_key, float *value)
{
	int pos_str=0;

	if ( (json_str==NULL)||(str_key==NULL)||(value==NULL))
	{
		return -1;
	}

	//1,find key value
	pos_str=find_value_from_json_str(json_str, str_len, str_key, len_key);
	if(pos_str<0)
	{
		PRINT("find value failed\n");
		return -1;
	}

	//2,change the string to float
	float value_float=atof(json_str+pos_str);
	*value=value_float;

	//PRINT("after memcpy str_value, to return: %d\n", pos_str);
	return (pos_str);
}


int get_str_from_json_str(char * json_str, int str_len, char * str_key, int len_key, char * str_value, int * plen_value)
{
	int pos_str=0;
	int pos_start=0;
	int pos=0;
	int size_value=*plen_value;

	if ( (json_str==NULL)||(str_key==NULL)||(str_value==NULL))
	{
		str_value=NULL;
		return -1;
	}

	//1,find key value
	pos_str=find_value_from_json_str(json_str, str_len, str_key, len_key);
	if(pos_str<0)
	{
		PRINT("find value failed\n");
		str_value=NULL;
		return -1;
	}

	//2,find the value start "
	pos=find_str_in_buf(json_str+pos_str, str_len-pos_str, "\"", 1);
	//PRINT("%s: find the value start \" pos_str=%d, pos=%d\n",__func__,pos_str, pos);
	//PRINT("str is :%s\n",json_str+pos_str);
	if(pos>=0)
	{
	 	pos_str+=pos;
	 	pos_start=pos_str+1;
	}
	else
	{
		PRINT("find the value start \" failed\n");
		str_value=NULL;
		return -1;
	}

	//3,find the value end "
	pos_str+=pos+1;
	pos=find_str_in_buf(json_str+pos_str, str_len-pos_str, "\"", 1);
	//PRINT("%s: find the value end \" pos_str=%d, pos=%d\n",__func__,pos_str, pos);
	//PRINT("str is :%s\n",json_str+pos_str);
	if(pos>=0)
	{
	 	pos_str+=pos;
	}
	else
	{
		PRINT("find the value end \" failed\n");
		str_value=NULL;
		return -1;
	}

	if(pos_str-pos_start>=size_value)
	{
		*plen_value=size_value-1;
	}
	else
	{
		*plen_value=pos_str-pos_start;
	}
	//PRINT("to memcpy str_value: pos_str-pos_start=%d, *plen_value=%d\n",pos_str-pos_start,*plen_value);
	memcpy(str_value, json_str+pos_start, *plen_value);
	str_value[*plen_value]=0;

	//PRINT("after memcpy str_value, to return: %d\n", pos_str+1);
	return (pos_str+1);
}



int main(int argc, char **argv)
{
    int ret=-1, i;
    char str1[4096],  *str;
    int len_find=0;
    int pos;
    int len_value;
	FILE *fp;

	int flen1 = 0;
	char file_path[100];
	
	people workers[10];	
	
	
	


//parse json string

	sprintf(file_path,"json_str3.txt");// json_str1.txt, json_str2.txt, json_str3.txt, json_str4.txt
	fp = fopen(file_path, "r");
	if (NULL == fp)
	{
		printf("open file %s fail : %m.\n", file_path);
		return ret;
	}
	fseek(fp,0,SEEK_END); /* 定位到文件末尾 */
	flen1=ftell(fp); /* 得到文件大小 */
	fseek(fp,0,SEEK_SET); /* 定位到文件开头 */
	ret=fread(str1,flen1,1,fp); /* 一次性读取全部文件内容 */ /**/	
	fclose(fp);

	if(ret<=0)
	{
		PRINT("read file %s failed\n",file_path);
		return -1;
	}
	
	printf("after read file %s .\n", file_path);


	ret=judge_json_format(str1, flen1);//whether meet the Json standards
	if(ret<0)
	{
		PRINT("the json str is invalid\n");
		return -1;
	}
	else
	{		
		PRINT("the json str is valid\n\n");
	}

	
	
	
	
	pos=0;	
	str=str1;
	
	len_find=flen1;
	pos=find_value_from_json_str(str, len_find, "people", strlen("people"));	
	if(pos<0)
	{
		PRINT("find people failed \n");
		return -1;
	}
	else
	{
		PRINT("find people successful .\n" ); 			
	}
	str=str+pos;
	len_find-=pos;
	
	pos=find_str_in_buf(str, len_find, "[", strlen("["));	//  
	if(pos<0)
	{
		PRINT("find [ failed \n");
		return -1;
	}
	else
	{
		PRINT("find [ successful .\n" ); 			
	} 	
	str=str+pos;
	len_find-=(pos+1);
	

	
 	for(i=0;i<3;i++)
 	{
 		
 		//需要定义一个边界,避免搜索到下一个结构体中的内容(当前结构体中缺少某成员的赋值)。每个结构体都是{}为边界。
	 	int pos_struct_start=0;
		int pos_struct_end=0;
		int len_find_struct=0;
	
		pos=find_str_in_buf(str, len_find, "{", strlen("{"));	//  
		if(pos<0)
		{
			PRINT("find { failed \n");
			return -1;
		}
		else
		{
			PRINT("find { successful .\n" ); 			
		} 	
		str=str+pos+1;
		len_find-=(pos+1);		
		pos_struct_start=0;//the pos in str now.
		
		
		pos=find_str_in_buf(str, len_find, "}", strlen("}"));	//  
		if(pos<0)
		{
			PRINT("find } failed \n");
			return -1;
		}
		else
		{
			PRINT("find } successful .\n" ); 			
		} 	
		//str=str+pos;//just find the pos,not change str pos
		pos_struct_end=pos-1;
		len_find-=(pos+1);		
		len_find_struct =	pos_struct_end - pos_struct_start + 1;

 		
 		workers[i].id=i;
 		
 		len_value=sizeof(workers[i].firstName);
 		pos=get_str_from_json_str(str, len_find_struct, "firstName", strlen("firstName"), workers[i].firstName, &len_value);
 		if(pos<0)
 		{
 			PRINT("read firstName failed , i=%d\n",i);
 		}
 		else
 		{
 			PRINT("id=%d, firstName is %s .\n", i,workers[i].firstName); 			
 		}
	
 		len_value=sizeof(workers[i].lastName);
 		pos=get_str_from_json_str(str, len_find_struct, "lastName", strlen("lastName"), workers[i].lastName, &len_value);//str1+strlen("firstName")
 		if(pos<0)
 		{
 			PRINT("read lastName failed , i=%d\n",i);
 		}
 		else
 		{
 			PRINT("id=%d, lastName is %s .\n", i,workers[i].lastName); 			
 		}

 		 		
 		len_value=sizeof(workers[i].email);
 		pos=get_str_from_json_str(str, len_find_struct, "email", strlen("email"), workers[i].email, &len_value);//str1+strlen("lastName")
 		if(pos<0)
 		{
 			PRINT("read email failed , i=%d\n",i);
 		}
 		else
 		{
 			PRINT("id=%d, email is %s .\n", i,workers[i].email); 			
 		}

 		pos=get_int_from_json_str(str, len_find_struct, "age", strlen("age"), &(workers[i].age));
 		if(pos<0)
 		{
 			PRINT("read age failed , i=%d\n",i);
 		}
 		else
 		{
 			PRINT("id=%d, age is %d .\n", i,workers[i].age); 			
 		}

 		pos=get_float_from_json_str(str, len_find_struct, "height", strlen("height"), &(workers[i].height));
 		if(pos<0)
 		{
 			PRINT("read height failed , i=%d\n",i);
 		}
 		else
 		{ 			
 			PRINT("id=%d, height is %.02f .\n", i,workers[i].height); 			
 		}
 		
 		PRINT("id=%d,  len_find_struct=%d .\n", i,len_find_struct); 			

 		str=str+len_find_struct+1;//

 	}

	return 0;
}







 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值