一、背景
在C++项目开发中,不同的服务之间会定义通讯接口,接口格式定义中的通讯数据往往是json格式的。为了快速开发,我的需求如下:
1.定义好通讯接口后,就定义好了交互的json内容格式。我希望有工具可以一键将json内容转换成C++结构体;
2.服务交互过程中,我希望结构体数据和json内容可以相互转换,并且不需要写两者之间的转换代码。请注意:重点是不需要写两者之间的转换代码
二、解决方案
先说需求2,我在网上找到一个开源库,可以满足此需求,开源库介绍地址:
json与C++结构体互相转换_c++ 结构体转json_xyz347的博客-CSDN博客
gitee地址:xpack: 用于C++结构体和json/xml/bson/mysql的互相转换
简单介绍一下这个库的作用及用法:如下图所示,在结构体中增加XPACK宏定义,就可以轻松完成json字符串与结构体之间相互转换了,节省了大量的编写转换代码的时间。
也许有人会说,上图所示的结构体就2个变量,写转换代码几行就搞定了。
如果json的内容如下呢?写转换代码的工作量大不大呢?
{
"status": 0,
"message": "message",
"data": {
"search_data": [{
"elements": [{
"rating": 0,
"name": "奈良市",
"url": "/scenic/3/10052/",
"wish_to_go_count": 328,
"name_orig": "奈良市",
"visited_count": 1958,
"comments_count": 0,
"location": {
"lat": 34.685087,
"lng": 135.805
},
"has_experience": false,
"rating_users": 0,
"name_zh": "奈良市",
"name_en": "Nara",
"type": 3,
"id": 10052,
"has_route_maps": false,
"icon": "http://media.breadtrip.com/images/icons/2/city.png"
},
{
"rating": 0,
"name": "小樽市",
"url": "/scenic/3/26772/",
"wish_to_go_count": 266,
"name_orig": "小樽市",
"visited_count": 954,
"comments_count": 0,
"location": {
"lat": 43.190717,
"lng": 140.994662
},
"has_experience": false,
"rating_users": 0,
"name_zh": "小樽市",
"name_en": "Otaru",
"type": 3,
"id": 26772,
"has_route_maps": false,
"icon": "http://media.breadtrip.com/images/icons/2/city.png"
},
{
"rating": 0,
"name": "挪威",
"url": "/scenic/1/3258/",
"wish_to_go_count": 788,
"name_orig": "挪威",
"visited_count": 850,
"comments_count": 0,
"location": {
"lat": 60.472024,
"lng": 8.468946
},
"has_experience": false,
"icon": "http://media.breadtrip.com/images/icons/2/country.png",
"type": 1,
"id": 26773,
"has_route_maps": false,
"rating_users": 0
}
],
"type": "destination",
"title": "国外热门目的地"
},
{
"elements": [{
"rating": 0,
"name": "台湾",
"url": "/scenic/1/3660/",
"wish_to_go_count": 37947,
"name_orig": "台湾",
"visited_count": 15729,
"comments_count": 0,
"location": {
"lat": 23.69781,
"lng": 120.960515
},
"has_experience": false,
"icon": "http://media.breadtrip.com/images/icons/2/country.png",
"type": 1,
"id": 45012,
"has_route_maps": false,
"rating_users": 0
},
{
"rating": 0,
"name": "香港",
"url": "/scenic/1/3814/",
"wish_to_go_count": 23495,
"name_orig": "香港",
"visited_count": 31249,
"comments_count": 0,
"location": {
"lat": 22.396428,
"lng": 114.109497
},
"has_experience": false,
"icon": "http://media.breadtrip.com/images/icons/2/country.png",
"type": 1,
"id": 55012,
"has_route_maps": true,
"rating_users": 0
},
{
"rating": 0,
"name": "厦门",
"url": "/scenic/3/65012/",
"wish_to_go_count": 29887,
"name_orig": "厦门",
"visited_count": 26077,
"comments_count": 0,
"location": {
"lat": 24.477188,
"lng": 118.094398
},
"has_experience": false,
"rating_users": 0,
"name_zh": "厦门",
"name_en": "Xiamen",
"type": 3,
"id": 65012,
"has_route_maps": false,
"icon": "http://media.breadtrip.com/images/icons/2/city.png"
}
],
"type": "destination",
"title": "国内热门目的地"
}
],
"date_time": "2017-09-11 10:52:27.811321",
"elements": [{
"type": 1,
"data": [{
"platform": "android",
"image_url": "http://photos.breadtrip.com/covers_2017_09_05_d5b225291045767fcfa0508f3d96ae26.jpg?imageView/2/w/960/",
"html_url": "http://www.iqiyi.com/v_19rr8w7drg.html?dummy=&wx_uid2=wxidoG0a9jsIGfq1jln1HtWebMCOKKSQ"
},
{
"platform": "android",
"image_url": "http://photos.breadtrip.com/covers_2014_12_25_ed43331bac65ee0752f7e56116993b2c.jpg?imageView2/2/w/750/format/jpg/interlace/1/",
"html_url": "http://web.breadtrip.com/mobile/destination/topic/2387718817/"
},
{
"platform": "android",
"image_url": "http://photos.breadtrip.com/covers_2014_10_29_46217a91ace672787ed1fec4c2011b52.png?imageView2/2/w/750/format/jpg/interlace/1/",
"html_url": "http://web.breadtrip.com/mobile/destination/topic/2387718790/"
}
],
"desc": "广告banner"
},
{
"type": 11,
"data": [{
"title": "每日精选故事"
}],
"desc": ""
}
]
}
}
使用xpack开源库之后,只需要如下定义结构体即可,转换代码不需要你写!!
struct Location {
int lat;
int lng;
XPACK(O(lat, lng)); // 添加宏定义XPACK在结构体定义结尾
};
struct Elements2 {
int comments_count;
bool has_experience;
bool has_route_maps;
std::string icon;
int id;
Location location;
std::string name;
std::string name_en;
std::string name_orig;
std::string name_zh;
int rating;
int rating_users;
int type;
std::string url;
int visited_count;
int wish_to_go_count;
XPACK(O(comments_count, has_experience, has_route_maps, icon, id, location, name, name_en, name_orig, name_zh, rating, rating_users, type, url, visited_count, wish_to_go_count)); // 添加宏定义XPACK在结构体定义结尾
};
struct Search_data {
std::vector<Elements2> elements;
std::string title;
std::string type;
XPACK(O(elements, title, type)); // 添加宏定义XPACK在结构体定义结尾
};
struct Data2 {
std::string html_url;
std::string image_url;
std::string platform;
XPACK(O(html_url, image_url, platform)); // 添加宏定义XPACK在结构体定义结尾
};
struct Elements {
std::vector<Data2> data;
std::string desc;
int type;
XPACK(O(data, desc, type)); // 添加宏定义XPACK在结构体定义结尾
};
struct Data {
std::string date_time;
std::vector<Elements> elements;
std::vector<Search_data> search_data;
XPACK(O(date_time, elements, search_data)); // 添加宏定义XPACK在结构体定义结尾
};
struct Ticket {
Data data;
std::string message;
int status;
XPACK(O(data, message, status)); // 添加宏定义XPACK在结构体定义结尾
};
到此为止,我的需求2已经完美解决了。再说需求1,请看上面那段复杂的json示例,要根据这个json格式定义结构体,工作量大不大?有没有工具可以将上面的json转换成结构体定义?我在网上找了很久,找到一个勉强能用的,网址是:Instantly parse JSON in any language | quicktype
转换效果如下:
这个在线网站转换出来的结构体定义,我还需要手动添加XPACK宏才能配合xpack开源库
使用。为了追求极致的开发效率,我使用Qt5手撸了一个转换工具,工具使用效果如下:
如上图所示,只需要将json内容复制到工具的左侧输入框,然后点“生成”按钮,即可自动将结构体生成出来。
该转换工具的下载地址:https://download.csdn.net/download/liuguangzhou123/88053077
至此,我的需求已完美解决!