- Used to convert between C++ structure and json/xml, bson is supported in xbson.
- Only header files, no need to compile library files, so there is no Makefile.
- For details, please refer to the example
- Quick start
- Container Support
- FLAG
- Alias
- Bitfield
- Inherit
- enum
- Custom codec
- union
- Schema indeterminate type
- Define macro outside the structure
- Array
- Format indentation
- XML array
- CDATA
- Qt support
- Important note
- Use macro
XPACK
(orXPACK_OUT
if you don't want to change the structure) include structure members - Use xpack::json::encode to convert structure to json
- Use xpack::json::decode to convert json to structure
#include <iostream>
#include "xpack/json.h" // include this header file for json or "xpack/xml.h" for xml
using namespace std;
struct User {
int id;
string name;
XPACK(O(id, name)); // Add XPACK at the end of structure, up to 99 'O' can be added, and each 'O' can contain up to 99 members
};
int main(int argc, char *argv[]) {
User u;
string data = "{\"id\":12345, \"name\":\"xpack\"}";
xpack::json::decode(data, u); // json to structure
cout<<u.id<<';'<<u.name<<endl;
string json = xpack::json::encode(u); // structure to json
cout<<json<<endl;
return 0;
}
The following containers are currently supported (std)
- vector
- set
- list
- map<string, T>
- map<integer, T> // only for json
- unordered_map<string, T> (need C++11)
- shared_ptr (need C++11)
In the macro XPACK
, variables need to be enclosed with letters, such as XPACK(O(a,b))
, XPACK
can contain multiple letters, and each letter can contain multiple variables. Currently supported letters are:
- X Usage: X(F(flag1, flag2...), member1, member2,...) Multiple flags can be written in 'F', currently supported flags are:
- 0 no flag
- OE omitempty. When encoding, if the variable is 0 or an empty string or false, the variable is ignored
- EN empty as null. When json encoding, encode empty variable as null(OE is ignore the variable)
- M mandatory. When decoding, if the key corresponding to the variable does not exist, an exception is thrown
- ATTR attribute. When xml encode, put the value in attribute
- SL single line, When json encoding, put vector in single line
- C Usage: C(customcodec, F(flag1,flags...), member1, member2,...) For custom codec function, please refer to Custom codec for details
- O Usage: O(member1, member2, ...) Same as X(F(0), member1, member2, ...) no flags
- M Usage: M(member1, member2, ...) Same as X(F(M), member1, member2, ...) mandatory
- A Usage: A(member1, alias1, member2, alias2...) Used when the key and the variable name are different, please refer to Alias for details
- AF Usage: AF(F(flag1, flag2,...), member1, alias1, member2, alias2...) Alias with flags
- B Usage: B(F(flag1, flag2, ...), member1, member2, ...) For bitfield, please refer to Bitfield for details. bitfield not support alias
- I Usage: I(baseclass1, baseclass2....), baseclassx is parent class, please refer to Inherit for details
- E Usage: E(member1, member2) For enumeration variables that do not support C++11. E not support alias
- Used when the key and the variable name are different
- Usage: A(member1, alias1, member2, alias2...) or AF(F(flag1, flag2,...), member1, alias1, member2, alias2...), alias's format is "x t:n"
- x stands for global alias, not required
- t stands for type(currently support json/xml/bson), n stands for type alias, type alias is not required
- The order of precedence is: type alias, global alias, variable name
- For example,
id bson:_id
, in bson will use_id
and json/xml will useid
- Type alias can take some type flags, format is "t:n,flag1,flag2,...", currently supported flags are:
- cdata. For xml, indicates that it is cdata
- sbs. For xml vector, In normal,
vector<int> nums
will be encoded into<nums><nums>1</nums><nums>2</nums><nums>
, in sbs is<nums>1</nums><nums>2</nums>
#include <iostream>
#include "xpack/json.h"
using namespace std;
struct Test {
long uid;
string name;
XPACK(A(uid, "id"), O(name)); // "uid" use alias "id"
};
int main(int argc, char *argv[]) {
Test t;
string json="{\"id\":123, \"name\":\"Pony\"}";
xpack::json::decode(json, t);
cout<<t.uid<<endl;
return 0;
}
- Use 'B' include bitfield members. bitfield not support alias
#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<<t.ver<<endl;
cout<<t.len<<endl;
return 0;
}
- Use 'I' include parent classes. If you don't need variables from the parent class, you don't need use 'I'
- Parent class need add macro 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<<t.mail<<endl;
cout<<t.version<<endl;
return 0;
}
- If support C++11, enum is same as other type, use X/O/M/A is ok
- Otherwise need to use 'E', usage: 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<<t.name<<endl;
cout<<t.e<<endl;
return 0;
}
Used in scenarios where you want to define your own codec method, such as:
- Wish to encode numeric types in string or hexadecimal
- Don't want to encode the struct variable by variable:
struct Time {
long ts; //unix timestamp
};
Don't want to encode to {"ts":1218196800} but "2008-08-08 20:00:00"
There are two ways to achieve:
- Use xtype. You can refer to this example
- Use 'C' include members need to custome codec(Hereinafter referred to as the
C method
), You can refer to this example
Both methods need to implement custom codec, but there are some differences:
- xtype is at the type level, that is, once a certain type is encapsulated with xtype, the custom encode/decode will take effect for this type. xtype cannot be used for basic types (int/string, etc.)
- The C method can support basic types (int/string, etc.) and non-basic types, but only works on variables contained in C, such as
int a;
int b;
XPACK(O(a), C(custome_int, F(0), b ))
Then "a" still uses the default codec, and "b" uses the custom codec.
- xtype takes precedence over the XPACK macro, that is, if xtype is defined, the encode/decode of xtype will be used first
- The C method takes precedence over xtype, that is, the variables contained in C must use the codec method specified in C
With these two features, some more flexible codec control can be realized. For example, this example realizes a function of encoding according to the variable situation. If Sub.type==1, then encode seq1, Otherwise encode seq2. __x_pack_decode
and __x_pack_encode
are the decode/encode functions added to the structure by the XPACK macro, and the custom codec function can call the default codec function of xpack through these functions.
Unions can be handled using Custom codec. You can refer to this example
- When decoding, if the number of elements exceeds the length of the array, it will be truncated
- The char array needs to have a '\0' terminator
#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<<t.name<<endl;
cout<<t.email<<endl;
return 0;
}
- Json only
- Use xpack::JsonData for this kind of content
- You can refer to this example
- The main APIs for xpack::JsonData are:
- Type. To get the field type
- IsXXX. To check is the field type is xxx, same as
return Type()==xxxx;
- GetXXX. To get the field value
- operator bool. To check is't a valid xpack::JsonData
- Size. To get the array's elements number
operator [](size_t index)
. Used to get the index element in arrayoperator [](const char *key)
. Used to get the element by key in object- Iterator:
- Begin. Get the first element's iterator
- Next. Get the next iterator
- Key. Get the key of iterator
- Val. Get the value of iterator
- Use
XPACK_OUT
instead ofXPACK
to include structure members XPACK_OUT
must define in global namespace
#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<<s<<endl;
xpack::json::decode(s, r);
cout<<r.a<<','<<r.b<<','<<r.t.tv_sec<<','<<r.t.tv_usec<<endl;
return 0;
}
- The default encode is not indented, and the readability is not good
- If indentation is required, it can be controlled by the last two parameters of encode:
- indentCount Indicates the number of characters for indentation, <0 means no indentation, 0 means newline but no indentation
- indentChar Characters that represent indentation, use spaces or tabs
- Arrays use variable names as element labels by default, such as "ids":[1,2,3] will be encoded as:
<ids>
<ids>1</ids>
<ids>2</ids>
<ids>3</ids>
</ids>
- You can use alias to change the label name. For example: A(ids,"xml:ids,vl@id"), vl@id means to use id as label:
<ids>
<id>1</id>
<id>2</id>
<id>3</id>
</ids>
- If want to encode array element side by side, can use
sbs
flag. For example:A(ids, "xml:ids,sbs")
. Note that the sbs tag can only be used for arrays(vector), and it may crash if used elsewhere
<ids>1</ids>
<ids>2</ids>
<ids>3</ids>
- For xml CDATA, need to use
cdata
flag. For example: A(data, "xml:data,cdata") - variable type must be std::string
- Non-cdata types can also add cdata flag, which will be processed as ordinary strings
- Modify config.h to enable XPACK_SUPPORT_QT(or enable it in compile flags)
- Currently supports: QString/QMap/QList/QVector
- Try not to start the variable name with __x_pack, otherwise it may conflict with the library.
- vc6 is not supported
- msvc has only been tested on vs2019
- The serialization and deserialization of json uses rapidjson (November 2018 edition)
- The deserialization of xml uses rapidxml
- The serialization of xml is written by myself, without reference to RFC, there may be some differences from the standard.