美文网首页
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

    我需要IP定位功能,很多IP定位API使用HTTP或HTTPS协议,返回的数据是json格式,例如百度IP定位AP...

  • 8、go第三方json解析器

    go原生的json解析器:encoding/json 和第三方的json解析器在 Marshal 上基本没有差别,...

  • Jackson,强大的java json解析器,方便json字符

    概述 json解析器有很多,Gson、Jackson、fastJson等,Jackson是一款优秀的json解析器...

  • Mojo::JSON

    Mojo::JSON 是一个纯Perl实现的简约的JSON解析器。 简介 Mojo::JSON 支持正常的Perl...

  • IOS JSON,XML

    用系统的json解析器解析 NSDictionary *dict=[NSJSONSerialization JSO...

  • SpringBoot中使用Jackson 统一配置日期格式

    概述 在《Jackson,强大的java json解析器,方便json字符串、对象bean、map、数组list互...

  • golang第三方类库(json)-jsoniter

    概述 jsoniter(json-iterator)是一款快且灵活的 JSON 解析器;从 dsljson和 js...

  • json

    json在线解析器 读写 http://www.cnblogs.com/bigberg/p/6430095.html

  • Fastjson

    Fastjson是基于Java开发的JSON解析器和生成器,是Alibaba开源的JSON解析库。 支持解析JSO...

  • c语言json处理-cJSON

    简介 一个超轻量级的JSON解析器-官网,json官网注:跟java JSON官方库解决的思路大体相同 安装 cJ...

网友评论

      本文标题:json解析器kajson

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