convert json/xml/bson to c++ struct

Related tags

JSON json cpp xml bson struct
Overview

xpack

  • 用于在C++结构体和json/xml之间互相转换, bson在xbson中支持。
  • 只需要头文件, 无需编译库文件。
  • 具体可以参考example的例子

基本用法

#include <iostream>
#include "xpack/json.h" // 包含这个头文件

using namespace std;

struct User {
    int64_t id;
    string  name;
    string  mail;
    User(int64_t i=0, const string& n="", const string& m=""):id(i),name(n),mail(m){}
    XPACK(O(id, name, mail)); // 添加宏定义XPACK在结构体定义结尾
};

struct Group {
    string  name;
    int64_t master;
    vector members;
    XPACK(O(name, master, members)); // 添加宏定义XPACK在结构体定义结尾
};

int main(int argc, char *argv[]) {
    Group g;
    g.name = "C++";
    g.master = 2019;
    g.members.resize(2);
    g.members[0] = User(1, "Jack", "[email protected]");
    g.members[1] = User(2, "Pony", "[email protected]");

    string json = xpack::json::encode(g);  	// 结构体转json
    cout<xpack::json::decode(json, n); 			// json转结构体
    cout<name<int> vi;
    xpack::json::decode("[1,2,3]", vi); 	// 直接转换vector
    cout<size()<<','<1]<int> m;
    xpack::json::decode("{\"1\":10, \"2\":20}", m); // 直接转换map
    cout<size()<<','<"2"]<return 0;
}

步骤有:

  • 引用头文件 "xpack/json.h"
  • 添加宏定义XPACK在结构体结尾, 里面用"O"包含所有变量
  • 用xpack::json::encode将结构体转json
  • 用xpack::json::decode将json转结构体

容器支持

目前支持下列容器(std)

  • vector
  • set
  • list
  • map
  • unordered_map (需要C++11支持)
  • shared_ptr (需要C++11支持)

FLAG

宏XPACK里面,需要用字母将变量包含起来,比如XPACK(O(a,b)),目前支持的字母有:

  • X。格式是X(F(flag1, flag2...), member1, member2,...) F里面包含各种FLAG,目前支持的有:
    • 0 没有任何FLAG
    • OE omitempty,encode的时候,如果变量是0或者空字符串或者false,则不生成对应的key信息
    • M mandatory,decode的时候,如果这个字段不存在,则抛出异常,用于一些id字段。
    • ATTR attribute,xml encode的时候,把值放到attribute里面。
  • O。等价于X(F(0), ...) 没有任何FLAG。
  • M。等价于X(F(M),...) 表示这些字段是必须存在的。
  • A。别名,A(member1, alias1, member2, alias2...)
  • AF。带FLAG的别名,AF(F(flag1, flag2,...), member1, alias1, member2, alias2...)
  • B。位域,B(F(flag1, flag2, ...), member1, member2, ...) 位域不支持别名
  • I。继承,I(baseclass1, baseclass2....)
  • E。枚举:
    • 如果编译器支持C++11,不需要用E,枚举可以放X/O/M/A里面。
    • 否则枚举只能放E里面,不支持别名

别名

  • 用于变量名和key名不一致的场景
  • 格式是A(变量,别名....)或者AF(F(flags), 变量,别名....),别名的格式是"x t:n"的格式
    • x表示全局别名,t表示类型(目前支持json),n表示类型下的别名
    • 全局别名可以没有,比如"json:_id"是合法的
    • 类型别名可以没有,比如"_id"是合法的
    • 有类型别名优先用类型别名,否则用全局别名,都没有,则用变量名
#include <iostream>
#include "xpack/json.h"

using namespace std;

struct Test {
    long uid;
    string  name;
    XPACK(A(uid, "id"), O(name)); // "uid"的别名是"id"
};

int main(int argc, char *argv[]) {
    Test t;
    string json="{\"id\":123, \"name\":\"Pony\"}";

    xpack::json::decode(json, t); 
    cout<uid<return 0;
}

位域

  • 使用"B"来包含位域变量,位域不支持别名
#include <iostream>
#include "xpack/json.h"

using namespace std;

struct Test {
    short ver:8;
    short len:8;
    string  name;
    XPACK(B(F(0), ver, len), O(name)); 
};

int main(int argc, char *argv[]) {
    Test t;
    string json="{\"ver\":4, \"len\":20, \"name\":\"IPv4\"}";

    xpack::json::decode(json, t);
    cout<ver<len<return 0;
}

继承

  • 使用"I"来包含父类
  • 所有父类都需要包含,比如class Base; class Base1:public Base; class Base2:public Base1;那么在Base2中需要I(Base1, Base)
  • 父类也需要定义XPACK/XPACK_OUT宏。
#include <iostream>
#include "xpack/json.h"

using namespace std;

struct P1 {
    string mail;
    XPACK(O(mail));
};

struct P2 {
    long version;
    XPACK(O(version));
};

struct Test:public P1, public P2 {
    long uid;
    string  name;
    XPACK(I(P1, P2), O(uid, name)); 
};

int main(int argc, char *argv[]) {
    Test t;
    string json="{\"mail\":\"[email protected]\", \"version\":2019, \"id\":123, \"name\":\"Pony\"}";

    xpack::json::decode(json, t);
    cout<mail<version<return 0;
}

枚举

  • 如果编译器支持C++11,则枚举和普通变量名一样,放X/O/M/A里面皆可。
  • 否则需要放到E里面,格式是E(F(...), member1, member2, ...)
#include <iostream>
#include "xpack/json.h"

using namespace std;

enum Enum {
    X = 0,
    Y = 1,
    Z = 2,
};

struct Test {
    string  name;
    Enum    e;
    XPACK(O(name), E(F(0), e)); 
};

int main(int argc, char *argv[]) {
    Test t;
    string json="{\"name\":\"IPv4\", \"e\":1}";

    xpack::json::decode(json, t);
    cout<name<e<return 0;
}

自定义编解码

应用场景:部分类型可能不想按结构体变量逐个编码,比如定义了一个时间结构体:

struct Time {
    long ts; //unix timestamp
};

并不希望编码成{"ts":1218196800} 这种格式,而是希望编码成"2008-08-08 20:00:00"这种格式,这个时候就可以用自定义编解码实现。

char数组

  • 缺省是不支持char数组的
  • 修改config.h,开启XPACK_SUPPORT_CHAR_ARRAY这个宏即可。也可以直接在编译选项加上这个定义。
  • 除了char,其他类型不支持数组
#include <iostream>
#include "xpack/json.h"

using namespace std;


struct Test {
    char  name[64];
    char  email[64];
    XPACK(O(name, email)); 
};

int main(int argc, char *argv[]) {
    Test t;
    string json="{\"name\":\"Pony\", \"email\":\"[email protected]\"}";

    xpack::json::decode(json, t);
    cout<name<email<return 0;
}

第三方类和结构体

  • 用XPACK_OUT而非XPACK来包含变量
  • XPACK_OUT必须定义在全局命名空间
#include <sys/time.h>
#include <iostream>
#include "xpack/json.h"

using namespace std;

/*
struct timeval {
    time_t      tv_sec;
    suseconds_t tv_usec;
};
*/

// timeval is thirdparty struct
XPACK_OUT(timeval, O(tv_sec, tv_usec));

struct T {
    int  a;
    string b;
    timeval t;
    XPACK(O(a, b, t));
};


int main(int argc, char *argv[]) {
    T t;
    T r;
    t.a = 123;
    t.b = "xpack";
    t.t.tv_sec = 888;
    t.t.tv_usec = 999;
    string s = xpack::json::encode(t);
    cout<xpack::json::decode(s, r);
    cout<a<<','<b<<','<t.tv_sec<<','<t.tv_usec<return 0;
}

格式化缩进

  • encode缺省生成的json/xml是没有缩进的,适合程序使用,如果让人读,可以进行缩进。
  • encode的最后两个参数控制
    • indentCount 表示缩进的字符数,<0表示不缩进,0则是换行但是不缩进
    • indentChar 表示缩进的字符,用空格或者制表符

XML数组

  • 数组默认会用"x"作为标签,比如"ids":[1,2,3],对应的xml是:
<ids>
    <x>1x>
    <x>2x>
    <x>3x>
ids>
  • 可以用别名的方式来控制数组的标签,比如A(ids,"xml:ids,[email protected]"),vl后面跟着一个@xx,xx就是数组的标签,生成的结果就是:
<ids>
    <id>1id>
    <id>2id>
    <id>3id>
ids>

Qt支持

  • 修改config.h,开启XPACK_SUPPORT_QT这个宏(或者在编译选项开启)
  • 当前支持 QString/QMap/QList/QVector

重要说明

  • 变量名尽量不要用__x_pack开头,不然可能会和库有冲突。
  • vc6不支持。
  • msvc没有做很多测试,只用2019做过简单测试。
  • json的序列化反序列化用的是rapidjson
  • xml的反序列化用的是rapidxml
  • xml的序列化是我自己写的,没有参考RFC,可能有和标准不一样的地方.
  • 有疑问可以加QQ群878041110
Issues
  • 能否加一下xpack::json::decode(rapidjson::Value*, T&)

    能否加一下xpack::json::decode(rapidjson::Value*, T&)

    json.h中有decode(std::string&, T&),可以满足字符串到对象的解析。但在实际应用中,可能需要对复杂结构体中的部分Value对象解析到Object中。参考现有代码,加起来应该比较简单,比如:

        template <class T>
        static void decode(const rapidjson::Value* value_data, T &val) {
            JsonDecoder doc(value_data);
            doc.decode(NULL, val, NULL);
        }
    
    opened by willkk 7
  • 解析map嵌套结构体bug

    解析map嵌套结构体bug

    map的value类型是结构体,解析有问题。 示例:

    struct value {
      int a;
      XPACK(O(a));
    };
    std::map<std::string, value>  map;
    xpack::json::decode("{\"123\":{\"a\":1011}, \"234\":{}}", map);
    cout << map.size() << ',' << map["123"].a << ',' << map["234"].a << endl;
    

    后面空的234的a跟前面123里面的a值一样,看起来是内部实现复用了结构体成员。

    opened by willkk 4
  • 空数组出错

    空数组出错

    json文本为:{"data":{"info":[]}}时,解析会出错。在document.h的IsArray出错。 struct Info { int base, Id; XPACK(O(base, Id)); }; struct dataInfo { std::vector data; XPACK(O(data)); }; dataInfo sInfo; xpack::json::decode("{"data":{"info":[]}}", sInfo);

    opened by motopx 3
  • Is it possible to add support for enum key based std::map?

    Is it possible to add support for enum key based std::map?

    Currently Im using the following workaround.

    // std::map<enum, T>
    template <typename TK, typename TV>
    struct is_xpack_xtype<std::map<TK, TV>> {
        static bool const value = true;
    };
    
    template <class OBJ, typename TK, typename TV>
    bool xpack_xtype_decode(OBJ& obj, const char* key, std::map<TK, TV>& val, const Extend* ext) {
        if constexpr (std::is_enum_v<TK>) {
            std::map<int64_t, TV> tmp;
            if (!obj.decode(key, tmp, ext)) {
                return false;
            }
            val.clear();
            for (auto&& item : tmp) {
                val[item.first] = item.second;
            }
            return true;
        } else {
            static_assert(false, "std::map with this key type is not supported to decode");
            return false;
        }
    }
    
    template <class OBJ, typename TK, typename TV>
    bool xpack_xtype_encode(OBJ& obj, const char* key, const std::map<TK, TV>& val, const Extend* ext) {
        if constexpr (std::is_enum_v<TK>) {
            std::map<TK, TV> tmp;
            for (auto&& item : val) {
                tmp[item.first] = item.second;
            }
            return obj.encode(key, tmp, ext);
        } else {
            static_assert(false, "std::map with this key type is not supported to encode");
            return false;
        }
    }
    
    opened by Zvicii 2
  • customize basetype's serialisation

    customize basetype's serialisation

    Dear developer, How could I do if I wanna to customize basetype's serialisation? For example, if I want to convert an int to its hex string representation during serialize or deserialize, current xtype.cpp cannot do this, its just warning "already defined" when I write template. Any suggestions well be welcome.

    opened by southern-dust 2
  • 结构体重命名

    结构体重命名

    项目主页上介绍了怎么对结构体的成员变量重命名 那是否可以对结构体重命名呢

    struct TimeSpan
    {
        string startTime;
        string endTime;
        XPACK(O(startTime, endTime));
    };
    struct CMSearchDescription
    {
        string           searchID;
        vector<TimeSpan> timeSpanList;
        XPACK(O(searchID, timeSpanList))
    };
    

    在最后的xml中,结构体TimeSpan对应的是timeSpan标签,我又不想在代码中将结构体名改为timeSpan,有什么办法吗

    opened by markwinds 2
  • int64_t encode 结果有问题

    int64_t encode 结果有问题

    struct JanusResponse {
    	std::string janus;
    	std::string transaction;		
    	int64_t session_id = -1;
    	int64_t sender = -1;
    	XPACK(O(janus, transaction, session_id, sender));
    };
    
    struct CreateSessionData {
    	int64_t id;
    	XPACK(O(id));
    };
    
    struct CreateSessionResponse : public JanusResponse {
    	CreateSessionData data;
    	XPACK(I(JanusResponse), O(data));
    };
    
    std::string js = "{\"janus\":\"success\",\"transaction\":\"RftQMdXKkq6q\",\"data\":{\"id\":6053426257610390}}";
    vi::CreateSessionResponse model;
    xpack::json::decode(js, model);
    
    std::string result = xpack::json::encode(model);
    
    你好,我发现decode结果是对的,encode的结果是错的,id的值不对。是我的用法不对?
    (在x2struct上能正确encode)
    
    opened by ouxianghui 2
  • 请教一个继承的问题

    请教一个继承的问题

    两个struct属继承关系

    struct A {
        string t1;
        XPACK(O(t1));
    };
    
    struct B : public A{
        string t2;
        XPACK(I(A), O(t2));
    };
    

    现在我有一个函数,接受的是A类型,但传递的是B类型,转成JSON字符串后B类型的数据丢了?

    VOID invoke(A a)
    {
        string data = xpack::json::encode(a); // data 没有 t2 ?
    }
    
    B b = {0};
    b.t1 = "111";
    b.t2 = "222";
    
    invoke(b);
    
    opened by endison1986 1
Releases(v1.0.2)
https://github.com/json-c/json-c is the official code repository for json-c. See the wiki for release tarballs for download. API docs at http://json-c.github.io/json-c/

\mainpage json-c Overview and Build Status Building on Unix Prerequisites Build commands CMake options Testing Building with vcpkg Linking to libjson-

json-c 2.5k Aug 2, 2022
JSON & BSON parser/writer

jbson is a library for building & iterating BSON data, and JSON documents in C++14. \tableofcontents Features # {#features} Header only. Boost license

Chris Manning 39 May 12, 2022
Convert YouTube Subscriptions JSON into RSS Reader Compatible OPML

OPMLify Convert YouTube Subscriptions JSON into RSS Reader Compatible OPML Brief Overview OPMLify allows you to import your YouTube Subscriptions to a

null 13 May 25, 2022
Convert runtime_block_states*.json from steadfast to more simplified format and use on other platforms (e.g. nukkit)

block_state_converter Convert runtime_block_states*.json from steadfast to more simplified format and use on other platforms. Example for Nukkit:

Alex 1 May 12, 2022
json-cpp is a C++11 JSON serialization library.

JSON parser and generator for C++ Version 0.1 alpha json-cpp is a C++11 JSON serialization library. Example #include <json-cpp.hpp> struct Foo {

Anatoly Scheglov 4 Dec 31, 2019
This is a JSON C++ library. It can write and read JSON files with ease and speed.

Json Box JSON (JavaScript Object Notation) is a lightweight data-interchange format. Json Box is a C++ library used to read and write JSON with ease a

Anhero inc. 108 Jul 7, 2022
A convenience C++ wrapper library for JSON-Glib providing friendly syntactic sugar for parsing JSON

This library is a wrapper for the json-glib library that aims to provide the user with a trivial alternative API to the API provided by the base json-

Rob J Meijer 16 May 10, 2022
json-build is a zero-allocation JSON serializer compatible with C89

json-build is a zero-allocation JSON serializer compatible with C89. It is inspired by jsmn, a minimalistic JSON tokenizer.

Lucas Müller 27 Jul 26, 2022
Ultralightweight JSON parser in ANSI C

cJSON Ultralightweight JSON parser in ANSI C. Table of contents License Usage Welcome to cJSON Building Copying the source CMake Makefile Vcpkg Includ

Dave Gamble 7.7k Aug 5, 2022
JSON parser and generator for C/C++ with scanf/printf like interface. Targeting embedded systems.

JSON parser and emitter for C/C++ Features ISO C and ISO C++ compliant portable code Very small footprint No dependencies json_scanf() scans a string

Cesanta Software 611 Aug 5, 2022
C library for encoding, decoding and manipulating JSON data

Jansson README Jansson is a C library for encoding, decoding and manipulating JSON data. Its main features and design principles are: Simple and intui

Petri Lehtinen 2.7k Aug 4, 2022
A very sane (header only) C++14 JSON library

JeayeSON - a very sane C++14 JSON library JeayeSON was designed out of frustration that there aren't many template-based approaches to handling JSON i

Jeaye Wilkerson 128 Jun 7, 2022
Jsmn is a world fastest JSON parser/tokenizer. This is the official repo replacing the old one at Bitbucket

JSMN jsmn (pronounced like 'jasmine') is a minimalistic JSON parser in C. It can be easily integrated into resource-limited or embedded projects. You

Serge Zaitsev 3k Aug 8, 2022
JSON for Modern C++

Design goals Sponsors Integration CMake Package Managers Pkg-config Examples JSON as first-class data type Serialization / Deserialization STL-like ac

Niels Lohmann 31.2k Aug 11, 2022
A JSON parser in C++

JSON++ Introduction JSON++ is a light-weight JSON parser, writer and reader written in C++. JSON++ can also convert JSON documents into lossless XML d

Hong Jiang 485 Jul 23, 2022
🗄️ single header json parser for C and C++

??️ json.h A simple single header solution to parsing JSON in C and C++. JSON is parsed into a read-only, single allocation buffer. The current suppor

Neil Henning 506 Aug 2, 2022
A C++ library for interacting with JSON.

JsonCpp JSON is a lightweight data-interchange format. It can represent numbers, strings, ordered sequences of values, and collections of name/value p

null 6.6k Aug 4, 2022
Very low footprint JSON parser written in portable ANSI C

Very low footprint JSON parser written in portable ANSI C. BSD licensed with no dependencies (i.e. just drop the C file into your project) Never recur

James McLaughlin 1.2k Jul 28, 2022
A tiny JSON library for C++11.

json11 json11 is a tiny JSON library for C++11, providing JSON parsing and serialization. The core object provided by the library is json11::Json. A J

Dropbox 2.4k Aug 6, 2022