json格式
json 分为种类型 一种是包含键值对的对象 一种是值的序列,即是数组 具体可以分为从此例子可看出,JSON 是树状结构,而 JSON 只包含 6 种数据类型:
null: 表示为 null
boolean: 表示为 true 或 false
number: 一般的浮点数表示方式
string: 表示为 “…”
array: 表示为 [ … ]
object: 表示为 { … }
json库的需求:
(1) 把 JSON 文本解析为一个树状数据结构
(2) 提供接口访问该数据结构
(3) 把数据结构转换成 JSON 文本
提供一个向下递归的解析器 解析的规则如下所示:
n ➔ null
t ➔ true
f ➔ false
“ ➔ string
0-9/- ➔ number
[ ➔ array
{ ➔ object
unicode是一种编码方式,映射字符为码点,utf-8/16/32是计算机内部对unicode的三种存储方式,utf-8是可变长度编码,与ASCII兼容。如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的字节数,其余各字节均以10开头。
解析null true false
判断字符串的开始字符 ‘n’ ‘t’ ‘f’ 并进行相应操作
static int wizz_parse_literal(wizz_context *c, wizz_value* v, const char* literal, wizz_type type){
expect(c,literal[0]);
size_t i;
for(i=0;literal[i+1];i++)
{
if(c->json[i]!=literal[i+1])
return WIZZ_PARSE_INVALID_VALUE;
}
c->json += i;
v->type = type;
return WIZZ_PARSE_OK;}
解析数字
strtod (const char* str, char**endptr);
Convert string to double str目标字符串 endptr 转换成功返回数字字符串最后一位的后一位
使用strtod函数解析数字:
static int wizz_parse_number(wizz_context* c, wizz_value* v)
{
char *end;
v->n = strtod(c->json, &end);
if(c->json == end)
return WIZZ_PARSE_INVALID_VALUE;
c->json = end;
v->type = WIZZ_NUMBER;
return WIZZ_PARSE_OK;}
利用stack存储字符串 判断“作为字符串开始 另一个”作为结束 判断转移字符
static void put_ch(wizz_context* c, char ch)
{
*(char*)wizz_context_push(c, sizeof(char)) = ch;
}
static int wizz_parse_string(wizz_context* c, wizz_value* v){
expect(c, '\"');
size_t head=c->top, len;
const char* p = c->json;
while(true)
{
char ch = *p++;
switch (ch) {
case '\"':
len = c->top - head;
wizz_set_string(v, (const char*)wizz_context_pop(c, len), len);
c->json = p;
return WIZZ_PARSE_OK;
case '\0':
c->top = head;
return WIZZ_PARSE_MISS_QUOTATION_MARK;
case '\\':
switch (*p++) {
case '\"': put_ch(c, '\"'); break;
case '\\': put_ch(c, '\\'); break;
case '/': put_ch(c, '/' ); break;
case 'b': put_ch(c, '\b'); break;
case 'f': put_ch(c, '\f'); break;
case 'n': put_ch(c, '\n'); break;
case 'r': put_ch(c, '\r'); break;
case 't': put_ch(c, '\t'); break;
default:
c->top = head;
return WIZZ_PARSE_INVALID_STRING_ESCAPE;
}
break;
default:
put_ch(c, ch);
}
}}
解析数组
利用栈存储数组元素 遇到’[‘进入数组解析 开始解析元素,解析’,’前的元素 遇到’]’出栈 将栈中所有元素存储为数组元素,具体代码如下所示:
static int wizz_parse_array(wizz_context* c, wizz_value* v){
size_t size = 0;
int ret;
expect(c, '[');
wizz_parse_whitespace(c);
if(*c->json == ']')
{
c->json++;
v->type = WIZZ_ARRAY;
v->u.a.size = 0;
v->u.a.e = NULL;
return WIZZ_PARSE_OK;
}
while(true)
{
wizz_value e;
wizz_init(&e);
if((ret = wizz_parse_value(c, &e)) != WIZZ_PARSE_OK)
break;
wizz_parse_whitespace(c);
printf("value type:%d\n", e.type);
memcpy(wizz_context_push(c, sizeof(wizz_value)), &e, sizeof(wizz_value));
size++;
if(*c->json==',')
{
c->json++;
wizz_parse_whitespace(c);
}
else if(*c->json == ']'){
c->json++;
v->type = WIZZ_ARRAY;
v->u.a.size = size;
size *= sizeof(wizz_value);
memcpy(v->u.a.e=(wizz_value* )malloc(size), wizz_context_pop(c, size),size);
return WIZZ_PARSE_OK;
}
else{
ret = WIZZ_PARSE_MISS_COMMA_OR_SQUARE_BRACKET;
break;
}
}
// avoid memory leak
for(size_t i=0;i<size;i++)
{
wizz_free((wizz_value*)wizz_context_pop(c, sizeof(wizz_value)));
}
return ret;}
解析对象
使用动态数组存储键 使用自定义的wizz_value(解析数字 数组等)作为值
object = %x7B ws [ member *( ws %x2C ws member ) ] ws %x7D
根据上述格式进行递归
static int wizz_parse_object(wizz_context* c, wizz_value* v){
expect(c, '{');
wizz_member m;
int ret;
size_t size;
wizz_parse_whitespace(c);
if(*c->json=='}')
{
c->json++;
v->type = WIZZ_OBJECT;
v->u.o.size = 0;
v->u.o.m = 0;
return WIZZ_PARSE_OK;
}
m.k = NULL;
size = 0;
while(true)
{
wizz_init(&m.v);
char* str;
if(*c->json!='"')
{
ret = WIZZ_PARSE_MISS_KEY;
break;
}
if((ret=wizz_parse_string_raw(c,&str,&m.klen))!=WIZZ_PARSE_OK)
break;
memcpy(m.k=(char*)malloc(m.klen+1), str, m.klen);
m.k[m.klen] = '\0';
wizz_parse_whitespace(c);
if(*c->json!=':')
{
ret = WIZZ_PARSE_MISS_COLON;
break;
}
c->json++;
wizz_parse_whitespace(c);
if((ret=wizz_parse_value(c,&m.v))!=WIZZ_PARSE_OK)
break;
memcpy(wizz_context_push(c, sizeof(wizz_member)), &m, sizeof(wizz_member));
size++;
// prepare for the next parse
m.k = NULL;
wizz_parse_whitespace(c);
if(*c->json == ',')
{
c->json++;
wizz_parse_whitespace(c);
}else if(*c->json == '}')
{
c->json++;
v->type = WIZZ_OBJECT;
v->u.o.size = size;
size_t s = sizeof(wizz_member)*size;
memcpy(v->u.o.m = (wizz_member*)malloc(s),wizz_context_pop(c, s),s);
return WIZZ_PARSE_OK;
}else{
ret = WIZZ_PARSE_MISS_COMMA_OR_CURLY_BRACKET;
break;
}
}
free(m.k);
for(size_t i=0;i<size;i++)
{
wizz_member* tmp = (wizz_member*)wizz_context_push(c, sizeof(wizz_member));
free(tmp->k);
wizz_free(&tmp->v);
}
v->type = WIZZ_NULL;
return ret;}
生成器
json解析的逆过程 将存储在wizz_value的数据根据类型存储到栈中 将栈的字符串弹出 即是原始字符串
解析字符串
static void wizz_stringify_string(wizz_context* c, const char* s, size_t len) {
size_t i;
assert(s != NULL);
put_ch(c, '"');
for (i = 0; i < len; i++) {
unsigned char ch = (unsigned char)s[i];
switch (ch) {
case '\"': put_s(c, "\\\"", 2); break;
case '\\': put_s(c, "\\\\", 2); break;
case '\b': put_s(c, "\\b", 2); break;
case '\f': put_s(c, "\\f", 2); break;
case '\n': put_s(c, "\\n", 2); break;
case '\r': put_s(c, "\\r", 2); break;
case '\t': put_s(c, "\\t", 2); break;
default:
if (ch < 0x20) {
char buffer[7];
sprintf(buffer, "\\u%04X", ch);
put_s(c, buffer, 6);
}
else
put_ch(c, s[i]);
}
}
put_ch(c, '"');}
解析函数 结果存储在json
int wizz_stringify( wizz_value* v,char** json, size_t* length){
assert(v!=NULL);
assert(json!=NULL);
wizz_context c;
int ret;
c.stack= (char*)malloc(c.size = WIZZ_PARSE_STRINGIFY_INIT_SIZE);
c.top = 0;
if((ret=wizz_stringify_value(&c,v)) != WIZZ_STRINGIFY_OK)
{
free(c.stack);
*json = NULL;
return ret;
}
put_ch(&c, '\0');
if(length)
*length = c.top - 1;
*json = c.stack;
return WIZZ_STRINGIFY_OK;}
根据不同类型 选择不同方式将内容入栈
int wizz_stringify_value(wizz_context *c, wizz_value *v){
switch (v->type) {
case WIZZ_NULL:
put_s(c,"null",4);
break;
case WIZZ_TRUE:
put_s(c, "true",4);
break;
case WIZZ_FALSE:
put_s(c, "false",5);
break;
case WIZZ_NUMBER:
{
char* buffer = (char *)wizz_context_push(c, 32);
int length = sprintf(buffer, "%.17g", v->u.n);
c->top -=32-length;
}
break;
case WIZZ_STRING:
wizz_stringify_string(c,v->u.s.s, v->u.s.len);
break;
case WIZZ_ARRAY:
{
put_ch(c, '[');
for(size_t i= 0;i<v->u.a.size;i++)
{
if(i>0)
put_ch(c, ',');
wizz_stringify_value(c,&v->u.a.e[i]);
}
put_ch(c, ']');
}
break;
case WIZZ_OBJECT:
{
put_ch(c, '{');
for(size_t i = 0;i<v->u.o.size;i++)
{
if(i>0)
put_ch(c, ',');
wizz_stringify_string(c, v->u.o.m[i].k, v->u.o.m[i].klen);
put_ch(c, ':');
wizz_stringify_value(c, &v->u.o.m[i].v);
}
put_ch(c,'}');
}
break;
}
return WIZZ_STRINGIFY_OK;}