月初写了一个简单的单片机json生成框架,目的是想为蓝牙开发板封装一套协议。加班了小一个月,终于有时间喘口气搞搞自己的东西了….回过头来看,发现很多不足之处,抽空进行了一些重构。主要修改了以下几个方面:
1.修改了基本的数据结构,统一抽象为 JsonPair 与 JsonObject,方便解析;
2.重新定义了内存管理模块,将结构存储与数据存储分开管理,这样方便根据不同的MCU进行相应调整;
3.重新实现了相应的方法
上一篇文章中定义的结构比较混乱,虽然可以较为容易地实现json的生成,但是解析时就会使程序变得异常混乱,所以我将json结构重新抽取为
JsonPair和JsonObject,json数组就是若干JsonObject组成。
typedef struct _JsonPair{
char *key;
char *value;
int keyLength;
int valueLength;
struct _JsonObject **obj;
int jsonObjLength;
int valueType;
struct _JsonPair *next;
//struct _JsonPair *prev;
//char* (* setPair)(struct _JsonPair *this, char *key, char *value);
//char* (* getValue)(struct _JsonPair *this, char *key);
} JsonPair;
typedef struct _JsonObject{
struct _JsonPair *jsonPair;
struct _JsonPair *lastJsonPair;
struct _JsonObject *next;
int length;
} JsonObject;
其中JsonPair即为json键值对,可以存储的值为字符串或者json数组,定义valueType用来区分jsonPair中存储内容的类型。struct _JsonObject *obj是一个jsonObject 的数组。同时JsonPair又可以串成一个链表。
我们还定义了JsonObject,里面用来存储jsonPair的链表,两个解构是递归定义的。
单片机上对内存的操作比较麻烦,我们可以直接使用数组作为内存。这样做的好处是内存地址是连续的,我们知道结构体中的地址也是连续的,也就是说我们可以直接把结构体的首地址指向一片足够大的内存,这样结构体变可存值了。定义结构体时应当注意内存对齐。此处我们优化了内存管理结构,将“存储结构的内存”和“存储数据的内存”分离开来,根据情况分别为其分配空间。
char memStructure[MEM_SIZE_STRUCTURE];
char memJsonData[MEM_SIZE_JSONDATA];
char memJsonParse[MEM_SIZE_JSONPARSEDATA];
/****************************************** *Structure Memory Manager *******************************************/
char *structureBasePtr = memStructure;
char *structureCurrPtr = memStructure;
int structureMemCnt = 0;
//malloc jsonPair
JsonPair *jsonPairMalloc(){
void *ptr = structureCurrPtr;
int size = sizeof(JsonPair);
structureMemCnt += size;
if(structureMemCnt > MEM_SIZE_STRUCTURE)
return NULL;
structureCurrPtr = structureCurrPtr + structureMemCnt;
return (JsonPair *)ptr;
}
//malloc jsonObj
JsonObject *jsonObjectMalloc(){
void *ptr = structureCurrPtr;
int size = sizeof(JsonObject);
structureMemCnt += size;
if(structureMemCnt > MEM_SIZE_STRUCTURE)
return NULL;
structureCurrPtr = structureCurrPtr + structureMemCnt;
return (JsonObject *)ptr;
}
char *structureMemFree(){
memset(memJsonData, 0, MEM_SIZE_STRUCTURE);
structureBasePtr = memJsonData;
structureCurrPtr = memJsonData;
structureMemCnt = 0;
return structureBasePtr;
}
/****************************************** *Data Memory Manager *******************************************/
char *dataBasePtr = memJsonData;
char *dataCurrPtr = memJsonData;
int dataMemIndex = 0;
//malloc json data memory
char *dataMemMalloc(int size){
char *ptr = dataCurrPtr;
dataCurrPtr = dataCurrPtr + size;
return ptr;
}
//free json data memory
char *dataMemFree(){
memset(dataBasePtr, 0, MEM_SIZE_JSONDATA);
dataBasePtr = dataBasePtr;
dataCurrPtr = dataBasePtr;
dataMemIndex = 0;
return dataBasePtr;
}
/****************************************** *Data Memory Manager *******************************************/
char *memJsonParseFree(){
memset(dataBasePtr, 0, MEM_SIZE_JSONDATA);
}
目前还不能支持多任务操作系统进行任务间切换,除非为不同任务定义不同的存储空间,否则只能顺序转换。
有了上面的示意图我们即可知道,json生成其实相当于创建一棵树,然后将其顺序转换为字符串。json的解析就是将字符串按照一定顺序取出,然后创建一棵树。
生成json
/**************************************** * generate json *****************************************/
JsonObject *createJsonObject(){
JsonObject *ptr = jsonObjectMalloc();
//json-pair header
ptr->jsonPair = NULL;
//json-pair rear
ptr->lastJsonPair = NULL;
ptr->length = 0;
return ptr;
}
//add a normal key-value pair
JsonObject *addJsonPair(JsonObject *rootObject, char *key, char *value){
JsonPair *jsonPair = jsonPairMalloc();
jsonPair->key = key;
jsonPair->keyLength = strlen(key);
jsonPair->value = value;
jsonPair->valueLength = strlen(value);
jsonPair->valueType = VALUE_TYPE_NORMALPAIR;
if(rootObject->jsonPair == NULL){
rootObject->jsonPair = jsonPair;
rootObject->lastJsonPair = jsonPair;
//jsonPair->prev = NULL;
jsonPair->next = NULL;
}else{
//jsonPair->prev = rootObject->lastJsonPair;
jsonPair->next = NULL;
rootObject->lastJsonPair->next = jsonPair;
rootObject->lastJsonPair = jsonPair;
}
rootObject->length++;
return rootObject;
}
//get json key-value as string
char *generateJsonPairString(char *mem, int *index, JsonPair *jsonPair){
char *str = NULL;
mem[(*index)++] = '"';
memcpy(mem+(*index), jsonPair->key, jsonPair->keyLength);
*index = *index + jsonPair->keyLength;
mem[(*index)++] = '"';
mem[(*index)++] = ':';
memcpy(mem+(*index), jsonPair->value, jsonPair->valueLength);
*index = *index + jsonPair->valueLength;
mem[(*index)] = '\0';
str = mem;
return str;
}
//add a json object array's address
JsonObject *addJsonObjects(JsonObject *rootObject, char *key, JsonObject **childObject){
JsonPair *jsonPair = jsonPairMalloc();
jsonPair->key = key;
jsonPair->keyLength = strlen(key);
jsonPair->obj = childObject;
//(*jsonPair->obj)->length = arrayLength;
jsonPair->valueType = VALUE_TYPE_JSONARRAY;
if(rootObject->jsonPair == NULL){
rootObject->jsonPair = jsonPair;
rootObject->lastJsonPair = jsonPair;
//jsonPair->prev = NULL;
jsonPair->next = NULL;
}else{
//jsonPair->prev = rootObject->lastJsonPair;
jsonPair->next = NULL;
rootObject->lastJsonPair->next = jsonPair;
rootObject->lastJsonPair = jsonPair;
}
rootObject->length++;
return rootObject;
}
//get json array as string
char *generateJsonArrayString(char *mem, int *index, JsonPair *jsonPair){ //JsonObject *jsonObject
char *str = NULL;
int i = 0, j = 0;
int length = 0;
mem[(*index)++] = '"';
memcpy(mem+(*index), jsonPair->key, jsonPair->keyLength);
*index = *index + jsonPair->keyLength;
mem[(*index)++] = '"';
mem[(*index)++] = ':';
mem[(*index)++] = '[';
JsonPair *jsonPairHead;
JsonObject **jsonObject = jsonPair->obj;
JsonObject *jsonObjectCurr;
jsonObjectCurr = jsonObject[0];
for(j=0; j<jsonPair->jsonObjLength; j++){
jsonPairHead = jsonObjectCurr->jsonPair;
mem[(*index)++] = '{';
while(jsonPairHead != NULL){
//JsonPair *innerJsonPair = (*jsonPairHead->obj)->jsonPair;
if(jsonPairHead->valueType == VALUE_TYPE_NORMALPAIR){
//handle normal json pair
generateJsonPairString(mem, index, jsonPairHead);
}else if(jsonPairHead->valueType == VALUE_TYPE_JSONARRAY){
//handle json array pair
generateJsonArrayString(mem, index, jsonPairHead);
}
jsonPairHead = jsonPairHead->next;
mem[(*index)++] = ',';
}
mem[(*index)-1] = '}';
mem[(*index)++] = ',';
jsonObjectCurr = jsonObjectCurr->next;
}
mem[(*index)-1] = ']';
mem[(*index)] = '\0';
str = mem;
return str;
}
//json generate function
char *generateJsonObjectString(char *mem, int *index, JsonObject *jsonObject){
char *str = NULL;
int i;
int length = jsonObject->length;
JsonPair *jsonPairPtr = jsonObject->jsonPair;
mem[(*index)++] = '{';
for(i=0; i<length; i++){
if(jsonPairPtr->valueType == VALUE_TYPE_NORMALPAIR){
generateJsonPairString(mem, index, jsonPairPtr);
}else if(jsonPairPtr->valueType == VALUE_TYPE_JSONOBJ){
}else if(jsonPairPtr->valueType == VALUE_TYPE_JSONARRAY){
generateJsonArrayString(mem, index, jsonPairPtr);
}
jsonPairPtr = jsonPairPtr->next;
mem[(*index)++] = ',';
}
mem[(*index)-1] = '}';
mem[(*index)] = '\0';
return mem;
}
解析json
JsonObject *parseJsonObject(JsonObject *rootJsonObject, char *mem, char* jsonObjectStr, int *index){
int innerIndex = 0;
int keyValueIndex = 0;
int keyLength = 0;
int valueLength = 0;
int i = 0;
int startKeyValueFlag = 0;
int mesureKeyLengthFlag = 0;
char *keyStr = NULL;
char *valueStr = NULL;
int type = -1;
int arrayLength = 0;
rootJsonObject->jsonPair = NULL;
rootJsonObject->lastJsonPair = NULL;
rootJsonObject->length = 0;
rootJsonObject->next = NULL;
while(jsonObjectStr[i] != '\0'){
if(jsonObjectStr[i] == '"' && startKeyValueFlag == 0){
startKeyValueFlag = 1;
}
if(startKeyValueFlag){ //start to parse key-value pair
mesureKeyLengthFlag = 1;
keyValueIndex = 0;
keyLength = 0;
valueLength = 0;
while(jsonObjectStr[i+keyValueIndex] != ',' && jsonObjectStr[i+keyValueIndex] != '}'){
if(jsonObjectStr[i+keyValueIndex] == '"'){ //measure length of key
keyValueIndex++;
}
if(jsonObjectStr[i+keyValueIndex] == ':'){ //measure length of value
mesureKeyLengthFlag = 0;
}
if(mesureKeyLengthFlag){
keyLength++;
}else{
valueLength++;
}
keyValueIndex++;
}
valueLength = valueLength - 1; //skip ','
innerIndex = i;
//fetch key string
keyLength = keyLength;
keyStr = copyString(mem+(*index), &jsonObjectStr[i+1], keyLength);
*index += (keyLength+2);
//fetch value string
valueStr = copyString(mem+(*index), &jsonObjectStr[i+keyLength+3],valueLength);
*index += (valueLength+1); //avoid other string rewrite the value's last '\0'
type = getStringType(valueStr);
//create a jsonPair and add this jsonPair to the rootJsonObject
JsonPair *jsonPair = jsonPairMalloc();
jsonPair->key = keyStr;
jsonPair->keyLength = strlen(keyStr);
jsonPair->next = NULL;
if(type == VALUE_TYPE_NORMALPAIR){
jsonPair->value = valueStr;
}else if(type == VALUE_TYPE_JSONOBJ){
}else if(type == VALUE_TYPE_JSONARRAY){
//TODO
//JsonObject *jsonObject =
}
jsonPair->valueType = type;
if(rootJsonObject->jsonPair == NULL){
rootJsonObject->jsonPair = jsonPair;
rootJsonObject->lastJsonPair = rootJsonObject->jsonPair;
}else{
rootJsonObject->lastJsonPair->next = jsonPair;
rootJsonObject->lastJsonPair = rootJsonObject->lastJsonPair->next;
}
i += keyValueIndex;
startKeyValueFlag = 0;
}else{
i++;
}
}
return mem;
}
生成json
char* testNewJsonGenerateUtil(){
dataMemIndex = 0;
JsonObject *rootJsonObject = createJsonObject();
//add key-value pair
addJsonPair(rootJsonObject, "key1", "value1");
addJsonPair(rootJsonObject, "key2", "value2");
addJsonPair(rootJsonObject, "key3", "value3");
//add json array
JsonObject *jsonObject0 = createJsonObject();
addJsonPair(jsonObject0, "key40", "value40");
addJsonPair(jsonObject0, "key50", "value50");
JsonObject *jsonObject1 = createJsonObject();
addJsonPair(jsonObject1, "key41", "value41");
addJsonPair(jsonObject1, "key51", "value51");
jsonObject0->next = jsonObject1;
addJsonObjects(rootJsonObject, "key_arr1", &jsonObject0);
rootJsonObject->lastJsonPair->jsonObjLength = 2;
//generate json string
char *str = generateJsonObjectString(dataBasePtr, &dataMemIndex, rootJsonObject);
//clear memory
//structureMemFree();
//dataMemFree();
printf("json string: \n");
printf(str);
return str;
}
解析生成的json(目前不能解析数组)
void testNewJsonParseUtil(char *jsonStr){
JsonObject *rootJsonObject = createJsonObject();
int index = 0;
char *str = parseJsonObject(rootJsonObject, memJsonParse, jsonStr, &index);
printf("\n\njson data:\n");
printf(rootJsonObject->jsonPair->key);
printf("\n");
printf(rootJsonObject->jsonPair->value);
printf("\n");
printf(rootJsonObject->jsonPair->next->key);
printf("\n");
printf(rootJsonObject->jsonPair->next->value);
printf("\n");
printf(rootJsonObject->jsonPair->next->next->key);
printf("\n");
printf(rootJsonObject->jsonPair->next->next->value);
printf("\n\n");
//clear memory
//structureMemFree();
//memJsonParseFree();
//dataMemFree();
}
目前还没有处理换行等一些问题,有时间了继续完善。
代码托管地址:
https://git.oschina.net/vonchenchen/Embed_C_JSON_Utils.git