Skip to content

Commit dfcd44c

Browse files
authored
support xml (#1)
* support xml and fix clang warning * support custom encode/decode * update readme
1 parent 2bbad3c commit dfcd44c

31 files changed

+5065
-100
lines changed

README.md

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
xpack
22
====
3-
* 用于在C++结构体和json之间互相转换, xml/bson将很快支持。
3+
* 用于在C++结构体和json/xml之间互相转换, bson将很快支持。
44
* 只需要头文件, 无需编译库文件。
5+
* 具体可以参考example的例子
56

67
------
78
* [基本用法](#基本用法)
@@ -11,9 +12,11 @@ xpack
1112
* [位域](#位域)
1213
* [继承](#继承)
1314
* [枚举](#枚举)
15+
* [自定义编解码](#自定义编解码)
1416
* [char数组](#char数组)
1517
* [第三方类和结构体](#第三方类和结构体)
1618
* [格式化缩进](#格式化缩进)
19+
* [XML数组](#xml数组)
1720
* [Qt支持](#qt支持)
1821
* [重要说明](#重要说明)
1922

@@ -89,6 +92,7 @@ FLAG
8992
- 0 没有任何FLAG
9093
- OE omitempty,encode的时候,如果变量是0或者空字符串或者false,则不生成对应的key信息
9194
- M mandatory,decode的时候,如果这个字段不存在,则抛出异常,用于一些id字段。
95+
- ATTR attribute,xml encode的时候,把值放到attribute里面。
9296
- O。等价于X(F(0), ...) 没有任何FLAG。
9397
- M。等价于X(F(M),...) 表示这些字段是必须存在的。
9498
- A。[别名](#别名),A(member1, alias1, member2, alias2...)
@@ -234,10 +238,22 @@ int main(int argc, char *argv[]) {
234238

235239
```
236240
241+
自定义编解码
242+
----
243+
应用场景:部分类型可能不想按结构体变量逐个编码,比如定义了一个时间结构体:
244+
```C++
245+
struct Time {
246+
long ts; //unix timestamp
247+
};
248+
```
249+
并不希望编码成{"ts":1218196800} 这种格式,而是希望编码成"2008-08-08 20:00:00"这种格式,这个时候就可以用自定义编解码实现。
250+
251+
- 可以参考[例子](example/xtype.cpp)
252+
237253
char数组
238254
----
239255
- **缺省是不支持char数组的**
240-
- 修改[config.h](config.h),使能XPACK_SUPPORT_CHAR_ARRAY这个宏即可。也可以直接在编译选项加上这个定义。
256+
- 修改[config.h](config.h)开启XPACK_SUPPORT_CHAR_ARRAY这个宏即可。也可以直接在编译选项加上这个定义。
241257
- **除了char,其他类型不支持数组**
242258

243259
```C++
@@ -311,11 +327,21 @@ int main(int argc, char *argv[]) {
311327

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

335+
XML数组
336+
----
337+
- 数组会用"x"作为标签,比如"ids":[1,2,3],对应的xml是:
338+
``` xml
339+
<ids>
340+
<x>1</x>
341+
<x>2</x>
342+
<x>3</x>
343+
</ids>
344+
```
319345

320346
Qt支持
321347
----
@@ -329,4 +355,6 @@ Qt支持
329355
- vc6不支持。
330356
- msvc没有做很多测试,只用2019做过简单测试。
331357
- json的序列化反序列化用的是[rapidjson](https://github.com/Tencent/rapidjson)
358+
- xml的反序列化用的是[rapidxml](http://rapidxml.sourceforge.net)
359+
- xml的序列化是我自己写的,没有参考RFC,可能有和标准不一样的地方.
332360
- 有疑问可以加QQ群878041110

example/alias.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ using namespace std;
2222
struct Test {
2323
long uid;
2424
string name;
25-
XPACK(A(uid, "id"), O(name)); // "uid"的别名是"id"
25+
XPACK(A(uid, "id"), O(name));
2626
};
2727

2828
int main(int argc, char *argv[]) {

example/build_json.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (C) 2021 Duowan Inc. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing,
11+
* software distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <iostream>
18+
#include "xpack/json.h"
19+
20+
using namespace std;
21+
22+
int main(int argc, char *argv[]) {
23+
xpack::JsonEncoder en;
24+
en.ObjectBegin(NULL);
25+
26+
vector<int> vi(3);
27+
vi[0] = 1;
28+
vi[1] = 2;
29+
vi[2] = 3;
30+
en.encode("vv", vi, NULL);
31+
en.ObjectEnd(NULL);
32+
cout<<en.String()<<endl;
33+
return 0;
34+
}

example/makefile

100644100755
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
ifeq ($(GPP),)
2+
GPP=g++
3+
endif
4+
15
SRC=$(wildcard *.cpp)
26
TAR=$(basename $(SRC))
37

48
%:%.cpp
5-
g++ -o $@ $< -I ../.. -DXPACK_SUPPORT_CHAR_ARRAY
9+
$(GPP) -o $@ $< -I ../.. -DXPACK_SUPPORT_CHAR_ARRAY
610
@echo ============ run $@ ================
711
@./$@
812
@-rm $@

example/msvc.make

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
SRC=$(wildcard *.cpp)
2+
TAR=$(SRC:.cpp=.exe)
3+
4+
%.exe:%.cpp
5+
cl /Fe:${CURDIR}/$@ $< /EHsc -I ../.. -DXPACK_SUPPORT_CHAR_ARRAY
6+
@echo ============ run $@ ================
7+
@$@
8+
9+
tar:$(TAR)
10+
@echo -------test done-------
11+
@-del *.obj
12+
@-del *.exe

example/my_encoder.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <iostream>
2+
#include "xpack/json.h"
3+
4+
class MemberList {
5+
public:
6+
std::vector<std::string> members;
7+
8+
template<class T>
9+
bool encode(const char *key, const T&val, const xpack::Extend *ext) {
10+
members.push_back(std::string(key));
11+
return true;
12+
}
13+
};
14+
15+
template <class T>
16+
std::string GetMembers(const T&val) {
17+
MemberList m;
18+
val.__x_pack_encode(m, val, 0);
19+
20+
return xpack::json::encode(m.members);
21+
}
22+
23+
24+
struct Test {
25+
int a;
26+
int b;
27+
XPACK(O(a,b));
28+
};
29+
30+
int main(int argc, char *argv[]) {
31+
Test t;
32+
std::cout<<GetMembers(t)<<std::endl;
33+
return 0;
34+
}

example/xpack_out.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,21 @@
1414
* limitations under the License.
1515
*/
1616

17-
#include <sys/time.h>
17+
// #include <sys/time.h> linux only
1818
#include <iostream>
1919
#include "xpack/json.h"
20+
#ifndef _MSC_VER
21+
#include <sys/time.h>
22+
#endif
2023

2124
using namespace std;
2225

23-
/*
26+
#ifdef _MSC_VER
2427
struct timeval {
25-
time_t tv_sec;
26-
suseconds_t tv_usec;
28+
long tv_sec;
29+
long tv_usec;
2730
};
28-
*/
31+
#endif
2932

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

example/xtype.cpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright (C) 2021 Duowan Inc. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing,
11+
* software distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <iostream>
18+
#include "xpack/xtype.h"
19+
#include "xpack/json.h"
20+
#include "xpack/xml.h"
21+
22+
using namespace std;
23+
24+
struct Date {
25+
long unix_time;
26+
};
27+
28+
namespace xpack { // must define in namespace xpack
29+
30+
template<>
31+
struct is_xpack_xtype<Date> {static bool const value = true;};
32+
33+
// implement decode
34+
template<class OBJ>
35+
bool xpack_xtype_decode(OBJ &obj, const char*key, Date &val, const Extend *ext) {
36+
std::string str;
37+
obj.decode(key, str, ext);
38+
if (str.empty()) {
39+
return false;
40+
}
41+
42+
#ifndef _MSC_VER
43+
tm ttm;
44+
45+
if (0 != strptime(str.c_str(), "%Y-%m-%d %H:%M:%S", &ttm)) {
46+
val.unix_time = mktime(&ttm);
47+
} else {
48+
val.unix_time = 0;
49+
}
50+
#else
51+
static int days[]={31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 32};
52+
struct tm ttm={0};
53+
sscanf_s(str.c_str(), "%d-%d-%d %d:%d:%d", &ttm.tm_year, &ttm.tm_mon, &ttm.tm_mday, &ttm.tm_hour, &ttm.tm_min, &ttm.tm_sec);
54+
ttm.tm_mon-=1; // mon[0-11]
55+
ttm.tm_year-=1900; // since 1900
56+
val.unix_time = mktime(&ttm);
57+
#endif
58+
return true;
59+
}
60+
61+
// implement encode
62+
template<class OBJ>
63+
bool xpack_xtype_encode(OBJ &obj, const char*key, const Date &val, const Extend *ext) {
64+
time_t tt = (time_t)val.unix_time;
65+
tm ttm;
66+
67+
#ifndef _MSC_VER
68+
localtime_r(&tt, &ttm);
69+
#else
70+
localtime_s(&ttm, &tt);
71+
#endif
72+
73+
char buf[64];
74+
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ttm);
75+
return obj.encode(key, buf, ext);
76+
}
77+
78+
}
79+
80+
struct User {
81+
int64_t id;
82+
string name;
83+
string mail;
84+
Date d;
85+
User(int64_t i=0, const string& n="", const string& m="", long _d=0):id(i),name(n),mail(m){d.unix_time = _d;}
86+
XPACK(O(id, name, mail, d));
87+
};
88+
89+
struct Group {
90+
string name;
91+
int64_t master;
92+
vector<User> members;
93+
XPACK(O(name, master, members));
94+
};
95+
96+
int main(int argc, char *argv[]) {
97+
Group g;
98+
g.name = "C++";
99+
g.master = 2019;
100+
g.members.resize(2);
101+
g.members[0] = User(1, "Jack", "jack@xpack.com", 1);
102+
g.members[1] = User(2, "Pony", "pony@xpack.com", 1609249232);
103+
104+
string json = xpack::json::encode(g, 0, 2, ' ');
105+
cout<<json<<endl;
106+
107+
string xml = xpack::xml::encode(g, "root", 0, 2, ' ');
108+
cout<<xml<<endl;
109+
110+
Group n1;
111+
xpack::json::decode(json, n1);
112+
cout<<n1.name<<';'<<n1.members[0].name<<';'<<n1.members[0].d.unix_time<<endl;
113+
114+
Group n2;
115+
xpack::xml::decode(xml, n2);
116+
cout<<n2.name<<';'<<n2.members[1].name<<';'<<n2.members[1].d.unix_time<<endl;
117+
118+
return 0;
119+
}

extend.h

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ namespace xpack {
3131
#define X_PACK_FLAG_OE (1<<0) // omitempty, in encode
3232
#define X_PACK_FLAG_M (1<<1) // mandatory, in decode
3333

34+
#define X_PACK_FLAG_ATTR (1<<15) // for xml encode, encode in attribute
35+
3436
// control flag
3537
#define X_PACK_CTRL_FLAG_INHERIT (1<<0)
3638

@@ -97,28 +99,31 @@ struct Extend {
9799
}
98100
}
99101

100-
int Flag() const {
101-
if (NULL == this) {
102+
static int Flag(const Extend *ext) {
103+
if (NULL == ext) {
102104
return 0;
103105
} else {
104-
return flag;
106+
return ext->flag;
105107
}
106108
}
107109

108-
int CtrlFlag() const {
109-
if (NULL == this) {
110+
static int CtrlFlag(const Extend *ext) {
111+
if (NULL == ext) {
110112
return 0;
111113
} else {
112-
return ctrl_flag;
114+
return ext->ctrl_flag;
113115
}
114116
}
115117

116118

117-
bool OmitEmpty() const {
118-
return NULL!=this && (this->flag&X_PACK_FLAG_OE);
119+
static bool OmitEmpty(const Extend *ext) {
120+
return NULL!=ext && (ext->flag&X_PACK_FLAG_OE);
121+
}
122+
static bool Mandatory(const Extend *ext) {
123+
return NULL!=ext && (ext->flag&X_PACK_FLAG_M);
119124
}
120-
bool Mandatory() const {
121-
return NULL!=this && (this->flag&X_PACK_FLAG_M);
125+
static bool Attribute(const Extend *ext) {
126+
return NULL!=ext && (ext->flag&X_PACK_FLAG_ATTR);
122127
}
123128
};
124129

0 commit comments

Comments
 (0)