This article will show how to deserialize from JSON string or JSON file into C structure in one single line with ZetJsonCpp. Also, it will show how to perform some operations and serialize reflecting the changes.
It can also be downloaded from Github.
Introduction
Nowadays, JSON structure has become the most used in web apps to interchange data. This is because JSON is the simplest and most human readable format, so it is more friendly to use. This article aims to explain how to deserialize/serialize from/to json strings or files using zetjsoncpp
library in C++.
1. Deserialization
To serialize JSON variable is done using zetjsoncpp::deserialize
. Zet JsonCpp supports deserialization of the following types:
- Boolean
- Vector of booleans
- Map of booleans
- Number
- Vector of numbers
- Map of numbers
- String
- Vector of strings
- Map of strings
- Object
- Vector of objects
- Map of objects
2.1 Boolean
To deserialize a JSON boolean, it is done through JsonVarBoolean
as shown below:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarBoolean<>>("true");
2.2 Vector of Booleans
A JSON vector of booleans could be the following:
[true,false,true]
To deserialize a JSON vector of booleans, it is done through JsonVarVectorBoolean
as it shows below:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarVectorBoolean<>>(
"["
"true"
",false"
",true"
"]");
2.3 Map of Booleans
A JSON map of booleans could be the following:
{
"id1":true
,"id2":false
,"id3":true
}
To deserialize a JSON map of booleans, it is done through JsonVarMapBoolean
as it shows below:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarMapBoolean<>>(
"{"
"\"id1\":true"
",\"id2\":false"
",\"id3\":true"
"}");
2.4 Number
A JSON number could be the following:
To deserialize a JSON number, it is done through JsonVarNumber
as shown below:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarNumber<>>("1");
2.5 Vector of Numbers
A JSON vector of numbers could be the following,
[1,3.7e+2,-3]
To deserialize a JSON vector of numbers, it is done through JsonVarVectorNumber
as shown below:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarVectorNumber<>>(
"["
"1"
",3.7e+2"
",-3"
"]");
2.6 Map of Numbers
A JSON map of numbers could be the following:
{
"id1":1
,"id2":3.7e+2
,"id3":-3
}
To deserialize a JSON map of numbers, it is done through JsonVarMapNumber
as shown below:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarMapNumber<>>(
"{"
"\"id1\":1"
",\"id2\":3.7e+2"
",\"id3\":-3"
"}");
2.7 String
To deserialize a JSON string
, it is done through JsonVarString
as shown below:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarString<>>("\"my_string\"")
2.8 Vector of Strings
A JSON vector of string
s could be the following:
["string_1","string_2","string_3"]
To deserialize a vector of string
s, it is done through JsonVarVectorString
as shown below:
zetjsoncpp::deserialize<JsonVarVectorString<>>(
"["
"\"string_1\""
",\"string_2\""
",\"string_3\""
"]");
2.9 Map of Strings
A JSON map of string
s could be the following:
{
"id1":"string_1"
,"id2":"string_2"
,"id3":"string_3"
}
To deserialize a map of string
s, it is done through JsonVarMapString
as shown below:
JsonVarMapString<> *m3=zetjsoncpp::deserialize<zetjsoncpp::JsonVarMapString<>>(
"{"
"\"id1\":\"string_1\""
",\"id2\":\"string_2\""
",\"id3\":\"string_3\""
"}");
2.10 Object
Until now, it has seen a way to serialize primitive and structured types that are easy to understand. Now we present the method to deserialize JSON object that requires a little bit of setup. A JSON object is like a JSON map with different content on its values.
A JSON object could be the following:
{
"encoding":"UTF-8"
,"length":1000
,"use_space":false
}
List 2.1
Taking the example of list 2.1, in zetjsoncpp
, it defines JSON object using a structure in C as shown below:
typedef struct{
zetjsoncpp::JsonVarString<ZJ_CONST_CHAR("encoding")> encoding;
zetjsoncpp::JsonVarNumber<ZJ_CONST_CHAR("length")> length;
zetjsoncpp::JsonVarBoolean<ZJ_CONST_CHAR("use_space")> use_space;
}JsonSample;
List 2.2
Note:
You may have noticed ZJ_CONST_CHAR(s)
. This is a trick to pass literal string through variadic templates char by char, so that templates don't accept pass literal strings (i.e., const char *
) as a parameter.
And finally, to deserialize a json object, it is done through JsonVarObject
passing the type of structure to deserialize it has seen in list 2.2:
auto json_object=zetjsoncpp::deserialize<zetjsoncpp::JsonVarObject<JsonSample>>(
"{"
"\"encoding\":\"UTF-8\""
",\"length\":1000"
",\"use_space\":false"
"}");
If any variable has not been deserialized, because it does not exist in string/file, either it doesn't match json property name json with that defined in the C++ structure, it has to use isDeserialized()
to check whether the variable was deserialized or not.
For example:
if(json_object->encoding.isDeserialized()){
}
List 3.4
By default, any no deserialized variable the strings are set empty, numbers and booleans will set as 0
and false
respectively.
2.11 Vector of Objects
A JSON vector of objects could be as follows:
[{
"encoding":"UTF-8"
,"length":1000
,"use_space":false
},{
"encoding":"ANSII"
,"length":1500
,"use_space":true
}]
To deserialize a vector of objects, it is done through JsonVarVectorObject
passing the type of structure to deserialize it has seen in list 2.2:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarVectorObject<JsonSample>>(
"[{"
"\"encoding\":\"UTF-8\""
",\"length\":1000"
",\"use_space\":false"
"},{"
"\"encoding\":\"ANSII\""
",\"length\":1500"
",\"use_space\":true"
"}]");
2.12 Map of Objects
A json map of objects could be the following:
{
"id1":{
"encoding":"UTF-8"
,"length":1000
,"use_space":false
}
,"id2":{
"encoding":"ANSII"
,"length":1500
,"use_space":true
}
}
To deserialize a map of objects, it is done through JsonVarMapObject
passing the type of structure to deserialize it has seen in list 2.2:
zetjsoncpp::deserialize<zetjsoncpp::JsonVarMapObject<JsonSample>>(
"{"
"\"id1\":{"
"\"encoding\":\"UTF-8\""
",\"length\":1000"
",\"use_space\":false"
"}"
",\"id2\":{"
"\"encoding\":\"ANSII\""
",\"length\":1500"
",\"use_space\":true"
"}"
"}");
2. Serialize
To serialize JSON variable, it is done using zetjsoncpp::serialize
.
For example:
auto json_number=zetjsoncpp::deserialize<zetjsoncpp::JsonVarNumber<>>("2");
json_number=3.5;
std::cout << zetjsoncpp::serialize(json_var); << std::enl;
3. Example
In this section, it will see an example to deserialize almost all types mentioned in section 2. Let's suppose it has a file called sample.json with the following content:
{
"encoding" : "UTF-8",
"number": 3.34E-5,
"plug-ins" : [
"python",
"c++",
"ruby"
],
"indent" : { "length" : 3, "use_space": true },
"languages":[{
"code" : "en",
"general_texts": {
"general.hello_word":"Hello world!"
,"general.yes":"Yes"
,"general.no":"No"
}
},{
"code" : "es",
"general_texts": {
"general.hello_word":"Hola mundo!"
,"general.yes":"Si"
,"general.no":"No"
}
},{
"code" : "zh-CN",
"general_texts": {
"general.hello_word":"你好词"
,"general.yes":"是"
,"general.no":"没有"
}
}]
,"interpolations":{
"id_1":{
"type":"material"
,"channels":"rgb"
,"data":[
0.0,1.0,0.0,1000
,0.0,0.0,0.0,0
]
},"id_2":{
"type":"transform"
,"channels":"xyz"
,"data":[
0.0,1.0,0.0,1000
,0.0,0.0,0.0,0
]
}
}
}
List 3.1
We can associate JSON structure seen on list 3.1 with the following C structure with JSON vars:
#include "zetjsoncpp.h"
using zetjsoncpp::JsonVarNumber;
using zetjsoncpp::JsonVarBoolean;
using zetjsoncpp::JsonVarString;
using zetjsoncpp::JsonVarMapString;
using zetjsoncpp::JsonVarVectorNumber;
using zetjsoncpp::JsonVarVectorString;
using zetjsoncpp::JsonVarObject;
using zetjsoncpp::JsonVarVectorObject;
using zetjsoncpp::JsonVarMapObject;
typedef struct{
JsonVarNumber<ZJ_CONST_CHAR("length")> length;
JsonVarBoolean<ZJ_CONST_CHAR("use_space")> use_space;
}Ident;
typedef struct{
JsonVarString<ZJ_CONST_CHAR("code")> code;
JsonVarMapString<ZJ_CONST_CHAR("general_texts")> general_texts;
}Language;
typedef struct{
JsonVarString<ZJ_CONST_CHAR("type")> type;
JsonVarString<ZJ_CONST_CHAR("channels")> channels;
JsonVarVectorNumber<ZJ_CONST_CHAR("data")> data;
}Interpolation;
typedef struct
{
JsonVarString<ZJ_CONST_CHAR("encoding")> encoding;
JsonVarNumber<ZJ_CONST_CHAR("number")> number;
JsonVarVectorString<ZJ_CONST_CHAR("plug-ins")> plugins;
JsonVarObject<Ident,ZJ_CONST_CHAR("indent")> indent;
JsonVarVectorObject<Language,ZJ_CONST_CHAR("languages")> languages;
JsonVarMapObject<Interpolation,ZJ_CONST_CHAR("interpolations")> interpolations;
}SampleJson;
List 3.2
Below, you can see an example of deserialization, data manipulation of the loaded json object, and finally serialization to reflect the changes made.
int main(int argc, char *argv[]){
try{
auto json_object=zetjsoncpp::deserialize_file<JsonVarObject<SampleJson>>("sample.json");
std::cout << "---------------------------------------------------" << std::endl;
std::cout << " Before modifications:"<< std::endl;
std::cout << zetjsoncpp::serialize(json_object);
json_object->indent.use_space = false;
for(unsigned i = 0; i < json_object->plugins.size(); i++) {
json_object->plugins[i] =
"my_randomstring"+zetjsoncpp::zj_strutils::int_to_str(i+1);
}
for(auto it_map = json_object->interpolations.begin();
it_map != json_object->interpolations.end(); it_map++) {
for(auto it = it_map->second->data.begin();
it != it_map->second->data.end(); it++) {
*it = rand();
}
}
std::cout << "--------------------------------------------------" << std::endl;
std::cout << " After modifications:"<< std::endl;
std::cout << zetjsoncpp::serialize(json_object);
delete json_object;
}catch(std::exception & ex){
std::cerr << "Error:" << ex.what() << std::endl;
}
}
List 3.3
After its execution, the output shows the serialized json before and after the changes marked in bold,
---------------------------------------------------
Before modifications:
{
"encoding":"UTF-8",
"number":0.000033,
"plug-ins":
[
"python","c++","ruby"
],
"indent":
{
"length":3.000000,
"use_space":true
},
"languages":
[{
"code":"en",
"general_texts":
{
"general.hello_word":"Hello world!"
,"general.no":"No"
,"general.yes":"Yes"
}
},{
"code":"es",
"general_texts":
{
"general.hello_word":"Hola mundo!"
,"general.no":"No"
,"general.yes":"Si"
}
},{
"code":"zh-CN",
"general_texts":
{
"general.hello_word":"你好词"
,"general.no":"没有"
,"general.yes":"是"
}
}],
"interpolations":
{
"id_1":{
"type":"material",
"channels":"rgb",
"data":
[
0.000000,1.000000,0.000000,1000.000000,0.000000,0.000000,0.000000,0.000000
]
}
,"id_2":{
"type":"transform",
"channels":"xyz",
"data":
[
0.000000,1.000000,0.000000,1000.000000,0.000000,0.000000,0.000000,0.000000
]
}
}
}--------------------------------------------------
After modifications:
{
"encoding":"UTF-8",
"number":0.000033,
"plug-ins":
[
"my_randomstring1","my_randomstring2","my_randomstring3"
],
"indent":
{
"length":3.000000,
"use_space":false
},
"languages":
[{
"code":"en",
"general_texts":
{
"general.hello_word":"Hello world!"
,"general.no":"No"
,"general.yes":"Yes"
}
},{
"code":"es",
"general_texts":
{
"general.hello_word":"Hola mundo!"
,"general.no":"No"
,"general.yes":"Si"
}
},{
"code":"zh-CN",
"general_texts":
{
"general.hello_word":"你好词"
,"general.no":"没有"
,"general.yes":"是"
}
}],
"interpolations":
{
"id_1":{
"type":"material",
"channels":"rgb",
"data":
[
41.000000,18467.000000,6334.000000,26500.000000,19169.000000,
15724.000000,11478.000000,29358.000000
]
}
,"id_2":{
"type":"transform",
"channels":"xyz",
"data":
[
26962.000000,24464.000000,5705.000000,28145.000000,
23281.000000,16827.000000,9961.000000,491.000000
]
}
}
}
4. Compile
To compile the source code, you need cmake
tool to create its makefile or visualstudio solution and then compile the project:
cmake -H. -Bbuild
After its compilation, apart from generating the zetjsoncpp
library, it will generate executables called test and test_file respectively. The executable called test does basic operations to check its integrity, meanwhile test_file reads a JSON file with content seen in section 3..
5. Conclusion
This article has presented a straightforward way to deserialize a json content from string or file in a single line of code. The results are very optimal for production and because it is binded in a C structure, the user can know each field easily so it's clear to deal with. I hope you find this tool useful.
History
2021-04-7 ZetJsonCpp 2.0.1
- Fix bug when jsonvar c++ value mismatches with readed value
2021-02-15 ZetJsonCpp 2.0.0
- Added support for map/dictionary of elements
- Massive code organization and clean up
- Support uft-8 files with bom
- Support deserialize any json type (i.e., number/string/boolean/object, vector or map of elements)
2018-05-15 ZetJsonCpp 1.3.0
- Review version history to new format (
MAJOR.MINOR.PATCH
) - Behaviour on error/warning is done through a callback
setFunctionOnError
, setFunctionOnWarning
. If these functions are not set, then the message is printed with fprintf
(stderr
) - Added memory leak detection (only for GNU toolchain). It needs
memmanager https://github.org/jespa007/memmanager
and pass -DMEMMANAGER
parameter on cmake
- Fixed
compile test_json
shared library on MSVC platform - Improve
cmake
message prints
2018-05-10 ZetJsonCpp 1.2.0
- Project is built through
cmake
- MSVC Support (v141 Tools or MSVC++ 2015)
- Added
zetjsoncpp namespace
- Renamed
fastjsoncpp
to zetjsoncpp
- Added feature detect array types
- Changed GPL3 license to MIT
2015-08-29 ZetJsonCpp 1.1.0
- Added feature support number as scientific notation (i.e., 2.1E-10)
- Added feature on detecting property group or property group arrays
- Fixed carry return line feeds compatible for Windows
2014-08-08 ZetJsonCpp 1.0.0