เอ็กซ์แพ็ก
ภาษาอังกฤษ
- ใช้ในการแปลงระหว่างโครงสร้าง C++ และ json/xml/yaml/bson/mysql/sqlite
- มีเพียงไฟล์ส่วนหัวเท่านั้น ไม่จำเป็นต้องคอมไพล์ไฟล์ไลบรารี ดังนั้นจึงไม่มี Makefile
- รองรับ bson ขึ้นอยู่กับ
libbson-1.0
จำเป็นต้องติดตั้งด้วยตัวเอง ยังไม่ผ่านการทดสอบทั้งหมด โปรดดูรายละเอียดที่ README - รองรับ MySQL และขึ้นอยู่กับ
libmysqlclient-dev
ซึ่งจำเป็นต้องติดตั้งด้วยตัวเอง ไม่ได้ทดสอบอย่างเต็มที่ - รองรับ Sqlite และขึ้นอยู่กับ libsqlite3 ซึ่งจำเป็นต้องติดตั้งด้วยตัวเอง ไม่ได้ทดสอบอย่างเต็มที่
- รองรับ yaml ขึ้นอยู่กับ yaml-cpp ต้องติดตั้งด้วยตัวเอง ไม่ได้ทดสอบอย่างเต็มที่
- สำหรับรายละเอียด โปรดดูตัวอย่าง
- การใช้งานขั้นพื้นฐาน
- รองรับคอนเทนเนอร์
- ธง
- นามแฝง
- ฟิลด์บิต
- สืบทอด
- แจกแจง
- ตัวแปลงสัญญาณที่กำหนดเอง
- สหภาพแรงงาน
- ประเภทไม่แน่นอน
- อาร์เรย์
- คลาสและโครงสร้างของบุคคลที่สาม
- เยื้องรูปแบบ
- อาร์เรย์ XML
- ซีดีดาต้า
- รองรับคิวที
- MySQL
- หมายเหตุสำคัญ
การใช้งานขั้นพื้นฐาน
- มาโคร XPACK ถูกใช้หลังโครงสร้างเพื่อให้มีตัวแปรแต่ละตัว XPACK ยังต้องใช้ตัวอักษร โปรดดูที่ FLAG สำหรับความหมายของตัวอักษรที่แตกต่างกัน
- ใช้ xpack::json::encode เพื่อแปลงโครงสร้างเป็น json
- ใช้ xpack::json::decode เพื่อแปลง json เป็นโครงสร้าง
# include < iostream >
# include " xpack/json.h " // Json包含这个头文件,xml则包含xpack/xml.h
using namespace std ;
struct User {
int id;
string name;
XPACK (O(id, name)); // 添加宏定义XPACK在结构体定义结尾
};
int main ( int argc, char *argv[]) {
User u;
string data = " { " id " :12345, " name " : " xpack " } " ;
xpack::json::decode (data, u); // json转结构体
cout<<u. id << ' ; ' <<u. name <<endl;
string json = xpack::json::encode (u); // 结构体转json
cout<<json<<endl;
return 0 ;
}
รองรับคอนเทนเนอร์
ปัจจุบันรองรับคอนเทนเนอร์ต่อไปนี้ (std)
- เวกเตอร์
- ชุด
- รายการ
- แผนที่<สตริง, T>
- map<integer, T> // JSON เท่านั้น ไม่รองรับ XML
- unordered_map<string, T> (ต้องรองรับ C++11)
- shared_ptr (ต้องรองรับ C++11)
ธง
ในมาโคร XPACK ตัวแปรจะต้องรวมไว้กับตัวอักษร เช่น XPACK(O(a,b)) XPACK สามารถมีตัวอักษรได้หลายตัว และตัวอักษรแต่ละตัวสามารถมีตัวแปรได้หลายตัว ตัวอักษรที่รองรับในปัจจุบันคือ:
- เอ็กซ์ รูปแบบคือ X(F(flag1, flag2...), member1, member2,...) F มี FLAG ต่างๆ ที่รองรับในปัจจุบันคือ:
- 0 ไม่มีธง
- OE ละเว้น เมื่อเข้ารหัส หากตัวแปรเป็น 0 หรือสตริงว่างหรือเท็จ ข้อมูลคีย์ที่เกี่ยวข้องจะไม่ถูกสร้างขึ้น
- EN ว่างเปล่าเป็น null ซึ่งใช้สำหรับการเข้ารหัส json OE เป็นฟิลด์ที่ไม่สร้างค่าว่างโดยตรง ในขณะที่ EN จะสร้างค่า null
- M บังคับ เมื่อถอดรหัส หากไม่มีฟิลด์นี้ ข้อยกเว้นจะถูกส่งออกไป ใช้สำหรับฟิลด์ ID บางฟิลด์
- แอตทริบิวต์ ATTR เมื่อเข้ารหัส xml ให้ใส่ค่าลงในแอตทริบิวต์
- SL บรรทัดเดียว เมื่อ json เข้ารหัส สำหรับอาร์เรย์ ให้รวมไว้ในบรรทัดเดียว
- ค. รูปแบบคือ C(customcodec, F(flag1,flags...), member1, member2,...) สำหรับฟังก์ชันการเข้ารหัสและถอดรหัสแบบกำหนดเอง สำหรับรายละเอียด โปรดดูที่ Custom Codec
- โอ เทียบเท่ากับ X(F(0), ...) โดยไม่มี FLAG ใด ๆ
- ม. เทียบเท่ากับ X(F(M),...) ที่ระบุว่าต้องมีช่องเหล่านี้อยู่
- ก. นามแฝง, A(member1, alias1, member2, alias2...) ใช้เมื่อชื่อตัวแปรและคีย์แตกต่างกัน
- เอเอฟ นามแฝงที่มี FLAG, AF(F(flag1, flag2,...), member1, alias1, member2, alias2...)
- บี. Bitfield, B(F(flag1, flag2, ...), member1, member2, ...) bitfield ไม่รองรับนามแฝง
- ฉัน. การสืบทอด I(baseclass1, baseclass2....) ใส่คลาสพาเรนต์ไว้
- อี. แจกแจง:
- หากคอมไพลเลอร์รองรับ C++11 ก็ไม่จำเป็นต้องใช้ E และสามารถระบุการแจงนับใน X/O/M/A ได้
- มิฉะนั้น การแจงนับสามารถวางไว้ใน E เท่านั้น และไม่รองรับนามแฝง
นามแฝง
- ใช้สำหรับสถานการณ์ที่ชื่อตัวแปรและชื่อคีย์ไม่สอดคล้องกัน
- รูปแบบคือ A(ตัวแปร, นามแฝง....) หรือ AF(F(แฟล็ก), ตัวแปร, นามแฝง....) และรูปแบบนามแฝงคือรูปแบบ "xt:n"
- x แสดงถึงนามแฝงส่วนกลาง t แสดงถึงประเภท (ปัจจุบันรองรับ json, xml และ bson) และ 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<<t. uid <<endl;
return 0 ;
}
ฟิลด์บิต
- ใช้ "B" เพื่อรวมตัวแปร Bitfield ไม่รองรับนามแฝง
# 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 ;
}
สืบทอด
- ใช้ "I" เพื่อรวมคลาสผู้ปกครอง หากคุณต้องการใช้ตัวแปรของคลาสพาเรนต์ ให้รวมตัวแปรเหล่านั้นด้วย หากคุณไม่ต้องการ คุณไม่จำเป็นต้องรวมตัวแปรเหล่านั้น
- จำเป็นต้องรวมคลาสแม่ของคลาสแม่ด้วย เช่น class Base; class Base1:public Base; class Base2:public Base1;
- คลาสพาเรนต์ยังต้องกำหนดแมโคร 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 ;
}
แจกแจง
- หากคอมไพลเลอร์รองรับ 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<<t. name <<endl;
cout<<t. e <<endl;
return 0 ;
}
ตัวแปลงสัญญาณที่กำหนดเอง
สถานการณ์การใช้งาน
- ประเภทพื้นฐานบางประเภทต้องการเข้ารหัสด้วยวิธีที่กำหนดเอง เช่น การใช้สตริงเพื่อเข้ารหัสจำนวนเต็ม/ตัวเลขทศนิยม
- บางประเภทอาจไม่ต้องการเข้ารหัสทีละรายการตามตัวแปรโครงสร้าง ตัวอย่างเช่น หากมีการกำหนดโครงสร้างเวลา:
struct Time {
long ts; // unix timestamp
};
เราไม่ต้องการเข้ารหัสเป็นรูปแบบ {"ts":1218196800} แต่เราต้องการเข้ารหัสเป็นรูปแบบ "2008-08-08 20:00:00"
มีสองวิธีที่นี่:
- การใช้ xtype คุณสามารถอ้างอิงถึงตัวอย่างได้
- ใช้ C เพื่อรวมตัวแปรที่ต้องมีการเข้ารหัสและถอดรหัสแบบกำหนดเอง (ต่อไปนี้จะเรียกว่าวิธี C) คุณสามารถอ้างอิงถึงตัวอย่างได้
ทั้งสองวิธีใช้การเข้ารหัส/ถอดรหัสด้วยตัวเองเป็นหลัก แต่มีข้อแตกต่างดังต่อไปนี้:
- xtype อยู่ที่ระดับประเภท กล่าวคือ เมื่อประเภทถูกห่อหุ้มด้วย xtype การเข้ารหัส/ถอดรหัสแบบกำหนดเองจะมีผลกับประเภทนี้ xtype ไม่สามารถใช้ได้กับประเภทพื้นฐาน (int/string ฯลฯ)
- เมธอด C สามารถรองรับประเภทพื้นฐาน (int/string ฯลฯ) และประเภทที่ไม่ใช่พื้นฐาน แต่ใช้ได้กับตัวแปรที่มีอยู่ใน C เท่านั้น เช่น int a; int b; O(a), C(custome_int, F(0 ), b) ;จากนั้น a ยังคงใช้ตัวแปลงสัญญาณเริ่มต้น และ b ใช้ตัวแปลงสัญญาณแบบกำหนดเอง
- xtype มีความสำคัญเหนือกว่ามาโคร XPACK นั่นคือหากมีการกำหนด xtype การเข้ารหัส/ถอดรหัสของ xtype จะถูกนำมาใช้ก่อน
- วิธี C มีความสำคัญเหนือกว่า xtype กล่าวคือ ตัวแปรที่อยู่ใน C จะใช้วิธีการเข้ารหัสและถอดรหัสที่ระบุใน C อย่างแน่นอน
เมื่อ __x_pack_decode
คุณลักษณะทั้งสองนี้ คุณสามารถบรรลุการควบคุมการเข้ารหัสและถอดรหัสที่ยืดหยุ่นมากขึ้น ตัวอย่างเช่น ตัวอย่างนี้ใช้ฟังก์ชันการเข้ารหัสตามเงื่อนไขของตัวแปร หาก Sub.type==1 ให้เข้ารหัส __x_pack_encode
หรือเข้ารหัส seq2 XPACK ฟังก์ชันถอดรหัส/เข้ารหัสที่เพิ่มโดยมาโครในโครงสร้าง ฟังก์ชันการเข้ารหัสและถอดรหัสแบบกำหนดเองสามารถเรียกใช้ฟังก์ชันการเข้ารหัสและถอดรหัสเริ่มต้นของ xpack ผ่านฟังก์ชันเหล่านี้
สหภาพแรงงาน
คุณสามารถใช้ตัวแปลงสัญญาณแบบกำหนดเองเพื่อประมวลผลสหภาพ โปรดดูตัวอย่าง
อาร์เรย์
- เมื่อถอดรหัส หากจำนวนองค์ประกอบเกินความยาวของอาร์เรย์ องค์ประกอบนั้นจะถูกตัดทอน
- อาร์เรย์ถ่านจะถูกประมวลผลเหมือนกับว่ามีจุดสิ้นสุด
# 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 ไม่แน่นอน
- ใช้ xpack::JsonData เพื่อรับข้อมูลนี้
- คุณสามารถดูตัวอย่างได้
- วิธีการหลักของ xpack::JsonData คือ:
- พิมพ์. เคยได้รับประเภท
- ฟังก์ชันชุด IsXXX ใช้เพื่อตรวจสอบว่าเป็นประเภทใดประเภทหนึ่ง โดยทั่วไปเทียบเท่ากับ return Type()==xxxx;
- ฟังก์ชันชุด GetXXX ใช้ในการดึงค่า
- โอเวอร์โหลดบูล ใช้เพื่อพิจารณาว่าเป็น JsonData ที่ถูกกฎหมายหรือไม่
- ขนาด. ใช้เพื่อกำหนดจำนวนองค์ประกอบในประเภทอาร์เรย์
-
operator [](size_t index)
ใช้เพื่อรับองค์ประกอบดัชนีของอาร์เรย์ (เริ่มจาก 0) -
operator [](const char *key)
ใช้เพื่อรับองค์ประกอบประเภท Object ตามคีย์ - เริ่ม. ใช้เพื่อสำรวจองค์ประกอบของ Object โดยเลือกองค์ประกอบแรก
- ต่อไป. ใช้กับ Begin เพื่อรับองค์ประกอบถัดไป
- สำคัญ. กำหนดค่า Begin และ Next เพื่อใช้งาน และรับกุญแจเมื่อเคลื่อนที่
คลาสและโครงสร้างของบุคคลที่สาม
- ใช้ 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<<s<<endl;
xpack::json::decode (s, r);
cout<<r. a << ' , ' <<r. b << ' , ' <<r. t . tv_sec << ' , ' <<r. t . tv_usec <<endl;
return 0 ;
}
เยื้องรูปแบบ
- json/xml ที่สร้างโดยการเข้ารหัสตามค่าเริ่มต้นจะไม่เยื้องและเหมาะสำหรับการใช้งานโปรแกรม หากมีคนอ่านก็สามารถเยื้องได้
- พารามิเตอร์สองตัวสุดท้ายของการควบคุมการเข้ารหัส
- indentCount หมายถึงจำนวนอักขระสำหรับการเยื้อง, <0 หมายถึงไม่มีการเยื้อง, 0 หมายถึงขึ้นบรรทัดใหม่แต่ไม่มีการเยื้อง
- indentChar แสดงถึงอักขระที่เยื้อง โดยใช้ช่องว่างหรือแท็บ
อาร์เรย์ XML
- อาร์เรย์ใช้ชื่อตัวแปรเป็นป้ายกำกับองค์ประกอบตามค่าเริ่มต้น เช่น "ids":[1,2,3] และ xml ที่สอดคล้องกันคือ:
< ids >
< ids >1</ ids >
< ids >2</ ids >
< ids >3</ ids >
</ ids >
- คุณสามารถใช้นามแฝงเพื่อควบคุมป้ายกำกับขององค์ประกอบของอาร์เรย์ เช่น A(ids,"xml:ids,vl@id"), vl ตามด้วย @xx, xx คือป้ายกำกับของอาร์เรย์ และค่าที่สร้างขึ้น ผลลัพธ์คือ:
< ids >
< id >1</ id >
< id >2</ id >
< id >3</ id >
</ ids >
- หากคุณต้องการให้อาร์เรย์ขยายโดยตรงแทนที่จะล้อมด้วยเลเยอร์ภายนอก คุณสามารถใช้นามแฝงบวกแฟล็ก "sbs" เพื่อให้บรรลุเป้าหมายนี้ เช่น A(ids, "xml:ids,sbs") โปรดทราบว่า แท็ก sbs สามารถใช้ได้เฉพาะกับอาร์เรย์เท่านั้น การใช้งานในเครื่องอื่นอาจขัดข้อง
< ids >1</ ids >
< ids >2</ ids >
< ids >3</ ids >
ซีดีดาต้า
- สำหรับประเภท CDATA คุณต้องใช้แฟล็ก "cdata" เพื่อนำไปใช้ เช่น A(data, "xml:data,cdata")
- cdata สามารถรับได้โดยใช้ std::string เท่านั้น
- หาก xml ที่สอดคล้องกับตัวแปรไม่ใช่โครงสร้าง CDATA จะถูกประมวลผลเป็นสตริงปกติ ตัวอย่างเช่น สามารถแยกวิเคราะห์
<data>hello</data>
ได้สำเร็จ
รองรับคิวที
- แก้ไข config.h และเปิดใช้งานมาโคร XPACK_SUPPORT_QT (หรือเปิดใช้งานในตัวเลือกการคอมไพล์)
- ปัจจุบันรองรับ QString/QMap/QList/QVector
MySQL
- ขณะนี้รองรับเฉพาะการถอดรหัสเท่านั้น และยังไม่รองรับการเข้ารหัส
- ยังทดสอบไม่ครบถ้วน โปรดใช้ด้วยความระมัดระวัง
- ประเภทที่รองรับในปัจจุบันคือ:
- เชือก การทดสอบง่ายๆ
- ประเภทจำนวนเต็ม การทดสอบง่ายๆ
- ประเภทจุดลอยตัว ไม่ได้ทดสอบ
- ใช้ประเภทจำนวนเต็ม (เช่น time_t) เพื่อรับ TIME/DATETIME/TIMESTAMP ไม่ได้ทดสอบ
- การแปลงประเภทที่กำหนดเอง is_xpack_mysql_xtype คล้ายกับ xtype ไม่ได้ทดสอบ
- มี API สองตัว (xpack::mysql::):
-
static void decode(MYSQL_RES *result, T &val)
- ใช้เพื่อแปลง MYSQL_RES เป็นโครงสร้างหรือเวกเตอร์<> หากไม่ใช่เวกเตอร์ ระบบจะแปลงเฉพาะแถวแรกเท่านั้น
-
static void decode(MYSQL_RES *result, const std::string&field, T &val)
- ใช้เพื่อแยกวิเคราะห์ฟิลด์บางฟิลด์ ใช้ในสถานการณ์ที่คุณต้องการรับเนื้อหาของฟิลด์บางฟิลด์เท่านั้น เช่น เลือก id จาก mytable โดยที่ name = lilei และเพียงต้องการรับข้อมูล id val รองรับเวกเตอร์
หมายเหตุสำคัญ
- พยายามอย่าขึ้นต้นชื่อตัวแปรด้วย __x_pack มิฉะนั้นอาจขัดแย้งกับไลบรารี
- ไม่รองรับ vc6
- msvc ยังไม่ได้ทำการทดสอบมากมาย มีเพียงการทดสอบง่ายๆ ในปี 2019
- การทำให้เป็นอนุกรมและดีซีเรียลไลซ์ของ json ใช้ Rapidjson
- การดีซีเรียลไลซ์ xml ใช้ Rapidxml
- การซีเรียลไลซ์ xml นั้นเขียนด้วยตัวเองโดยไม่ได้อ้างอิงถึง RFC ดังนั้นจึงอาจแตกต่างจากมาตรฐาน
- หากคุณมีคำถามใด ๆ คุณสามารถเข้าร่วมกลุ่ม QQ 878041110