第六节主要负责解析对象,这里简单分析下json对象,json值,json的区别:
JSON 是 JS 对象的字符串表示法,使用文本表示一个 JS 对象的信息,本质是一个字符串。在代码中是leptjson.cpp中lept_contex里的const char* json;
JSON对象是用大括号括起来的,里面有多个键值对,其中键是字符串格式,值可以是空、布尔、数字、字符串、数组、和对象(对象里面可以再套对象)。键值对在代码里面是leptjson.h里的lept_member,json对象是lept_value.o,由键值对指针和size构成;
JSON值是空、布尔、数字、字符串、数组、和对象,在代码里是lept_value,包括lept_type和具体内容。
leptjson.h
// lept_value与lept_member相互引用
//typedef struct lept_value lept_value;
typedef struct lept_member lept_member;
struct lept_value {
union {
struct { lept_member* m; size_t size; }o; // json对象(键值对组成) member(一组键值对,char* :json对象), size
struct { lept_value* e; size_t size; } a;
struct { char* s; size_t len; } s;
double n;
}u;
lept_type type;
};
struct lept_member {
char* k; size_t klen;
lept_value v;
};
解析对象的逻辑与数组类似,也是嵌套递归
leptjson.cpp
static int lept_parse_object(lept_context* c, lept_value* v) {
size_t i, size; // 用来统计json中键值对个数,用来释放内存
lept_member m;
int ret;
EXPECT(c, '{');
lept_parse_whitespace(c);
if (*c->json == '}') { // 直接遇到结尾
c->json++;
v->type = LEPT_OBJECT;
v->u.o.m = NULL;
v->u.o.size = 0;
return LEPT_PARSE_OK;
}
m.k = NULL;
size = 0;
for (;;){
// 逐个解析键值对
char* str;
lept_init(&m.v);
// 解析键
if (*c->json != '"') { // 找不到键
ret = LEPT_PARSE_MISS_KEY;
break;
}
// 找到键
if ((ret=lept_parse_string_raw(c,&str,&m.klen))!=LEPT_PARSE_OK) {
break;
}
memcpy(m.k = (char*)malloc(m.klen + 1), str, m.klen);
m.k[m.klen] = '\0';
// 解析冒号
lept_parse_whitespace(c);
if (*c->json != ':') {
ret = LEPT_PARSE_MISS_COLON;
break;
}
c->json++;
lept_parse_whitespace(c);
// 解析值
if ((ret = lept_parse_value(c, &m.v)) != LEPT_PARSE_OK) {
break;
}
// 把键值对指针存进json语句的栈中
memcpy(lept_context_push(c, sizeof(lept_member)), &m, sizeof(lept_member));
size++;
// 准备重新开始下一个
m.k = NULL;
lept_parse_whitespace(c);
if (*c->json == ',') {
c->json++;
lept_parse_whitespace(c);
}
else if (*c->json == '}') {
// 解析结束
size_t s = sizeof(lept_member) * size;
c->json++;
v->type = LEPT_OBJECT;
v->u.o.size = size;
// 把栈中内存存进json的对象指针里
memcpy(v->u.o.m = (lept_member*)malloc(s), lept_context_pop(c, s), s);
return LEPT_PARSE_OK;
}
else {
ret = LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET;
break;
}
}
/* Pop and free members on the stack */
// 逐个释放json键值对
free(m.k);
for (i = 0; i < size; i++) {
lept_member* m = (lept_member*)lept_context_pop(c, sizeof(lept_member));
free(m->k);
lept_free(&m->v);
}
v->type = LEPT_NULL;
return ret;
}
释放内存
void lept_free(lept_value* v) {
size_t i;
assert(v != NULL);
switch (v->type) {
case LEPT_STRING:
free(v->u.s.s);
break;
case LEPT_ARRAY:
for (i = 0; i < v->u.a.size; i++)
lept_free(&v->u.a.e[i]);
free(v->u.a.e);
break;
case LEPT_OBJECT:
for (i = 0; i < v->u.o.size; i++) {
free(v->u.o.m[i].k);
lept_free(&v->u.o.m[i].v);
}
free(v->u.o.m);
break;
default: break;
}
v->type = LEPT_NULL;
}
test.cpp
缺少键
TEST_ERROR(LEPT_PARSE_MISS_KEY, "{:1,");
TEST_ERROR(LEPT_PARSE_MISS_KEY, "{1:1,");
TEST_ERROR(LEPT_PARSE_MISS_KEY, "{true:1,");
TEST_ERROR(LEPT_PARSE_MISS_KEY, "{false:1,");
TEST_ERROR(LEPT_PARSE_MISS_KEY, "{null:1,");
TEST_ERROR(LEPT_PARSE_MISS_KEY, "{[]:1,");
TEST_ERROR(LEPT_PARSE_MISS_KEY, "{{}:1,");
TEST_ERROR(LEPT_PARSE_MISS_KEY, "{\"a\":1,");
缺少冒号
TEST_ERROR(LEPT_PARSE_MISS_COLON, "{\"a\"}");
TEST_ERROR(LEPT_PARSE_MISS_COLON, "{\"a\",\"b\"}");
缺少大括号或者逗号
TEST_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1");
TEST_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1]");
TEST_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1 \"b\"");
TEST_ERROR(LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":{}");