从零开始的 JSON 库教程(七):生成器

80 阅读1分钟

代码地址:github.com/WangHao-nlp…

这节介绍如何根据json对象生产json字符串: 如{“a”:1}“{\“a\”:1}”

leptjson.cpp

生成空和布尔类型json值, 直接添加

case LEPT_NULL:   PUTS(c, "null", 4); break;
case LEPT_FALSE:  PUTS(c, "false", 5); break;
case LEPT_TRUE:   PUTS(c, "true", 4); break;

生成数据类型json值, 有三种方法 本质上都是, 将数字通过sprintf函数转化为字符串, 然后将字符串添加到栈上。
sprintf函数会返回数字转换的字符串长度。

case LEPT_NUMBER:
{   
    /*char buffer[32];
    int length = sprintf(buffer, "%.17g", v->u.n);
    PUTS(c, buffer, length);
    break;*/

    c->top -= 32 - sprintf((char*)lept_context_push(c, 32), "%.17g", v->u.n); 
    break;

    /*char* buffer = (char*)lept_context_push(c, 32);
    int length = sprintf(buffer, "%.17g", v->u.n);
    c->top -= 32 - length;
    break;*/
}

生成字符串类型的json值。
主要处理转义字符和ASCII前20位

// Unoptimized
//static void lept_stringify_string(lept_context* c, const char* s, size_t len) {
//	size_t i;
//	assert(s != NULL);
//	PUTC(c, '"');
//	for (i = 0; i < len; i++) {
//		unsigned char ch = (unsigned char)s[i];
//		switch (ch) {
//		case '\"': PUTS(c, "\\\"", 2); break;
//		case '\\': PUTS(c, "\\\\", 2); break;
//		case '\b': PUTS(c, "\\b", 2); break;
//		case '\f': PUTS(c, "\\f", 2); break;
//		case '\n': PUTS(c, "\\n", 2); break;
//		case '\r': PUTS(c, "\\r", 2); break;
//		case '\t': PUTS(c, "\\t", 2); break;
//		default:
//			if (ch < 0x20) {
//				char buffer[7];
//				sprintf_s(buffer, ch, "\\u%04X");  // ?
//				PUTS(c, buffer, 6);
//			}
//			else
//				PUTC(c, s[i]);
//		}
//	}
//	PUTC(c, '"');
//}

static void lept_stringify_string(lept_context* c, const char* s, size_t len) {
    static const char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
    size_t i, size;
    char* head, * p;
    assert(s != NULL);
    p = head = (char*)lept_context_push(c, size = len * 6 + 2); /* "\u00xx..." */
    *p++ = '"';
    for (i = 0; i < len; i++) {
        unsigned char ch = (unsigned char)s[i];
        switch (ch) {
            case '\"': *p++ = '\\'; *p++ = '\"'; break;
            case '\\': *p++ = '\\'; *p++ = '\\'; break;
            case '\b': *p++ = '\\'; *p++ = 'b';  break;
            case '\f': *p++ = '\\'; *p++ = 'f';  break;
            case '\n': *p++ = '\\'; *p++ = 'n';  break;
            case '\r': *p++ = '\\'; *p++ = 'r';  break;
            case '\t': *p++ = '\\'; *p++ = 't';  break;
            default:
                if (ch < 0x20) {
                    *p++ = '\\'; *p++ = 'u'; *p++ = '0'; *p++ = '0';
                    *p++ = hex_digits[ch >> 4];
                    *p++ = hex_digits[ch & 15];
                }
                else
                    *p++ = s[i];
            }
    }
    *p++ = '"';
    c->top -= size - (p - head);
}

生产数组和对象。
根据size数据循环添加

case LEPT_ARRAY:
    PUTC(c, '[');
    for (i = 0; i < v->u.a.size; i++) {
        if (i > 0)
            PUTC(c, ',');
        lept_stringify_value(c, &v->u.a.e[i]);
    }
    PUTC(c, ']');
    break;
case LEPT_OBJECT:
    PUTC(c, '{');
    for (i = 0; i < v->u.o.size; i++) {
        if (i > 0)
            PUTC(c, ',');
        lept_stringify_string(c, v->u.o.m[i].k, v->u.o.m[i].klen);
        PUTC(c, ':');
        lept_stringify_value(c, &v->u.o.m[i].v);
    }
    PUTC(c, '}');
    break;

test.cpp

// 往返测试
#define TEST_ROUNDTRIP(json)\
    do{\
        lept_value v;\
        char* json2;\
        size_t length;\
        lept_init(&v);\
        EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json));\
        json2 = lept_stringify(&v,&length);\
        /*printf("_________%s\n",json2);\*/\
        EXPECT_EQ_STRING(json, json2, length);\
        lept_free(&v);\
        free(json2);\
    }while(0)

解析结果

教程7.png