SuperJson-超级Json解析和生成器

一款强大简单高性能的Json解析和生成器

设计的初衷有两个。希望能设计最佳性能而又强大的Json解析器。类似芯片一样,追求更高性能的芯片。
第二个初衷是,希望Json源文件数量少,容易导入项目。希望有更丰富的错误提示,让开发简单一点。更重要的是,希望有更高效的解析效率,甚至可以轻松解析几百MB大小的Json文件。根据多年的经验,设计出这款超级Json解析和生成器

介绍

SuperJson是一个Json解析器和生成器,它的设计遵循着无语言特性,可以用任何编程语言实现,目前暂时实现C++版本。

  • SuperJson很迷你,代码行数不超过2000,但功能相对完善。
  • SuperJson解析是非常快速,直接复制一份json数据,在此基础上,不会进行任何字符串切割,只是标记每个值的位置pos和len, 用node-tree的方式管理这些节点node。因此,它解析大json文件非常快速。只有取值的时候,才根据标记去获得相应的值。
    如果是字符串,直接返回json数据的内存所在地址,该内存片段末尾被置为0,确保是c语言字符串,当然也有字段记录数据片段的大小,以防数据缺失。如果获取的值是数值,会生成segment片段,记录此数值。
  • SuperJson使用节点node管理的,节点管理通过c语言数组实现,保证迭代json节点的高效。有四种节点node,这四种节点继承jsonnode。父类jsonnode是root节点,否则其子类就是子节点。子节点有NumberNode,StringNode,ObjectNode,ArrayNode四个,对应记录的json类型。root节点不记录任何值,只保存了树根节点。
  • SuperJson的内存管理很高效,当然还有进一步优化的空间。
    注意:不能释放SuperJson返回都内存,即使是write操作返回json字符串,也不能进行释放。因为它已经绑定到root节上。root节点释放,它就会自动被释放。

配置

只有源文件SuperJson.h和SuperJson.cpp,无其他依赖。跑测试例子,可以使用cmake快速构建编译执行

运行测试

在superjson根目录下,建一个build文件节。

mkdir build

cd到build文件文件夹,执行cmake。

cmake ../

再执行make命令,就可以生成可执行程序
也可以用cmake可视化工具进行生成工程。非常简单,不在此介绍。

demo

1.解析json字符串

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "SuperJson.h"
using namespace SuperJson;
int main(int argc, char* argv[])
{
    const char* test = "{\
        \"bool1\":    true,\
        \"bool2\" :     false,\
        \"int\" :  323,\
        \"long\" :    2147483648,\
        \"double\" :    234.23\
        \"string\" : \"txt\"\
    }";
    printf("start:%s", test);

    //创建root对象,基类JsonNode实例对象都是root对象
    JsonNode root = JsonNode();
    //输入json格式数据
    root.read(test, strlen(test));

    //root对象,只包含了一个子节点,这个子节点就是json的数据结构
    JsonNode* node = root.array(0);
    //由于json数据,是一个object,所以它必定是ObjectNode
    assert(node->isObject());

    //取出字段bool1的节点,此节点保存了数值,同时还保存了key节点
    JsonNode* bool1node = node->object("bool1");
    printf("key=%s value=%d\n", bool1node->getKey(), (int)bool1node->getBool());

    //同上
    JsonNode* bool2node = node->object("bool2");
    printf("key=%s value=%d\n", bool2node->getKey(), (int)bool2node->getBool());

    JsonNode* intnode = node->object("int");
    printf("key=%s value=%d\n", intnode->getKey(), intnode->getInteger());

    JsonNode* longnode = node->object("long");
    printf("key=%s value=%ld\n", longnode->getKey(), longnode->getLong());

    JsonNode* doublenode = node->object("double");
    printf("key=%s value=%lf\n", doublenode->getKey(), doublenode->getDouble());
    printf("for==>>\n");
    JsonNode* child;
    //Object和Array都是通过c语言数组保存,通过接口count()获得子节点的数量
    for (size_t i=0; i<node->count(); ++i)
    {
        //JsonNode& child = (*node)[i];
        child = node->array(i);
        //子节点的key节点丢弃,一般在Array节点存在
        if (child->getKey() == JsonNode::none) 
            printf("JsonNode type=%s, number=%lf\n", child->getTypeName(), child->getNumber());
        else 
            printf("JsonNode type=%s, key=%s, number=%lf\n", child->getTypeName(),child->getKey(), child->getNumber());
    }

    size_t len;
    //把解析出的json,再生成会json字符串数据
    const char* buffer = root.write(&len);
    printf("finish:%s", buffer);
    return 0;
}

2.解析json文件

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "SuperJson.h"
using namespace SuperJson;
int main(int argc, char* argv[])
{
    JsonNode* root = new JsonNode();
    //原json文件
    const char* src_file = "./TestCtrl.json";
    root->readFile(src_file);
    //再把它生成回去,用另一个文件保存
    const char* dst_file = "./TestCtrl123.json";
    root->writeFile(dst_file);
    return 0;
}

3.生成json数据

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "SuperJson.h"
using namespace SuperJson;
int main(int argc, char* argv[])
{
    //root节点
    JsonNode root = JsonNode();

    //创建一个ObjectNode节点  obj = {}
    JsonNode* object = root.newObjectNode();
    //放入到root节点,注意,root节点只能有一个节点
    root.addNode(object);

    //创建一个NumberNode节点  obj['bool'] = true
    JsonNode* numberb = root.newNumberNode();
    numberb->setBool(true);
    object->addNode("bool", numberb);

    //创建一个NumberNode节点  obj['int'] = 323
    JsonNode* numberi = root.newNumberNode();
    numberi->setInteger(323);
    object->addNode("int", numberi);

    //创建一个NumberNode节点  obj['double'] = 234.23
    JsonNode* numberd = root.newNumberNode();
    numberd->setDouble(234.23);
    object->addNode("double", numberd);
    {
        size_t len;
        //把此节点序列化成出来,打印
        const char* buffer = numberd->write(&len);
        printf("stringd:%s \n", buffer);
    }

    //创建一个NumberNode节点  obj['string'] = "test txt"
    JsonNode* stringd = root.newStringNode();
    const char* txt = "test txt";
    stringd->setString(txt, strlen(txt));
    object->addNode("string", stringd);

    //可以把每个节点序列化出来
    {
        size_t len;
        const char* buffer = stringd->write(&len);
        printf("stringd:%s\n", buffer);
    }
    {
        size_t len;
        const char* buffer = object->write(&len);
        printf("object:%s\n", buffer);
    }

    //最后生成整个json字符串
    size_t len;
    const char* buffer = root.write(&len);
    printf("finish:%s\n", buffer);
}

输出日志

stringd:"double":234.23 
stringd:"string":"test txt"
object:{"bool":1,"int":323,"double":234.23,"string":"test txt"}
finish:{"bool":1,"int":323,"double":234.23,"string":"test txt"}

4.迭代整个json结构

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "SuperJson.h"
using namespace SuperJson;

void iterFunc(JsonNode& node, int depth);
int main(int argc, char* argv[])
{
    const char* test = "{\
        \"bool1\":    true,\
        \"bool2\" :     false,\
        \"int\" :  323,\
        \"long\" :    2147483648,\
        \"double\" :    234.23\
        \"string\" : \"txt\"\
    }";
    JsonNode root = JsonNode();
    root.read(test, strlen(test));
    JsonNode* node = root.array(0);

    iterFunc(*node, 5);
}

void iterFunc(JsonNode& node, int depth)
{
    if (depth >= 7) return;
    switch (node.getType())
    {
    case JsonNode::STRING:
    case JsonNode::NUMBER:
        if (node.getKey() == JsonNode::none)
        {
            if (node.isNumber())
                printf("JsonNode index=%d,type=%s, number=%lf\n", node.getIndex(), node.getTypeName(), node.getNumber());
            else
                printf("JsonNode index=%d,type=%s, string=%s\n", node.getIndex(), node.getTypeName(), node.getString());
        }
        else
        {
            if (node.isNumber())
                printf("JsonNode index=%d, type=%s, key=%s, number=%lf\n", node.getIndex(), node.getTypeName(), node.getKey(), node.getNumber());
            else
                printf("JsonNode index=%d, type=%s, key=%s, string=%s\n", node.getIndex(), node.getTypeName(), node.getKey(), node.getString());
        }
        break;
    case JsonNode::ARRAY:
    case JsonNode::OBJECT:
        if (node.getKey() == JsonNode::none)
            printf("JsonNode:%d:%s\n", node.getIndex(), node.getTypeName());
        else
            printf("JsonNode:%d:%s:%s\n", node.getIndex(), node.getTypeName(), node.getKey());

        for (size_t i = 0; i < node.count(); ++i)
        {
            JsonNode& child = node[i];
            iterFunc(child, depth + 1);
        }
        break;
    case JsonNode::ROOT:
        for (size_t i = 0; i < node.count(); ++i)
        {
            JsonNode& child = node[i];
            iterFunc(child, depth + 1);
        }
        break;
    default:
        break;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容