单片机Json框架的实现

背景

月初写了一个简单的单片机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的链表,两个解构是递归定义的。

下图为基本结构
单片机Json框架的实现_第1张图片

内存管理

单片机上对内存的操作比较麻烦,我们可以直接使用数组作为内存。这样做的好处是内存地址是连续的,我们知道结构体中的地址也是连续的,也就是说我们可以直接把结构体的首地址指向一片足够大的内存,这样结构体变可存值了。定义结构体时应当注意内存对齐。此处我们优化了内存管理结构,将“存储结构的内存”和“存储数据的内存”分离开来,根据情况分别为其分配空间。

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的解析就是将字符串按照一定顺序取出,然后创建一棵树。

生成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();
}

单片机Json框架的实现_第2张图片

目前还没有处理换行等一些问题,有时间了继续完善。

代码托管地址:
https://git.oschina.net/vonchenchen/Embed_C_JSON_Utils.git

你可能感兴趣的:(数据结构,json,框架,数据存储,单片机)