打印

vsfjson -- 不到500行的MCU json库

[复制链接]
2229|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
vsfopen|  楼主 | 2018-8-3 07:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 vsfopen 于 2018-8-3 08:44 编辑

坐标:https://gitee.com/versaloon/vsf_open/blob/master/vsf/component/tool/json

极简方式实现,不使用中间结构,不是用动态分配,不使用递归,不使用全局变量。
RAM只使用堆栈,做大堆栈使用的函数是vsfjson_set_number,使用68字节堆栈(4字节返回值和64字节字符串缓冲)。
支持json解析和json生成
json生成时候,数据保存接口由用户定义
资源按需分配,比如解析json的时候,如果没有调用vsfjson_get_number,编译器就可以优化去掉浮点数的部分。

目前代码vsfjson.c为391字节,不过刚刚写好,兼容性还没做太多测试,并且以后会增加一些其他API。

demo:
static int usrapp_json_write_str(void *param, char *ch, int len)
{
        struct vsf_transaction_buffer_t *buf = (struct vsf_transaction_buffer_t *)param;
        if (buf->buffer.buffer != NULL)
        {
                if ((buf->buffer.size - buf->position) >= len)
                {
                        memcpy(&buf->buffer.buffer[buf->position], ch, len);
                        buf->position += len;
                        return 0;
                }
        }
        return -1;
}

void usrapp_json_test(void)
{
        const char *json = "{\"obj\":{\"arr\":[0.01, 1.01],\"str\":\"abcd\"},\"uuid\":\"012376545672184\"}";
        double double_value;
        char buff[128];
        int len;

        char *result = vsfjson_get(json, "/obj/str");
        if (result != NULL)
        {
                len = vsfjson_get_string(result, NULL, 0);
                if (len < sizeof(buff))
                {
                        vsfjson_get_string(result, buff, len);
                }
        }
        result = vsfjson_get(json, "obj");
        if (result != NULL)
        {
                result = vsfjson_get(result, "str");
                if (result != NULL)
                {
                        len = vsfjson_get_string(result, NULL, 0);
                        if (len < sizeof(buff))
                        {
                                vsfjson_get_string(result, buff, len);
                        }
                }
        }
        result = vsfjson_get(json, "obj/arr/0");
        if (result != NULL)
        {
                len = vsfjson_get_number(result, &double_value);
        }

/*        "{
                "key0":1.0,
                "key1":true,
                "key2":["123", 4.56],
                "key3":null
        }
*/
        struct vsfjson_constructor_t c;
        struct vsf_transaction_buffer_t buf = { NULL, 0 };

        do
        {
                if (buf.buffer.size)
                {
                        if (buf.buffer.size < sizeof(buff))
                        {
                                buf.buffer.buffer = (uint8_t *)buff;
                                buf.position = 0;
                                vsfjson_constructor_init(&c, &buf, usrapp_json_write_str);
                        }
                        else
                                break;
                }
                else
                {
                        vsfjson_constructor_init(&c, NULL, NULL);
                }

                vsfjson_set_object(&c, NULL,
                {
                        vsfjson_set_number(&c, "key0", 1.0);
                        vsfjson_set_boolean(&c, "key1", true);
                        vsfjson_set_array(&c, "key2",
                        {
                                vsfjson_set_string(&c, NULL, "123");
                                vsfjson_set_number(&c, NULL, 4.67);
                        });
                        vsfjson_set_null(&c, "key3");
                });
                if (!c.write_str)
                        buf.buffer.size = c.len + 1;
                else
                        c.write_str(c.param, "\0", 1);
        } while (!buf.buffer.buffer);
}


API:
1. char *vsfjson_get(const char *json, const char *key);
从json字符串后,或者指定的key的值,key可以用路径的方式表示,比如"/obj/arr/2"(obj需要是object,arr需要是array)。
2. enum vsfjson_type_t vsfjson_enumerate_start(struct vsfjson_enumerator_t *e, const char *json);
vsfjson_enumerate_start用于枚举指定的json,只对array和object有效。struct vsfjson_enumerator_t为枚举器。
3. char *vsfjson_enumerate_next(struct vsfjson_enumerator_t *e);
枚举array或者object的时候,用来得到下一个值。
4. enum vsfjson_type_t vsfjson_get_type(const char *json);
得到json的类型,比如object、array、number、string等等。
5. int vsfjson_get_string(const char *json, char *result, int len);
对于string类型的json,读取字符串的值,并且返回长度。如果result为NULL,可以返回保存字符串需要的长度。
6. int vsfjson_get_number(const char *json, double *result);
对于number类型的json,读取double类型的值。
7. int vsfjson_get_boolean(const char *json, bool *result);
对于boolean类型的json,读取bool类型的值。
8. void vsfjson_constructor_init(struct vsfjson_constructor_t *c, void *param, int (*write_str)(void *, char *, int));
初始化struct vsfjson_constructor_t构造器,并且指定写数据的用户回调,如果用户回调设置为NULL的话,则用来计算生成的json数据长度。
9. vsfjson_set_object(c, key, member);
json构造器中,加入指定key的object,member要使用闭包的方式。比如:
vsfjson_set_object(&c, "KEY0",
{
  vsfjson_set_boolean(&c, "enabled", true);
});
如果key参数为NULL的话,则生成不带名字的object(一般其他的成员,都写在一个不带名字的object内)。
10. vsfjson_set_array(c, key, member);
类似vsfjson_set_object,不过这里member里的成员,都必须不带key。
11. int vsfjson_set_string(struct vsfjson_constructor_t *c, char *key, char *value);
json构造器中,加入string。生成"key":"value"
12. int vsfjson_set_number(struct vsfjson_constructor_t *c, char *key, double value);
json构造器中,加入number。生成"key":double(value)
13. int vsfjson_set_boolean(struct vsfjson_constructor_t *c, char *key, bool value);
json构造器中,加入boolean。生成"key":true/false
14. int vsfjson_set_null(struct vsfjson_constructor_t *c, char *key);
json构造器中,加入null。生成"key":null


使用特权

评论回复

相关帖子

沙发
linqing171| | 2018-8-9 22:11 | 只看该作者
json已经把几年前还到处见的xml打的满地找牙了。

使用特权

评论回复
板凳
vsfopen|  楼主 | 2018-8-9 22:17 | 只看该作者
linqing171 发表于 2018-8-9 22:11
json已经把几年前还到处见的xml打的满地找牙了。

是啊,我们还有小资源占用的xml库,不过现在确实不想用xml的,都懒得整理代码发布了。

使用特权

评论回复
地板
dbdxbdfbds| | 2019-6-18 20:09 | 只看该作者
在线等在线等

使用特权

评论回复
5
aaa5866518| | 2020-2-22 19:59 | 只看该作者
呵呵~~~~你怎么老这样说~~~

使用特权

评论回复
发新帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

90

主题

325

帖子

8

粉丝