最近要修改一款海外的多语言主机,涉及到了语言的导入功能。
主机采用的是U盘导入.txt文件的方式,文件内容则是参照json格式,存到自身的flash当中。
JSON格式
先了解一下Jason的格式。
JSON 名称/值对
名称/值对包括字段名称(在双引号中),后面写一个冒号,然后是值:
key : value
例如 “encode”:“UTF-8” ,等价于encode = “UTF-8”
JSON 值
JSON 值可以是:
- 数字(整数或浮点数)
- 字符串(在双引号中)
- 逻辑值(true 或 false)
- 数组(在中括号中)
- 对象(在大括号中)
- null
JSON 数字
JSON 数字可以是整型或者浮点型:
{ “age”:30 }
JSON 对象
JSON 对象在大括号 {} 中书写:
{key1 : value1, key2 : value2, … keyN : valueN }
对象可以包含多个名称/值对:
例如:{ “encode”:“UTF-8”,“language”:“Türkiye”},等价于encode = “UTF-8”,language = “Türkiye”
JSON 数组
JSON 数组在中括号 [] 中书写,数组可包含多个对象:
[
{ key1 : value1-1 , key2:value1-2 },
{ key1 : value2-1 , key2:value2-2 },
{ key1 : value3-1 , key2:value3-2 },
…
{ keyN : valueN-1 , keyN:valueN-2 },
]
例如对象 sites 是包含三个对象的数组。每个对象代表一条关于某个网站(name、url)的记录:
{
“sites”: [
{ “name”:“百度” , “url”:“www.baidu.com” },
{ “name”:“google” , “url”:“www.google.com” },
{ “name”:“微博” , “url”:“www.weibo.com” }
]
}
C语言中的JSON库
C语言中有解析json的函数库,这个函数库就是cJSON了。自己使用时可以只需要其中的cJSON.c和cJSON.h文件就可以了,只需要将cJSON和自己的main文件一起编译即可。
cJSON 中有个很重要的结构体,用于存储JSON的数据,使用数据结构链表的方式来存储js对象:
typedef struct cJSON {
struct cJSON next,prev; / 遍历数组或对象链的前向或后向链表指针/
struct cJSON child; /数组或对象的孩子节点/
int type; / key的类型*/
char valuestring; /字符串值/
int valueint; / 整数值*/
double valuedouble; /* 浮点数值*/
char string; / key的名字*/
} cJSON;
说明:
1、cJSON是使用链表来存储数据的,其访问方式很像一颗树。每一个节点可以有兄弟节点,通过next/prev指针来查找,它类似双向链表;每个节点也可以有孩子节点,通过child指针来访问,进入下一层。只有节点是对象或数组时才可以有孩子节点。
2、type是键(key)的类型,一共有7种取值,分别是:False,Ture,NULL,Number,String,Array,Object。
若是Number类型,则valueint或valuedouble中存储着值。若期望的是int,则访问valueint,若期望的是double,则访问valuedouble,可以得到值。
若是String类型的,则valuestring中存储着值,可以访问valuestring得到值。
3、string中存放的是这个节点的名字,可理解为key的名称。
接口函数:
-
cJSON *cJSON_Parse(const char *value);
解析JSON数据包,并按照cJSON结构体的结构序列化整个数据包。可以看做是获取一个句柄。 -
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
功能:获取json指定的对象成员
参数:*objec:第一个函数中获取的句柄。
string:需要获取的对象
返回值:这个对象成员的句柄 如果json格式的对象成员直接就是字符串那么就可以直接通过结构体中的valuestring元素来获取这个成员的值 -
cJSON *cJSON_GetArrayItem(cJSON *array,int item);
功能:有可能第二个函数中获取到的是成员对象值是一个数组,那么就需要用到这个函数。用来获取这个数组指定的下标对象。
参数:*array:传入第二步中返回的值
item:想要获取这个数组的下标元素
返回值:这个数组中指定下标的对象。然后在对这个返回值重复使用第二步函数就可以获取到各个成员的值了。
也就是说对象是数组的比是字符串的要多用一个cJSON_GetArrayItem函数,其他的没区别。 -
int cJSON_GetArraySize(cJSON *array);
获取cjson对象数组成员的个数。 -
cJSON_Delete()
用来释放你第一步获取的句柄,来释放整个内存。用在解析完后调用。
例程
一般读取的流程如下:
(1)调用cJSON_Parse()函数,解析JSON数据包。
(2)调用一次cJSON_GetObjectItem()函数,获取到数组mainmenu。
(3)对我们刚取出来的数组mainmenu,调用cJSON_GetArraySize()函数,来获取数组中对象的个数。然后,多次调用cJSON_GetArrayItem()函数,逐个读取数组中对象的内容。
(4)通过cJSON_Delete(),释放cJSON_Parse()分配出来的内存空间。
下面是一个二维的jason数据的读取,类似于二维数组的读取:
/* 输入的MENU.TXT文件 */
{
"devicename":"VIVA FCP YANGIN KONTROL PANELI",
"mainmenu":
[
{
"name":"Sub1",
"menus":["menu1","menu2","menu3"]
},
{
"name":"Sub2",
"menus":["menu4","menu5","menu6"]
}
]
}
int read_data()
{
INT8U * pbuf = NULL;
int num,filelen = 0;
FILERES ret; //文件操作返回值
cJSON *pJson;
ret = Main_Read2("MENU.TXT", pbuf, &filelen); //一个读取函数,把menu.txt的内容拷到pbuf
pJson = cJSON_Parse(pbuf); //获取json文件句柄
if (pJson == NULL)
{
Uart0_Printf("xxx,JSON PARSE failed! \r\n");
return -1;
}
cJSON pDeviceName = cJSON_GetObjectItem(pJson, "devicename"); //获取“devicename”的值,此值是一个字符串
printf("output devicename:%s \n",pDeviceName->valuestring);
cJSON pMainmenu = cJSON_GetObjectItem(pJson, "mainmenu"); //获取"mainmenu"的值,此值是一个数组
num = cJSON_GetArraySize(pMainmenu); //获取“pMainmenu”数组成员的个数
for (int i = 0; i < num; i++)
{
cJSON pSub = cJSON_GetArrayItem(pMainmenu, i); //获取“pMainmenu”组中的第i个成员的内容句柄
cJSON pName = cJSON_GetObjectItem(pSub ,"name"); //读取“pMainmenu”数组中的第i个成员,里面名为"name"的值,此值是个字符串
printf("output subname:%s \n",pName->valuestring);
cJSON pMenus = cJSON_GetObjectItem(pSub,"menus"); //读取“pMainmenu”数组中的第i个成员,里面名为"menus"的值,此值是个数组
int subnum = cJSON_GetArraySize(pMenus); //获取"pMenus"数组成员的个数
for (int j = 0; j < subnum; j++)
{
cJSON pMenu = cJSON_GetArrayItem(pMenus, i); //获取“pMenus”组中的第i个成员的内容句柄
printf("Menu name:%s \n",pMenu->valuestring);
}
}
}
输出的结果为:
output devicename:VIVA FCP YANGIN KONTROL PANELI
output subname:Sub1
Menu name:menu1
Menu name:menu2
Menu name:menu3
output subname:Sub2
Menu name:menu4
Menu name:menu5
Menu name:menu6