6. 对象解析
章节目录
6.1 JSON对象结构
JSON对象和数组类似, 是一个复合类型, 使用{ }
包括, 数组中每个元素都是一个JSON的value
, 而对象中的每一个成员是一个键值对, 以冒号':'分隔, 且键必须为字符串类型, 值可以为任意JSON类型, 每个成员由逗号分隔.
如: {'memb1":[1, 2, "hello"], "memb2" : "world"}
C语言实现这个结构如下:
typedef struct __json_object json_object_t
struct __json_object
{
int size;
struct list_head head;
struct rb_root root;
};
typedef struct __json_member json_member_t;
struct __json_member
{
struct list_head list;
struct rb_node node;
json_value_t value;
char key[1];
};
可以看出, json_object_t
的结构和json_array_t
的结构类似, 就是多了一个struct rb_root root
, 这个是linux内核的红黑树实现, 前面说了, 为了提高JSON对象的查找效率, 所以使用了红黑树的结构, 这个不是我们的重点, 所以暂且知道怎么用就行了.
json_element_t
是一个和json_element_t
类似的结构, 内部包含一个value
即数据域表示键值对的值, 一个key
表示键值对的键名, 这里使用char key[1]只是做占位用, 在解析时分配内存. 其他的就是list
和数组元素结构里的list
相同, 然后多了一个红黑树的节点成员, 用于将当前的member
插入以json_object_t
结构中root
为根的红黑树.
外部调用:
case '{':
{
ret = __parse_json_object(cursor, end, depth, &val->value.object);
if (ret < 0)
{
return ret;
}
val->type = JSON_VALUE_OBJECT;
break;
}
模式和解析其他的类型相似, 看看解析object函数的实现:
static int __parse_json_object(const char *cursor, const char **end, int depth, json_object_t *obj)
{
int ret;
if(depth == JSON_DEPTH_LIMIT)
{
return -3;
}
// 初始化链表和红黑树
INIT_LIST_HEAD(&obj->head);
obj->root.rb_node = NULL;
ret = __parse_json_members(cursor, end, depth + 1, obj);
if (ret < 0)
{
__destroy_json_members(obj);
return ret;
}
obj->size = ret;
return 0;
}
可以看出, 除了多初始化一个红黑树, 其他的和数组的类似, 其中核心就是__parse_json_member
函数.
6.2 解析对象中的成员
实现__parse_json_member
函数其实和解析数组的元素的函数相似, 只是对象的成员多了一个字符串类型的键, 在解析value
之前将键解析出来就行了.
static int __parse_json_members(const char *cursor, const char **end, int depth, json_object_t *obj)
{
int ret;
int cnt = 0;
json_member_t *memb;
while (isspace(*cursor))
{
cursor++;
}
if (*cursor == '}')
{
*end = cursor + 1;
return 0;
}
while (1)
{
if (*cursor != '\"')
{
return -2;
}
cursor++;
ret = __json_string_length(cursor);
if (ret < 0)
{
return ret;
}
memb = (json_member_t *)malloc(offsetof(json_member_t, name) + ret + 1);
if (memb == NULL)
{
return -1;
}
ret = __parse_json_member(cursor, &cursor, depth, memb);
if (ret < 0)
{
free(memb);
return ret;
}
__insert_json_member(memb, obj->head.prev, obj);
cnt++;
while (isspace(*cursor))
{
cursor++;
}
if (*cursor == ',')
{
cursor++;
while (isspace(*cursor))
{
cursor++;
}
}
else if (*cursor == '}')
{
break;
}
else
{
return -2;
}
}
*end = cursor + 1;
return cnt;
}
static int __parse_json_member(const char *cursor, const char **end, int depth, json_member_t *memb)
{
int ret;
ret = __parse_json_string(cursor, &cursor, memb->name);
if (ret < 0)
{
return ret;
}
while (isspace(*cursor))
{
cursor++;
}
if (*cursor != ':')
{
return -2;
}
cursor++;
while (isspace(*cursor))
{
cursor++;
}
ret = __parse_json_value(cursor, &cursor, depth, &memb->value);
if (ret < 0)
{
return ret;
}
*end = cursor;
return 0;
}
可以看到, 除了多解析了一个string类型的键name
之外, 其他的大部分和数组的解析类似, 不过将单个成员的解析另立了一个函数, 没有太大区别.
在对象的单个成员解析完毕后, 进行了一个__insert_json_member
的操作, 这里就是将解析出来的memb
添加到对象的红黑树和链表之中.
static int __insert_json_member(json_member_t *memb, struct list_head *pos, json_object_t *obj)
{
struct rb_node **p = &obj->root.rb_node;
struct rb_node *parent = NULL;
json_member_t *entry;
while (*p)
{
parent = *p;
entry = rb_entry(*p, json_member_t, node);
if (strcmp(memb->name, entry->name) < 0)
{
p = &(*p)->rb_left;
}
else
{
p = &(*p)->rb_right;
}
}
rb_link_node(&memb->node, parent, p);
rb_insert_color(&memb->node, &obj->root);
list_add(&memb->list, pos);
}
这里默认对红黑树有基础, 先从父节点开始遍历, 查找memb
适合插入的节点位置, 找到合适的位置后, 进行插入和自平衡操作即rb_link_node
和rb_insert_color
, 最后将memb
也关联到一个链表一样, 操作和数组插入相同, 不过这个是插入到了链表的头结点之后而非尾结点之后.
到这里JSON数据的所有类型解析都实现了, 最后看看destroy相关函数的实现.
6.3 资源释放
在JSON数组和对象的解析中, 如果解析失败, 需要将分配的内存合理释放, 由于数组和对象结构是嵌套结构, 所以需要实现销毁数组元素和对象的成员的函数.
static void __destroy_json_elements(json_array_t *arr)
{
struct list_head *pos, *tmp;
json_element_t *elem;
list_for_each_safe(pos, tmp, &arr->head)
{
elem = list_entry(pos, json_element_t, list);
__destroy_json_value(&elem->value);
free(elem);
}
}
static void __destroy_json_value(json_value_t *val)
{
switch (val->type)
{
case JSON_VALUE_STRING:
free(val->value.string);
break;
case JSON_VALUE_ARRAY:
__destroy_json_elements(&val->value.array);
break;
case JSON_VALUE_OBJECT:
__destroy_json_members(&val->value.object);
break;
}
}
static void __destroy_json_members(json_object_t *obj)
{
struct list_head *pos, *tmp;
json_member_t *memb;
list_for_each_safe(pos, tmp, &obj->head)
{
memb = list_entry(pos, json_member_t, list);
__destroy_json_value(&memb->value);
free(memb);
}
}
释放的函数其实很简单, 遍历对应的链表, 然后调用销毁value的函数, 销毁value的函数内部根据不同的类型执行销毁函数即可.
参考:
[1] workflow 源码解析 : 基础数据结构 rbtree - 知乎 (zhihu.com)
[2] Workflow 源码解析 Json parser :part1 parse - 知乎 (zhihu.com)
[3] 红黑树 - 维基百科,自由的百科全书 (wikipedia.org)
[4] 二叉树 - 维基百科,自由的百科全书 (wikipedia.org)
[5] 二叉树及其作用浅析-腾讯云开发者社区-腾讯云 (tencent.com)
标签:__,member,memb,对象,ret,cursor,json,解析 From: https://www.cnblogs.com/xlqblog/p/object-analysis-zseait.html