美文网首页
json解析器kajson

json解析器kajson

作者: 客昂康 | 来源:发表于2019-05-07 13:06 被阅读0次

    我需要IP定位功能,很多IP定位API使用HTTP或HTTPS协议,返回的数据是json格式,例如百度IP定位API:
    请求格式:
    http://api.map.baidu.com/location/ip?ip=xx.xx.xx.xx&ak=xxxxxxxxxx&coor=bd09ll
    https://api.map.baidu.com/location/ip?ip=xx.xx.xx.xx&ak=xxxxxxxxxx&coor=bd09ll
    参数ip就是要查询的IP,参数ak是向百度申请的开发者密钥。
    返回格式:

    {
        "address": "CN|北京|北京|None|CHINANET|1|None",    //详细地址信息
        "content": {                                       //结构信息
            "address": "北京市",                           //简要地址信息
            "address_detail": {                            //结构化地址信息
                "city": "北京市",                          //城市
                "city_code": 131,                          //百度城市代码
                "district": "",                            //区县
                "province": "北京市",                      //省份
                "street": "",                              //街道
                "street_number": ""                        //门牌号
            },  
            "point": {                                     //当前城市中心点
                "x": "116.39564504",                       //当前城市中心点经度
                "y": "39.92998578"                         //当前城市中心点纬度
            }
        },
        "status": 0                                        //结果状态返回码
    }
    

    因此我还需要json解析器。根据对json的理解,写下这个json解析器,命名为kajson,读作"咔json"。kajson并没有完全符合标准json格式,标准json见json官网

    • 内存管理模块
      json是可递归的树状结构,节点多而杂,如果每个节点都用 malloc()这样的函数分配内存,不但造成大量内存碎片,而且频繁调用malloc()也会影响效率。内存管理模块的策略是,一次分配一块较大内存,比如4k,然后从上面切下一小片使用,比如40字节,切完后再次分配一大块,代码如下:

    kajsonMem.h

    //==============================================================================
    //  Copyright (C) 2019 王小康. All rights reserved.
    //
    //  作者: 王小康
    //  描述: kajson内存管理模块
    //  日期: 2019-05-07
    //
    //==============================================================================
    
    #ifndef _KAJSON_MEM_H_
    #define _KAJSON_MEM_H_
    
    #define KAJSON_MEM_BLOCK_SIZE   (1024*4)
    #define KAJSON_MEM_BLOCK_NUMB   (256)
    
    typedef struct {
        unsigned char *buffer;
        unsigned int   offset;
    } KAJSON_MEM_BLOCK;
    
    typedef struct {
        unsigned int      blockNum;
        KAJSON_MEM_BLOCK  blocks[KAJSON_MEM_BLOCK_NUMB];
    } KAJSON_MEM_CTX;
    
    void  kajsonMem_init  (KAJSON_MEM_CTX *ctx);                         //初始化,并预先分配一个内存块。
    void  kajsonMem_uninit(KAJSON_MEM_CTX *ctx);                         //去初始化,释放所有内存块。
    void  kajsonMem_clean (KAJSON_MEM_CTX *ctx);                         //清零,不释放内存块,仅仅将所有已分配内存块设置成未使用。
    void* kajsonMem_alloc (KAJSON_MEM_CTX *ctx, unsigned int allocSize); //从内存块上切下一小块内存,4字节对齐。如果内存块不够就重新分配内存块。达到极限返回NULL。
    
    #endif
    
    

    kajsonMem.c

    //==============================================================================
    //  Copyright (C) 2019 王小康. All rights reserved.
    //
    //  作者: 王小康
    //  描述: kajson内存管理模块
    //  日期: 2019-05-07
    //
    //==============================================================================
    
    #include <stdlib.h>
    #include <string.h>
    #include "kajsonMem.h"
    
    void kajsonMem_init(KAJSON_MEM_CTX *ctx){
        memset(ctx, 0, sizeof(KAJSON_MEM_CTX));
        ctx->blocks[0].buffer = malloc(KAJSON_MEM_BLOCK_SIZE);
        if(ctx->blocks[0].buffer) ctx->blockNum = 1;
    }
    
    void kajsonMem_uninit(KAJSON_MEM_CTX *ctx){
        unsigned int i;
        for(i=0; i<ctx->blockNum; i++){
            if(ctx->blocks[i].buffer){
                free(ctx->blocks[i].buffer);
            }
            ctx->blocks[i].buffer = NULL;
            ctx->blocks[i].offset = 0;
        }
        ctx->blockNum = 0;
    }
    
    void kajsonMem_clean(KAJSON_MEM_CTX *ctx){
        unsigned int i;
        for(i=0; i<ctx->blockNum; i++){
            ctx->blocks[i].offset = 0;
        }
    }
    
    void* kajsonMem_alloc(KAJSON_MEM_CTX *ctx, unsigned int allocSize){
        allocSize = (allocSize + 3) & (~3);
        if(allocSize <= KAJSON_MEM_BLOCK_SIZE){
            unsigned int i;
            KAJSON_MEM_BLOCK *block;
            for(i=0; i<ctx->blockNum; i++){
                block = &(ctx->blocks[i]);
                if(allocSize <= (KAJSON_MEM_BLOCK_SIZE - block->offset)){
                    void *p = block->buffer + block->offset;
                    block->offset += allocSize;
                    return p;
                }
            }
            if(ctx->blockNum >= KAJSON_MEM_BLOCK_NUMB) return NULL;
            block = &(ctx->blocks[ctx->blockNum]);
            block->buffer = malloc(KAJSON_MEM_BLOCK_SIZE);
            if(block->buffer){
                block->offset = allocSize;
                ctx->blockNum += 1;
                return block->buffer;
            }
            else{
                return NULL;
            }
        }
        else{
            return NULL;
        }
    }
    
    
    • kajson解析器
      kajson.h
    //==============================================================================
    //  Copyright (C) 2019 王小康. All rights reserved.
    //
    //  作者: 王小康
    //  描述: kajson解析器
    //  日期: 2019-05-07
    //
    //==============================================================================
    
    #ifndef _KAJSON_H_
    #define _KAJSON_H_
    
    #include "kajsonMem.h"
    
    #define  KAJSON_TYPE_ROOT      1
    #define  KAJSON_TYPE_STRING    2
    #define  KAJSON_TYPE_INTEGER   3
    #define  KAJSON_TYPE_FLOAT     4
    #define  KAJSON_TYPE_BOOLE     5
    #define  KAJSON_TYPE_OBJECT    6
    #define  KAJSON_TYPE_ARRAY     7
    
    typedef struct objectNode {
        char              *key;          //键名字符串
        void              *value;        //值,字符串、整数、浮点数、布尔、对象、数组、null 中任意类型。
        struct objectNode *next;         //下一个节点
    } KAJSON_OBJECT_NODE;                //对象中成员列表节点
    
    typedef struct arrayNode {
        void             *value;         //值,字符串、整数、浮点数、布尔、对象、数组、null 中任意类型。
        struct arrayNode *next;          //下一个节点
    } KAJSON_ARRAY_NODE;                 //数组中成员列表节点
    
    typedef struct {
        unsigned short  type;            //类型
        unsigned short  strLeng;         //字符串长度
        char           *value;           //字符串地址
    } KAJSON_STRING;                     //字符串类型
    
    typedef struct {
        unsigned short  type;            //类型
        unsigned short  xxxx;            //
        int             value;           //整数值
    } KAJSON_INTEGER;                    //整数类型
    
    typedef struct {
        unsigned short  type;            //类型
        unsigned short  xxxx;            //
        float           value;           //浮点值
    } KAJSON_FLOAT;                      //浮点类型
    
    typedef struct {
        unsigned short  type;            //类型
        unsigned short  value;           //布尔值
    } KAJSON_BOOLE;                      //布尔类型
    
    typedef struct {
        unsigned short       type;       //类型
        unsigned short       number;     //成员个数
        KAJSON_OBJECT_NODE  *head;       //对象节点链表头。
        KAJSON_OBJECT_NODE  *tail;       //对象节点链表尾。
    } KAJSON_OBJECT;                     //对象类型
    
    typedef struct {
        unsigned short      type;        //类型
        unsigned short      number;      //成员个数
        KAJSON_ARRAY_NODE  *head;        //数组节点链表头。
        KAJSON_ARRAY_NODE  *tail;        //数组节点链表尾。
    } KAJSON_ARRAY;                      //数组类型
    
    typedef struct {
        unsigned short  type;            //类型
        unsigned short  xxxx;            //
        void           *value;           //根节点,字符串、整数、浮点数、布尔、对象、数组、null 中任意类型。
        KAJSON_MEM_CTX  memCtx;          //对象中所有子孙后代成员的物理位置
    } KAJSON_CTX;                        //kajson结构、kajson环境、json树根节点。
    
    void  kajson_init         (KAJSON_CTX *jsonCtx);             //json结构初始化,会预先分配一个内存块。
    void  kajson_uninit       (KAJSON_CTX *jsonCtx);             //json结构去初始化,会释放所有内存块。
    void  kajson_clean        (KAJSON_CTX *jsonCtx);             //清空json树结构,并标记所有内存块为未分配。
    char* kajson_stringToJson (KAJSON_CTX *jsonCtx, char *src);  //将字符串转换成json结构,成功返回src字符串中json的结束地址,失败返回NULL。失败原因可能是格式不对或内存不够。
    int   kajson_getOutSize   (void *json);                      //使用 kajson_jsonToString() 之前可以用以计算输出buffer大小。
    int   kajson_jsonToString (void *json, char *out);           //将json结构转换成字符串,返回转换后的字节数。可以先通过 kajson_getOutSize() 计算输出buffer大小。
    void* kajson_search       (void *json, char *path);          //查询,可以从json树的任意位置开始查询,可以查询json树中除root以外的任意类型。
    
    #if 0
    //假设有如下json对象:
    {
        "name": "张三",
        "age": 25,
        "city": "武汉市",
        "friends": [
            {"name": "李四", "age": 26, "city": "北京市"},
            {"name": "王五", "age": 25, "city": "杭州市"},
            {"name": "赵六", "age": 24, "city": "上海市"}
        ]
    }
    
    //查询方法:
    void *value = kajson_search(&json, ".name");             // 查询张三的名字
    void *value = kajson_search(&json, ".friends[0].name");  // 查询张三的第1个朋友的名字
    void *value = kajson_search(&json, ".friends[2].age");   // 查询张三的第3个朋友的年龄
    
    //还支持这样查询,暂且叫做"分步查询":
    void *value = kajson_search(kajson_search(&json, ".friends"), "[0].name");                      // 查询张三的第1个朋友的名字
    void *value = kajson_search(kajson_search(&json, ".friends[0]"), ".name");                      // 查询张三的第1个朋友的名字
    void *value = kajson_search(kajson_search(kajson_search(&json, ".friends"), "[0]"), ".name");   // 查询张三的第1个朋友的名字
    
    //为什么要支持"分步查询"呢?假如同时查询张三的第3个朋友的名字、年龄和所在地,"分步查询"速度更快。
    
    //非"分步查询":
    void *name = kajson_search(&json, ".friends[2].name");    // 查询张三的第3个朋友的名字
    void *age  = kajson_search(&json, ".friends[2].age");     // 查询张三的第3个朋友的年龄
    void *city = kajson_search(&json, ".friends[2].city");    // 查询张三的第3个朋友的所在地
    
    //"分步查询":
    void *frie = kajson_search(&json, ".friends[2]");   // 查询张三的第3个朋友
    void *name = kajson_search(frie, ".name");          // 查询张三的第3个朋友的名字
    void *age  = kajson_search(frie, ".age");           // 查询张三的第3个朋友的年龄
    void *city = kajson_search(frie, ".city");          // 查询张三的第3个朋友的所在地
    #endif
    
    #endif
    
    

    kajson.c

    //==============================================================================
    //  Copyright (C) 2019 王小康. All rights reserved.
    //
    //  作者: 王小康
    //  描述: kajson解析器
    //  日期: 2019-05-07
    //
    //==============================================================================
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include "kajsonMem.h"
    #include "kajson.h"
    
    ////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////// 字符串转json结构 /////////////////////////////////
    
    static KAJSON_STRING* newString(KAJSON_MEM_CTX *memCtx, char *value){
        KAJSON_STRING *string = kajsonMem_alloc(memCtx, sizeof(KAJSON_STRING));
        if(string == NULL) return NULL;
        string->type = KAJSON_TYPE_STRING;
        string->strLeng = ((value)&&(value[0])) ? strlen(value) : 0;
        string->value = value;
        return string;
    }
    
    static KAJSON_INTEGER* newInteger(KAJSON_MEM_CTX *memCtx, int value){
        KAJSON_INTEGER *integer = kajsonMem_alloc(memCtx, sizeof(KAJSON_INTEGER));
        if(integer == NULL) return NULL;
        integer->type = KAJSON_TYPE_INTEGER;
        integer->value = value;
        return integer;
    }
    
    static KAJSON_FLOAT* newFloat(KAJSON_MEM_CTX *memCtx, float value){
        KAJSON_FLOAT *floa = kajsonMem_alloc(memCtx, sizeof(KAJSON_FLOAT));
        if(floa == NULL) return NULL;
        floa->type = KAJSON_TYPE_FLOAT;
        floa->value = value;
        return floa;
    }
    
    static KAJSON_BOOLE* newBoole(KAJSON_MEM_CTX *memCtx, int value){
        KAJSON_BOOLE *boole = kajsonMem_alloc(memCtx, sizeof(KAJSON_BOOLE));
        if(boole == NULL) return NULL;
        boole->type = KAJSON_TYPE_BOOLE;
        boole->value = value ? 1 : 0;
        return boole;
    }
    
    static KAJSON_OBJECT* newObject(KAJSON_MEM_CTX *memCtx, KAJSON_OBJECT_NODE *node){
        KAJSON_OBJECT *object = kajsonMem_alloc(memCtx, sizeof(KAJSON_OBJECT));
        if(object == NULL) return NULL;
        object->type = KAJSON_TYPE_OBJECT;
        object->head = node;
        object->tail = node;
        if(node) object->number = 1;
        else     object->number = 0;
        return object;
    }
    
    static KAJSON_ARRAY* newArray(KAJSON_MEM_CTX *memCtx, KAJSON_ARRAY_NODE *node){
        KAJSON_ARRAY *array = kajsonMem_alloc(memCtx, sizeof(KAJSON_ARRAY));
        if(array == NULL) return NULL;
        array->type = KAJSON_TYPE_ARRAY;
        array->head = node;
        array->tail = node;
        if(node) array->number = 1;
        else     array->number = 0;
        return array;
    }
    
    static KAJSON_OBJECT_NODE* newObjectNode(KAJSON_MEM_CTX *memCtx, char *key, void *value){
        KAJSON_OBJECT_NODE *node = kajsonMem_alloc(memCtx, sizeof(KAJSON_OBJECT_NODE));
        if(node == NULL) return NULL;
        node->key = key;
        node->value = value;
        node->next = NULL;
        return node;
    }
    
    static KAJSON_ARRAY_NODE* newArrayNode(KAJSON_MEM_CTX *memCtx, void *value){
        KAJSON_ARRAY_NODE *node = kajsonMem_alloc(memCtx, sizeof(KAJSON_ARRAY_NODE));
        if(node == NULL) return NULL;
        node->value = value;
        node->next = NULL;
        return node;
    }
    
    static void addObjectNode(KAJSON_OBJECT *object, KAJSON_OBJECT_NODE *node){
        object->number += 1;
        if(object->head) object->tail->next = node;
        else object->head = node;
        object->tail = node;
    }
    
    static void addArrayNode(KAJSON_ARRAY *array, KAJSON_ARRAY_NODE *node){
        array->number += 1;
        if(array->head) array->tail->next = node;
        else array->head = node;
        array->tail = node;
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    
    //判断是否遇到终止符
    #define isTerminatorSymbol(c)  (((c)==',')||(((c)>0)&&((c)<=' '))||((c)=='}')||((c)==']'))
    
    // 忽略连续的空白符,这里将(0 ~ ' ']之间的所有字符都当做空白符。
    static char* skipOverBlank(char *src){
        while(*src){
            if((*src > 0) && (*src <= ' ')) src++;
            else if((*src > ' ') && (*src <= '~')) return src;
            else return NULL;
        }
        return NULL;
    }
    
    // 生成字符串结构,不支持转义字符,字符串中允许出现除 '"' 以外的所有字符。
    static char* makeString(KAJSON_STRING **string, KAJSON_MEM_CTX *memCtx, char *src){
        char *start = src;
        int length = 0;
        while(*src){
            if(*src != '\"'){
                length++;
                src++;
            }
            else{
                char* strValue = kajsonMem_alloc(memCtx, length+1);
                if(strValue == NULL) return NULL;
                memcpy(strValue, start, length);
                strValue[length] = 0;
                KAJSON_STRING *str = newString(memCtx, strValue);
                if(str == NULL) return NULL;
                *string = str;
                return src+1;
            }
        }
        return NULL;
    }
    
    // 生成整数结构或浮点数结构
    static char* makeIntegerOrFloat(void **number, KAJSON_MEM_CTX *memCtx, char *src){
        int flag = 0;  //(0=正数,1=负数。) | (0=整数,2=浮点数) 
        if(*src == '-'){
            flag = 1;
            src = skipOverBlank(src+1);
        }
        else if(*src == '+'){
            src = skipOverBlank(src+1);
        }
        if(src == NULL) return NULL;
        
        char *start = src;
        int length = 0;
        while(*src){
            if((*src >= '0') && (*src <= '9')){
                length++;
                src++;
            }
            else if(*src == '.'){
                if(flag&2){
                    return NULL;
                }
                else{
                    flag |= 2;
                    length++;
                    src++;
                }
            }
            else if(isTerminatorSymbol(*src)){
                char *numberBuffer = alloca(length+1);
                memcpy(numberBuffer, start, length);
                numberBuffer[length] = 0;
                if(flag&2){
                    float value = (flag&1) ? -atof(numberBuffer) : atof(numberBuffer);
                    KAJSON_FLOAT *floa = newFloat(memCtx, value);
                    if(floa == NULL) return NULL;
                    *number = floa;
                }
                else{
                    int value = (flag&1) ? -atoi(numberBuffer) : atoi(numberBuffer);
                    KAJSON_INTEGER *integer = newInteger(memCtx, value);
                    if(integer == NULL) return NULL;
                    *number = integer;
                }
                return src;
            }
            else{
                return NULL;
            }
        }
        return NULL;
    }
    
    // 生成键值对的键,这里的键中字符的范围是 52个英文字符 + 10个数字字符 + 下划线。
    static char* makeKey(char **key, KAJSON_MEM_CTX *memCtx, char *src){
        char *start = src;
        int length = 0;
        while(*src){
            if(((*src>='a')&&(*src<='z')) || ((*src>='A')&&(*src<='Z')) || ((*src>='0')&&(*src<='9')) || (*src=='_')){
                length++;
                src++;
            }
            else if(*src == '\"'){
                char *keyBuffer = kajsonMem_alloc(memCtx, length+1);
                if(keyBuffer == NULL) return NULL;
                memcpy(keyBuffer, start, length);   //start没有以0结尾,不能用strcpy()
                keyBuffer[length] = 0;
                *key = keyBuffer;
                return src+1;
            }
            else{
                return NULL;
            }
        }
        return NULL;
    }
    
    static char* makeValue(void **value, KAJSON_MEM_CTX *memCtx, char *src);
    
    // 生成对象的一个成员节点
    static char* makeObjectNode(KAJSON_OBJECT_NODE **node, KAJSON_MEM_CTX *memCtx, char *src){
        // 提取键
        char *key = NULL;
        src = makeKey(&key, memCtx, src);
        if(src == NULL) return NULL;
        
        // 寻找键值分割符':'
        src = skipOverBlank(src);
        if(src == NULL) return NULL;
        if(*src != ':') return NULL;
        src = skipOverBlank(src+1);
        if(src == NULL) return NULL;
        
        // 提取值
        void *value = NULL;
        src = makeValue(&value, memCtx, src);
        if(src == NULL) return NULL;
        
        // 生成对象节点并返回
        KAJSON_OBJECT_NODE *objectNode = newObjectNode(memCtx, key, value);
        if(objectNode == NULL) return NULL;
        *node = objectNode;
        return src;
    }
    
    // 生成数组的一个成员节点
    static char* makeArrayNode(KAJSON_ARRAY_NODE **node, KAJSON_MEM_CTX *memCtx, char *src){
        // 提取值
        void *value = NULL;
        src = makeValue(&value, memCtx, src);
        if(src == NULL) return NULL;
        
        // 生成数组节点并返回
        KAJSON_ARRAY_NODE *arrayNode = newArrayNode(memCtx, value);
        if(arrayNode == NULL) return NULL;
        *node = arrayNode;
        return src;
    }
    
    // 生成对象
    static char* makeObject(KAJSON_OBJECT **object, KAJSON_MEM_CTX *memCtx, char *src){
        KAJSON_OBJECT *obj = newObject(memCtx, NULL);
        if(obj == NULL) return NULL;
        
        int status = 0;
        KAJSON_OBJECT_NODE *node;
        for(;;){
            src = skipOverBlank(src);
            if(src == NULL) return NULL;
            
            if(status == 0){
                if(*src == '\"'){
                    src = makeObjectNode(&node, memCtx, src+1);
                    if(src == NULL) return NULL;
                    addObjectNode(obj, node);
                    status = 1;
                }
                else if(*src == '}'){
                    *object = obj;
                    return src+1;
                }
                else{
                    return NULL;
                }
            }
            else if(status == 1){
                if(*src == ','){
                    src += 1;
                    status = 2;
                }
                else if(*src == '}'){
                    *object = obj;
                    return src+1;
                }
                else{
                    return NULL;
                }
            }
            else{
                if(*src == '\"'){
                    src = makeObjectNode(&node, memCtx, src+1);
                    if(src == NULL) return NULL;
                    addObjectNode(obj, node);
                    status = 1;
                }
                else{
                    return NULL;
                }
            }
        }
    }
    
    // 生成数组
    static char* makeArray(KAJSON_ARRAY **array, KAJSON_MEM_CTX *memCtx, char *src){
        KAJSON_ARRAY *arr = newArray(memCtx, NULL);
        if(arr == NULL) return NULL;
        
        int status = 0;
        KAJSON_ARRAY_NODE *node;
        for(;;){
            src = skipOverBlank(src);
            if(src == NULL) return NULL;
            
            if(status == 0){
                if(*src == ']'){
                    *array = arr;
                    return src+1;
                }
                else{
                    src = makeArrayNode(&node, memCtx, src);
                    if(src == NULL) return NULL;
                    addArrayNode(arr, node);
                    status = 1;
                }
            }
            else if(status == 1){
                if(*src == ','){
                    src += 1;
                    status = 2;
                }
                else if(*src == ']'){
                    *array = arr;
                    return src+1;
                }
                else{
                    return NULL;
                }
            }
            else{
                if(*src != ']'){
                    src = makeArrayNode(&node, memCtx, src);
                    if(src == NULL) return NULL;
                    addArrayNode(arr, node);
                    status = 1;
                }
                else{
                    return NULL;
                }
            }
        }
    }
    
    // 生成键值对的值。
    static char* makeValue(void **value, KAJSON_MEM_CTX *memCtx, char *src){
        if(*src == '\"'){
            KAJSON_STRING *str = NULL;
            src = makeString(&str, memCtx, src+1);
            if(src == NULL) return NULL;
            *value = str;
            return src;
        }
        else if(*src == '{'){
            KAJSON_OBJECT *obj = NULL;
            src = makeObject(&obj, memCtx, src+1);
            if(src == NULL) return NULL;
            *value = obj;
            return src;
        }
        else if(*src == '['){
            KAJSON_ARRAY *arr = NULL;
            src = makeArray(&arr, memCtx, src+1);
            if(src == NULL) return NULL;
            *value = arr;
            return src;
        }
        else if((src[0]=='t')&&(src[1]=='r')&&(src[2]=='u')&&(src[3]=='e')&&(isTerminatorSymbol(src[4]))){
            KAJSON_BOOLE *boo = newBoole(memCtx, 1);
            if(boo == NULL) return NULL;
            *value = boo;
            return src+4;
        }
        else if((src[0]=='f')&&(src[1]=='a')&&(src[2]=='l')&&(src[3]=='s')&&(src[4]=='e')&&(isTerminatorSymbol(src[5]))){
            KAJSON_BOOLE *boo = newBoole(memCtx, 0);
            if(boo == NULL) return NULL;
            *value = boo;
            return src+5;
        }
        else if((src[0]=='n')&&(src[1]=='u')&&(src[2]=='l')&&(src[3]=='l')&&(isTerminatorSymbol(src[4]))){
            *value = NULL;
            return src+4;
        }
        else{
            void *num = NULL;
            src = makeIntegerOrFloat(&num, memCtx, src);
            if(src == NULL) return NULL;
            *value = num;
            return src;
        }
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    ////////////////////////// 计算json结构转字符串后的大小 ////////////////////////
    
    static int getValueSize(void *json);
    
    static int getObjectSize(KAJSON_OBJECT_NODE *node){
        int size = 0;
        while(node){
            size += (((node->key) && (node->key[0])) ? strlen(node->key) : 0) + 3;  //"": = 3.
            size += getValueSize(node->value);
            node = node->next;
            if(node) size += 1;  //, = 1.
        }
        return size;
    }
    
    static int getArraySize(KAJSON_ARRAY_NODE *node){
        int size = 0;
        while(node){
            size += getValueSize(node->value);
            node = node->next;
            if(node) size += 1; //, = 1.
        }
        return size;
    }
    
    static int getValueSize(void *json){
        if(json){
            int type = *(unsigned short*)json;
            switch(type){
                case KAJSON_TYPE_ROOT:
                    return getValueSize(((KAJSON_CTX*)json)->value);
                    
                case KAJSON_TYPE_STRING:
                    return ((KAJSON_STRING*)json)->strLeng + 2;  //"" = 2
                    
                case KAJSON_TYPE_INTEGER:
                    return snprintf(NULL, 0, "%d", ((KAJSON_INTEGER*)json)->value);
                    
                case KAJSON_TYPE_FLOAT:
                    return snprintf(NULL, 0, "%f", ((KAJSON_FLOAT*)json)->value);
                    
                case KAJSON_TYPE_BOOLE:
                    return ((((KAJSON_BOOLE*)json)->value) ? 4 : 5);   //true = 4, false = 5.
                    
                case KAJSON_TYPE_OBJECT:
                    return getObjectSize(((KAJSON_OBJECT*)json)->head) + 2; //{} = 2
                    
                case KAJSON_TYPE_ARRAY:
                    return getArraySize(((KAJSON_ARRAY*)json)->head) + 2;//[] = 2
                    
                default:
                    return 0;
            }
        }
        else{
            return 4;  //null = 4.
        }
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    //////////////////////////// json结构转字符串 //////////////////////////////////
    
    static int valueToString(char *out, void *value);
    
    static int objectToString(char *out, KAJSON_OBJECT_NODE *node){
        int offset = 0;
        while(node){
            offset += sprintf(out+offset, "\"%s\":", ((node->key) && (node->key[0])) ? node->key : "");
            offset += valueToString(out+offset, node->value);
            node = node->next;
            if(node){
                out[offset] = ',';
                offset += 1;
            }
        }
        return offset;
    }
    
    static int arrayToString(char *out, KAJSON_ARRAY_NODE *node){
        int offset = 0;
        while(node){
            offset += valueToString(out+offset, node->value);
            node = node->next;
            if(node){
                out[offset] = ',';
                offset += 1;
            }
        }
        return offset;
    }
    
    static int valueToString(char *out, void *value){
        if(value){
            int n, type = *(unsigned short*)value;
            switch(type){
                case KAJSON_TYPE_ROOT:
                    return valueToString(out, ((KAJSON_CTX*)value)->value);
                
                case KAJSON_TYPE_STRING:
                    return sprintf(out, "\"%s\"", ((KAJSON_STRING*)value)->value ? ((KAJSON_STRING*)value)->value : "");
                
                case KAJSON_TYPE_INTEGER:
                    return sprintf(out, "%d", ((KAJSON_INTEGER*)value)->value);
                    
                case KAJSON_TYPE_FLOAT:
                    return sprintf(out, "%f", ((KAJSON_FLOAT*)value)->value);
                
                case KAJSON_TYPE_BOOLE:
                    return sprintf(out, "%s", ((KAJSON_BOOLE*)value)->value ? "true" : "false");
                
                case KAJSON_TYPE_OBJECT:
                    out[0] = '{';
                    n = objectToString(out+1, ((KAJSON_OBJECT*)value)->head);
                    out[1+n] = '}';
                    out[2+n] = 0;
                    return n+2;
                
                case KAJSON_TYPE_ARRAY:
                    out[0] = '[';
                    n = arrayToString(out+1, ((KAJSON_ARRAY*)value)->head);
                    out[1+n] = ']';
                    out[2+n] = 0;
                    return n+2;
                
                default:
                    return 0;
            }
        }
        else{
            return sprintf(out, "null");
        }
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////  查询接口 /////////////////////////////////////
    
    //数组的索引的范围[0 - 9999]
    static char* getIndexFromPath(int *index, char *path){
        char buffer[8];
        int length = 0;
        for(;;){
            if((*path >= '0') && (*path <= '9')){
                if(length >= 4) return NULL;
                buffer[length] = *path;
                length++;
                path++;
            }
            else if(*path == ']'){
                buffer[length] = 0;
                *index = atoi(buffer);
                return path+1;
            }
            else{
                return NULL;
            }
        }
    }
    
    //对象的键的长度上限127个字节
    static char* getKeyFromPath(char *key, char *path){
        int length = 0;
        for(;;){
            if(
                ((*path >= 'a') && (*path <= 'z')) ||
                ((*path >= 'A') && (*path <= 'Z')) ||
                ((*path >= '0') && (*path <= '9')) ||
                (*path == '_')
            ){
                if(length >= 127) return NULL;
                *key = *path;
                length++;
                path++;
                key++;
            }
            else if((*path=='.')||(*path=='[')||(*path==0)){
                *key = 0;
                return path;
            }
            else{
                return NULL;
            }
        }
    }
    
    static void* getValueByIndex(KAJSON_ARRAY_NODE *node, int index){
        while(node){
            if(index <= 0) return node->value;
            node = node->next;
            index--;
        }
        return NULL;
    }
    
    static void* getValueByKey(KAJSON_OBJECT_NODE *node, char *key){
        while(node){
            if((node->key) && (strcmp(key, node->key) == 0)){
                return node->value;
            }
            node = node->next;
        }
        return NULL;
    }
    
    static void* searchValue(void *json, char *path, char *tmpKeyBuffer){
        if(json == NULL) return NULL;
        if(*path == '.'){
            if(*(unsigned short*)json != KAJSON_TYPE_OBJECT) return NULL;
            path = getKeyFromPath(tmpKeyBuffer, path+1);
            if(path == NULL) return NULL;
            json = getValueByKey(((KAJSON_OBJECT*)json)->head, tmpKeyBuffer);
            if(json == NULL) return NULL;
            return searchValue(json, path, tmpKeyBuffer);
        }
        else if(*path == '['){
            if(*(unsigned short*)json != KAJSON_TYPE_ARRAY) return NULL;
            int index;
            path = getIndexFromPath(&index, path+1);
            if(path == NULL) return NULL;
            json = getValueByIndex(((KAJSON_ARRAY*)json)->head, index);
            if(json == NULL) return NULL;
            return searchValue(json, path, tmpKeyBuffer);
        }
        else if(*path == 0){
            return json;
        }
        else{
            return NULL;
        }
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////// 对外接口 /////////////////////////////////////
    
    void kajson_init(KAJSON_CTX *jsonCtx){
        jsonCtx->type = KAJSON_TYPE_ROOT;
        jsonCtx->value = NULL;
        kajsonMem_init(&(jsonCtx->memCtx));
    }
    
    void kajson_uninit(KAJSON_CTX *jsonCtx){
        jsonCtx->value = NULL;
        kajsonMem_uninit(&(jsonCtx->memCtx));
    }
    
    void kajson_clean(KAJSON_CTX *jsonCtx){
        jsonCtx->value = NULL;
        kajsonMem_clean(&(jsonCtx->memCtx));
    }
    
    char* kajson_stringToJson(KAJSON_CTX *jsonCtx, char *src){
        src = skipOverBlank(src);
        if(src == NULL) return NULL;
        src = makeValue(&(jsonCtx->value), &(jsonCtx->memCtx), src);
        if(src == NULL) return NULL;
        return src;
    }
    
    int kajson_getOutSize(void *json){
        return 1 + getValueSize(json);
    }
    
    int kajson_jsonToString(void *json, char *out){
        return 1 + valueToString(out, json);
    }
    
    void* kajson_search(void *json, char *path){
        if((json == NULL) || (path == NULL)) return NULL;
        char tmpKeyBuffer[128];
        if(*(unsigned short*)json == KAJSON_TYPE_ROOT){
            return searchValue(((KAJSON_CTX*)json)->value, path, tmpKeyBuffer);
        }
        else{
            return searchValue(json, path, tmpKeyBuffer);
        }
    }
    
    

    这个json解析器并没有完全符合json格式,例如字符串目前不支持转义字符。

    • 测试程序
    //==============================================================================
    //
    //  作者: 王小康
    //  描述: kajson解析器测试程序
    //  日期: 2019-05-07
    //
    //==============================================================================
    
    #include <stdio.h>
    #include <stdlib.h>
    #include "kajson.h"
    
    int main(int argc, char* argv[]){
        char* testStr[] = {
            " {\"name\":\"张三\",\"friend\":[{\"name\":\"李四\",\"age\":30},{\"name\":\"王五\",\"age\":33}],\"array\":[[1,2,3],[4,5,6],[7,8,9]]} ",   //查询测试
            " {\"user\" : \"root\" , \"passwd\" : \"admin\"} ",   //测试 root={}     情况
            " [\"root\" , \"admin\"]                         ",   //测试 root=[]     情况
            " \"hello world ...\"                            ",   //测试 root=字符串 情况
            " 123456789                                      ",   //测试 root=整数值 情况
            " -12345.678901                                  ",   //测试 root=浮点数 情况
            " true                                           ",   //测试 root=布尔值 情况
            " false                                          ",   //测试 root=布尔值 情况
            " null                                           ",   //测试 root=null   情况
            " {\"\":\"root\", \"\":\"admin\", \"name\":\"\"} ",   //无名键和空字符串测试
            " {\"name\": \"不告诉你\", \"city\": \"武汉市\"} ",   //字符串包含中文测试。仅限UTF-8编码。
            " [-3402823669209384634633746074317791234.123456789, 0.00000000000000000000000000000000000000000012345678999999] ",   //极大极小浮点数测试
            " [{\"user\":\"root\"}, \"hello world ...\", 123456, [1,2,3,+  4,-5.1,6,[[],[]]], true, false, null, +3.1415926] ",   //复杂数组测试
            " {\"object\":{\"x1\":{\"x2\":[{},{}]}}, \"array\":[{},[[]], [+1.2,3,-1.5], true, null, - 3.14], \"other\":null} ",   //复杂对象测试
            " \r\n {\r\n \"user\" \n\t\r : \n\t \"root\"\n\t ,\"passwd\":\"admin\", \"number\"\n:-\n\n\n\t3.14\n\n\n} \n\t\r ",   //复杂空白符测试
            " {} "
        };
        int testStrNum = (sizeof(testStr)/sizeof(char*));
        
        KAJSON_CTX json;
        kajson_init(&json);
        
        // 转换测试
        int i, n;
        char *end;
        for(i=0; i<testStrNum; i++){
            end = kajson_stringToJson(&json, testStr[i]);
            if(end){
                char *buffer = malloc(kajson_getOutSize(&json));
                n = kajson_jsonToString(&json, buffer);
                printf("test[%2d], outSize() = %3d, string = %s\n", i, n, buffer);
                free(buffer);
            }
            kajson_clean(&json);
        }
        putchar('\n');
        
        //查询测试
        char outBuffer[1024];
        void *jsonValue;
        kajson_clean(&json);
        kajson_stringToJson(&json, testStr[0]);
        kajson_jsonToString(&json, outBuffer);
        printf("root                     = %s\n", outBuffer);
        jsonValue = kajson_search(&json, ".name");
        if(jsonValue){
            kajson_jsonToString(jsonValue, outBuffer);
            printf("search(\".name\")          = %s\n", outBuffer);
        }
        jsonValue = kajson_search(&json, ".friend");
        if(jsonValue){
            kajson_jsonToString(jsonValue, outBuffer);
            printf("search(\".friend\")        = %s\n", outBuffer);
        }
        jsonValue = kajson_search(&json, ".friend[0]");
        if(jsonValue){
            kajson_jsonToString(jsonValue, outBuffer);
            printf("search(\".friend[0]\")     = %s\n", outBuffer);
        }
        jsonValue = kajson_search(&json, ".friend[1].age");
        if(jsonValue){
            kajson_jsonToString(jsonValue, outBuffer);
            printf("search(\".friend[1].age\") = %s\n", outBuffer);
        }
        jsonValue = kajson_search(&json, ".array");
        if(jsonValue){
            kajson_jsonToString(jsonValue, outBuffer);
            printf("search(\".array\")         = %s\n", outBuffer);
        }
        jsonValue = kajson_search(&json, ".array[1][1]");
        if(jsonValue){
            kajson_jsonToString(jsonValue, outBuffer);
            printf("search(\".array[1][1]\")   = %s\n", outBuffer);
        }
        
        jsonValue = kajson_search(kajson_search(kajson_search(&json, ".friend"), "[1]"), ".age");
        if(jsonValue){
            kajson_jsonToString(jsonValue, outBuffer);
            printf("search(search(search(json, \".friend\"), \"[1]\"), \".age\") = %s\n", outBuffer);
        }
        jsonValue = kajson_search(kajson_search(kajson_search(&json, ".array"), "[2]"), "[2]");
        if(jsonValue){
            kajson_jsonToString(jsonValue, outBuffer);
            printf("search(search(search(json, \".array\"), \"[2]\"), \"[2]\")   = %s\n", outBuffer);
        }
        
        kajson_uninit(&json);
        return 0;
    }
    
    
    • 运行效果

      注意事项:因为有中文字符,为了避免乱码,代码中的字符集应该和终端字符集相同,这里我都用的utf8,如图:

    相关文章

      网友评论

          本文标题:json解析器kajson

          本文链接:https://www.haomeiwen.com/subject/ufrroqtx.html