您的位置:首页 > Web前端 > JavaScript

C 实现解析Json字符串

2016-07-15 17:32 597 查看
    除了C的标准库之外,依赖两个数据结构的实现,C 实现ArrayMap字典映射 和 C 实现泛型ArrayList数组。实现了标准的json结构解析,并提供一套访问json数据对象属性的接口。

    首先,看数据结构的定义。

typedef enum
{
json_object,
json_array,
json_string,
json_float,
json_null,
}
JsonType;

typedef struct
{
ArrayStrMap(JsonValue*) arrayStrMap[1];
}
JsonObject;

typedef struct
{
ArrayList(JsonValue*) arrayList[1];
}
JsonArray;

typedef struct
{
JsonType type;

union
{
/** json_string */
char*       stringValue;
/** json_object */
JsonObject* object;
/** json_array */
JsonArray*  array;
/** json_float */
float       floatValue;
};
}
JsonValue;


    Json 就是一个Key-Value结构,value可能有5中类型,array和object类型单独拿出来定义了一下。每一个value都是JsonValue类型的,用联合体来存储类型的值。看着这里并没有给int类型,所有的int类型值是通过float强转得到的。

    对于,array和object类型,给定一组接口访问其内部的数据结构。

    

typedef struct
{
bool        (*GetBool)         (JsonObject* object, const char* key, bool  defaultValue);
int         (*GetInt)          (JsonObject* object, const char* key, int   defaultValue);
float       (*GetFloat)        (JsonObject* object, const char* key, float defaultValue);
JsonType    (*GetType)         (JsonObject* object, const char* key);

/**
* When JsonValue released string value will free
*/
char*       (*GetString)       (JsonObject* object, const char* key, char* defaultValue);

/** Not found return NULL */
JsonObject* (*GetObject)       (JsonObject* object, const char* key);

/** Not found return NULL */
JsonArray*  (*GetArray)        (JsonObject* object, const char* key);

const char* (*GetKey)          (JsonObject* object, int   index);

/** Get JsonObject in index of JsonObject map */
JsonObject* (*GetObjectByIndex)(JsonObject* object, int   index);

/** Get JsonArray in index of JsonObject map */
JsonArray*  (*GetArrayByIndex) (JsonObject* object, int   index);
}
_AJsonObject_;

extern _AJsonObject_ AJsonObject[1];

typedef struct
{
bool        (*GetBool)      (JsonArray* array, int index);
int         (*GetInt)       (JsonArray* array, int index);
float       (*GetFloat)     (JsonArray* array, int index);

JsonType    (*GetType)      (JsonArray* array, int index);

/** When JsonValue released string value will free */
char*       (*GetString)    (JsonArray* array, int index);

JsonObject* (*GetObject)    (JsonArray* array, int index);
JsonArray*  (*GetArray)     (JsonArray* array, int index);

}
_AJsonArray_;

extern _AJsonArray_ AJsonArray[1];


    整个Json的解析通过一个接口完成。

    

typedef struct
{

/**
* Parse with Json string, return root JsonValue
*/
JsonValue* (*Parse)         (const char* jsonString);

/**
* Parse with Json file, return root JsonValue
*/
JsonValue* (*ParseWithFile) (const char* jsonPath);

/**
* Release JsonValue member memory space and free itself
* if release root JsonValue will free all memory space
*/
void       (*Release)       (JsonValue*  jsonValue);
}
_AJson_;


    Parse是解析一个Json字符串,ParseWithFile是解析一个Json文件。返回一个JsonValue对象,具体这个是什么类型,需具体判断,然后一步步通过接口就可以访问每个数据成员。

    array和object的访问接口如下:

    

static bool ObjectGetBool(JsonObject* object, const char* key, bool defaultValue)
{
JsonValue* jsonValue = *(JsonValue**) AArrayStrMap->Get(object->arrayStrMap, key, (void*[]) {NULL});
return jsonValue ? strcmp(jsonValue->stringValue, "true") == 0 : defaultValue;
}

static int ObjectGetInt(JsonObject* object, const char* key, int defaultValue)
{
JsonValue* jsonValue = *(JsonValue**) AArrayStrMap->Get(object->arrayStrMap, key, (void*[]) {NULL});

if (jsonValue)
{
return jsonValue->floatValue;
}

return defaultValue;
}

static float ObjectGetFloat(JsonObject* object, const char* key, float defaultValue)
{
JsonValue* jsonValue = *(JsonValue**) AArrayStrMap->Get(object->arrayStrMap, key, (void*[]) {NULL});

if (jsonValue)
{
return jsonValue->floatValue;
}

return defaultValue;
}

static char* ObjectGetString(JsonObject* object, const char* key, char* defaultValue)
{
JsonValue* jsonValue = *(JsonValue**) AArrayStrMap->Get(object->arrayStrMap, key, (void*[]) {NULL});
return jsonValue ? jsonValue->stringValue : defaultValue;
}

static JsonObject* ObjectGetObject(JsonObject* object, const char* key)
{
JsonValue* jsonValue = *(JsonValue**) AArrayStrMap->Get(object->arrayStrMap, key, (void*[]) {NULL});
return jsonValue ? jsonValue->object : NULL;
}

static JsonArray* ObjectGetArray(JsonObject* object, const char* key)
{
JsonValue* jsonValue = *(JsonValue**) AArrayStrMap->Get(object->arrayStrMap, key, (void*[]) {NULL});
return jsonValue ? jsonValue->array : NULL;
}

static JsonType ObjectGetType(JsonObject* object, const char* key)
{
JsonValue* jsonValue = *(JsonValue**) AArrayStrMap->Get(object->arrayStrMap, key, (void*[]) {NULL});

if (!jsonValue)
{
return json_null;
}

return jsonValue->type;
}

static const char* ObjectGetKey(JsonObject* object, int index)
{
return AArrayStrMap->GetKey(object->arrayStrMap, index);
}

static JsonObject* ObjectGetObjectByIndex(JsonObject* object, int index)
{
return (*(JsonValue**) AArrayStrMap->GetAt(object->arrayStrMap, index))->object;
}

static JsonArray* ObjectGetArrayByIndex(JsonObject* object, int index)
{
return (*(JsonValue**) AArrayStrMap->GetAt(object->arrayStrMap, index))->array;
}

_AJsonObject_ AJsonObject[1] =
{
ObjectGetBool,
ObjectGetInt,
ObjectGetFloat,
ObjectGetType,
ObjectGetString,
ObjectGetObject,
ObjectGetArray,
ObjectGetKey,
ObjectGetObjectByIndex,
ObjectGetArrayByIndex,
};


    解析Json的过程实现如下:

    

// predefine
static JsonValue* ParseValue(const char** jsonPtr);

/**
* If json_array  free each items and recursive
* If json_object free each K-V   and recursive
*/
static void Release(JsonValue* value)
{
// JsonValue hold the whole memory
// so free JsonValue will be release JsonValue's memory

switch (value->type)
{
case json_array:
{
ArrayList* list = value->array->arrayList;
for (int i = 0; i < list->size; i++)
{
Release(AArrayList_Get(list, i, JsonValue*));
}

AArrayList->Release(list);
}   break;

case json_object:
{
ArrayStrMap* map = value->object->arrayStrMap;
for (int i = 0; i < map->arrayList->size; i++)
{
Release(*(JsonValue**) AArrayStrMap->GetAt(map, i));
}

AArrayStrMap->Release(map);
}   break;

default:
break;
}

free(value);
}

static JsonValue* CreateJsonValue(void* data, size_t valueSize, JsonType type)
{
JsonValue* value = (JsonValue*) malloc(sizeof(JsonValue) + valueSize);

switch (type)
{
case json_float:
break;

case json_string:
{
void* v = (char*) value + sizeof(JsonValue);
memcpy(v, data, valueSize);
value->stringValue = v;
}   break;

case json_array:
value->array  = (JsonArray*)  ((char*) value + sizeof(JsonValue));
AArrayList->Init(sizeof(JsonValue*), value->array->arrayList);
value->array->arrayList->increment = 20;
break;

case json_object:
value->object = (JsonObject*) ((char*) value + sizeof(JsonValue));
AArrayStrMap->Init(sizeof(JsonValue*), value->object->arrayStrMap);
value->object->arrayStrMap->arrayList->increment = 20;
break;

default:
ALog_A(0, "CreateJsonValue unknown JsonType = %d", type);
}

value->type = type;

return value;
}


// skip whitespace and CR/LF
static void Skip(const char** jsonPtr)
{
const char* json = *jsonPtr;
while (json && isspace(*json))
{
json++;
}

ALog_A(json, "Json Parse failed on NULL, json is incomplete");

*jsonPtr = json;
}

static void* ParseNumber(const char** jsonPtr)
{
char* json = (char*) *jsonPtr;
char  c;

do
{
json++;
c = *json;
}
while (isdigit(c) || c == '-' || c == '.' || c == 'e' || c == 'E');

*json = '\0';
ALog_D("Json number = %s", *jsonPtr);

JsonValue* value  = CreateJsonValue(NULL, 0, json_float);
value->floatValue = atof(*jsonPtr);

*json             = c;
*jsonPtr          = json;

return value;
}

static JsonValue* ParseString(const char** jsonPtr)
{
// Skip '\"'
(*jsonPtr)++;
const char* json = *jsonPtr;
char  c          = *json;
int   count      = 0;

while (c != '\"')
{
// skip escaped quotes
if (c == '\\')
{
do
{
json  += 2;
count += 2;
c = *json;
}
while (c == '\\');
}
else
{
json++;
count++;
c = *json;
}
}

JsonValue* value = CreateJsonValue((void*)(*jsonPtr), (count + 1) * sizeof(char), json_string);
value->stringValue[count] = '\0';
*jsonPtr         = json + 1;

ALog_D("Json string = %s", value->stringValue);

return value;
}

static char* ParseKey(char** jsonPtr, int* outKeyLen)
{
// skip '\"'
(*jsonPtr)++;
char* json   = *jsonPtr;
char  c      = *json;
int   count  = 0;

while (c != '\"')
{
// skip escaped quotes
if (c == '\\')
{
do
{
json  += 2;
count += 2;
c      = *json;
}
while (c == '\\');
}
else
{
json++;
count++;
c = *json;
}
}

ALog_D("Json key = %.*s", count, *jsonPtr);

char* key  = *jsonPtr;
*outKeyLen = count;
*jsonPtr   = json + 1;

return key;
}

static JsonValue* ParseArray(const char** jsonPtr)
{
JsonValue* jsonValue = CreateJsonValue(NULL, sizeof(JsonArray), json_array);
ArrayList* list      = jsonValue->array->arrayList;

ALog_D("Json Array: [");

// skip '['
(*jsonPtr)++;
Skip(jsonPtr);

// empty array
if (**jsonPtr == ']')
{
goto label_json_array_end;
}

do
{
JsonValue* value = ParseValue(jsonPtr);
// add Array element
AArrayList->Add(list, &value);

Skip(jsonPtr);
if (**jsonPtr == ',')
{
(*jsonPtr)++;
Skip(jsonPtr);
if (**jsonPtr == ']')
{
goto label_json_array_end;
}
}
else
{
break;
}
}
while (true);

Skip(jsonPtr);
ALog_A(**jsonPtr == ']', "Json Array not has ']', error char = %c ", **jsonPtr);

label_json_array_end:
// skip ']'
(*jsonPtr)++;
ALog_D("] JsonArray element count = %d", list->size);

return jsonValue;
}

static JsonValue* ParseObject(const char** jsonPtr)
{
JsonValue*   jsonValue = CreateJsonValue(NULL, sizeof(JsonObject), json_object);
ArrayStrMap* map       = jsonValue->object->arrayStrMap;

ALog_D("Json Object: {");

// skip '{'
(*jsonPtr)++;
Skip(jsonPtr);

// empty object
if (**jsonPtr == '}')
{
goto label_json_object_end;
}

do
{
Skip(jsonPtr);
if (**jsonPtr == '}')
{
goto label_json_object_end;
}

ALog_A(**jsonPtr == '\"', "Json object Parse failed, char = %c, should be '\"' ", **jsonPtr);

int keyLen;
// get object key
char* key = ParseKey((char**)jsonPtr, &keyLen);

Skip(jsonPtr);
ALog_A((**jsonPtr) == ':', "Json object Parse failed, char = %c, should be ':' ", **jsonPtr);

// Skip ':'
(*jsonPtr)++;
JsonValue*  value = ParseValue(jsonPtr);
char        c     = key[keyLen];

// make string end in json string
key[keyLen]       = '\0';

// set object element
AArrayStrMap->Put(map, key, &value);

key[keyLen]       = c;

Skip(jsonPtr);
if (**jsonPtr == ',')
{
(*jsonPtr)++;
}
else
{
break;
}

}
while (true);

Skip(jsonPtr);
ALog_A(**jsonPtr == '}', "Json Object not has '}', error char = %c ", **jsonPtr);

label_json_object_end:
// skip '}'
(*jsonPtr)++;
ALog_D("} JsonObject elements count = %d", map->arrayList->size);

return jsonValue;
}

/**
* ParseValue changed the *jsonPtr, so if *jsonPtr is direct malloc will cause error
*/
static JsonValue* ParseValue(const char** jsonPtr)
{
Skip(jsonPtr);
char c = **jsonPtr;

switch (c)
{
case '[':
return ParseArray(jsonPtr);

case '{':
return ParseObject(jsonPtr);

case '\"':
return ParseString(jsonPtr);

default:
if (isdigit(c) || c == '-')
{
return ParseNumber(jsonPtr);
}
else if (strncmp(*jsonPtr, "null", 4) == 0)
{
ALog_D("Json null");

(*jsonPtr) += 4;
// copy with '\0'
return CreateJsonValue("null", 5, json_string);

}
else if (strncmp(*jsonPtr, "false", 5) == 0)
{
ALog_D("Json false");

(*jsonPtr) += 5;
// copy with '\0'
return CreateJsonValue("false", 6, json_string);

}
else if (strncmp(*jsonPtr, "true", 4) == 0)
{
ALog_D("Json true");

(*jsonPtr) += 4;
// copy with '\0'
return CreateJsonValue("true", 5, json_string);
}
else
{
ALog_A(0, "Can't parse value type, error char = %c", c);
}

break;
}

return NULL;
}

static JsonValue* Parse(const char* jsonString)
{
return ParseValue(&jsonString);
}

static JsonValue* ParseWithFile(const char* jsonPath)
{
char*        jsonString = AFileTool->ReadString(jsonPath);
JsonValue*   value      = Parse(jsonString);
free(jsonString);

return value;
}

_AJson_ AJson[1] =
{
Parse,
ParseWithFile,
Release,
};


    其核心的思想很简单,就是一个一个字符读入,根据不同的字符来判断需要解析的数据类型。中间,需要跳过无效的字符比如空格什么的。因为array和object可以嵌套。所以在ParseArray和ParseObject的时候,调用ParseValue解析,其中会递归的调用ParseArray和ParseObject。

    当解析完成的时候,所有的Json都转化为对象存储起来。Json字符串也可以删除了,以后所有的访问都是在访问结构化的Json对象。Release方法可以释放JsonValue全部申请的内存空间,如果传入根JsonValue就可以释放全部的空间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: