xpack
Anglais
- Utilisé pour convertir entre les structures C++ et json/xml/yaml/bson/mysql/sqlite
- Il n'y a que des fichiers d'en-tête, aucun fichier de bibliothèque n'a besoin d'être compilé, donc il n'y a pas de Makefile.
- Prend en charge bson, dépend de
libbson-1.0
, doit être installé par vous-même. Pas entièrement testé , veuillez vous référer au README pour plus de détails - Prend en charge MySQL et dépend de
libmysqlclient-dev
, qui doit être installé par vous-même. Pas entièrement testé - Prend en charge SQLite et dépend de libsqlite3, qui doit être installé par vous-même. Pas entièrement testé
- Prend en charge yaml et dépend de yaml-cpp, qui doit être installé par vous-même. Pas entièrement testé
- Pour plus de détails, veuillez vous référer à l'exemple
- Utilisation de base
- Prise en charge des conteneurs
- DRAPEAU
- Alias
- champ de bits
- hériter
- énumérer
- Codec personnalisé
- union
- type indéfini
- tableau
- Classes et structures tierces
- Formater le retrait
- Tableau XML
- DONNÉES CD
- Prise en charge de Qt
- MySQL
- Remarque importante
Utilisation de base
- La macro XPACK est utilisée après la structure pour contenir chaque variable. XPACK nécessite également une lettre. Veuillez vous référer à FLAG pour la signification des différentes lettres.
- Utilisez xpack::json::encode pour convertir la structure en json
- Utilisez xpack::json::decode pour convertir json en structure
# 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 ;
}
Prise en charge des conteneurs
Actuellement, les conteneurs suivants (std) sont pris en charge
- vecteur
- ensemble
- liste
- carte<string, T>
- map<integer, T> // JSON uniquement, XML n'est pas pris en charge
- unordered_map<string, T> (nécessite la prise en charge de C++11)
- shared_ptr (nécessite la prise en charge de C++11)
DRAPEAU
Dans la macro XPACK, les variables doivent être incluses avec des lettres, telles que XPACK(O(a,b)). XPACK peut contenir plusieurs lettres, et chaque lettre peut contenir plusieurs variables. Les lettres actuellement prises en charge sont :
- X. Le format est X(F(flag1, flag2...), member1, member2,...) F contient divers FLAG, actuellement pris en charge :
- 0 pas de DRAPEAU
- Omission d'OE, lors de l'encodage, si la variable est 0 ou une chaîne vide ou fausse, les informations clés correspondantes ne seront pas générées.
- EN vide comme nul, utilisé pour l'encodage json OE ne génère pas directement de champs vides, tandis que EN génère un nul.
- M obligatoire, lors du décodage, si ce champ n'existe pas, une exception sera levée, utilisée pour certains champs d'identifiant.
- Attribut ATTR, lors du codage XML, mettez la valeur dans l'attribut.
- SL seule ligne, lors de l'encodage de json, pour les tableaux, placez-les sur une seule ligne
- C. Le format est C(customcodec, F(flag1,flags...), member1, member2,...) pour les fonctions de codage et de décodage personnalisées. Pour plus de détails, veuillez vous référer à Custom Codec.
- O. Équivalent à X(F(0), ...) sans aucun FLAG.
- M. Équivalent à X(F(M),...) indiquant que ces champs doivent exister.
- UN. Alias, A(member1, alias1, member2, alias2...), utilisé lorsque les noms de variable et de clé sont différents
- AF. Alias avec FLAG, AF(F(flag1, flag2,...), member1, alias1, member2, alias2...)
- B. Bitfield, B(F(flag1, flag2, ...), member1, member2, ...) bitfield ne prend pas en charge les alias
- JE. Héritage, je (baseclass1, baseclass2....), j'y ai mis la classe parent
- E. énumérer:
- Si le compilateur prend en charge C++11, il n'est pas nécessaire d'utiliser E et l'énumération peut être placée dans X/O/M/A.
- Sinon, l'énumération ne peut être placée que dans E et les alias ne sont pas pris en charge.
Alias
- Utilisé pour les scénarios dans lesquels le nom de la variable et le nom de la clé sont incohérents
- Le format est A (variable, alias....) ou AF (F (drapeaux), variable, alias....), et le format de l'alias est le format "xt:n"
- x représente l'alias global, t représente le type (prend actuellement en charge json, xml et bson) et n représente l'alias sous le type.
- Il n'est pas nécessaire d'avoir un alias global. Par exemple
json:_id
est légal. - Il n'est pas nécessaire d'avoir des alias de type. Par exemple,
_id
est légal. - S'il existe un alias de type, utilisez d'abord l'alias de type. Sinon, utilisez l'alias global. S'il n'y a pas d'alias de type, utilisez le nom de la variable.
# 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 ;
}
champ de bits
- Utilisez "B" pour inclure des variables de champ de bits. Les champs de bits ne prennent pas en charge les 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 ;
}
hériter
- Utilisez "I" pour inclure la classe parent. Si vous devez utiliser les variables de la classe parent, incluez-les. Si vous n'en avez pas besoin, vous n'avez pas besoin de les inclure.
- La classe parent de la classe parent doit également être incluse, comme la classe Base ; la classe Base1 : public Base ; la classe Base2 : public Base1 ; alors I(Base1, Base) est nécessaire dans Base2 ;
- La classe parent doit également définir la 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 ;
}
énumérer
- Si le compilateur prend en charge C++11, l'énumération porte le même nom qu'une variable ordinaire et peut être placée dans X/O/M/A.
- Sinon, il faut le placer en E, le format est 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 ;
}
Codec personnalisé
Scénarios d'application
- Certains types de base doivent être codés de manière personnalisée, par exemple en utilisant des chaînes pour coder des nombres entiers/à virgule flottante.
- Certains types peuvent ne pas vouloir être codés un par un en fonction des variables de structure. Par exemple, si une structure temporelle est définie :
struct Time {
long ts; // unix timestamp
};
Nous ne voulons pas l'encoder au format {"ts":1218196800}, mais nous voulons l'encoder au format "2008-08-08 20:00:00".
Il y a deux manières ici :
- En utilisant xtype, vous pouvez vous référer à l'exemple
- Utilisez C pour inclure des variables qui nécessitent un codage et un décodage personnalisés (ci-après dénommé la méthode C), vous pouvez vous référer à l'exemple
Les deux méthodes implémentent essentiellement l’encodage/décodage par elles-mêmes, mais il existe les différences suivantes :
- xtype est au niveau du type, c'est-à-dire qu'une fois qu'un type est encapsulé avec xtype, l'encodage/décodage personnalisé prendra effet sur ce type. xtype ne peut pas être utilisé sur les types de base (int/string, etc.)
- La méthode C peut prendre en charge les types de base (int/string, etc.) et les types non basiques, mais ne fonctionne que sur les variables contenues dans C, telles que int a int b; ), b) ; Ensuite, a utilise toujours le codec par défaut et b utilise le codec personnalisé.
- xtype a priorité sur la macro XPACK, c'est-à-dire que si xtype est défini, l'encodage/décodage de xtype sera utilisé en premier.
- La méthode C est prioritaire sur xtype, c'est-à-dire que les variables contenues en C utiliseront certainement les méthodes d'encodage et de décodage spécifiées en C.
En utilisant ces deux fonctionnalités, vous pouvez obtenir des contrôles d'encodage et de décodage plus flexibles. Par exemple, cet exemple implémente une fonction d'encodage basée sur des conditions variables. Si Sub.type==1, encodez __x_pack_encode
__x_pack_decode
XPACK Les fonctions de décodage/encodage ajoutées par la macro à la structure, les fonctions d'encodage et de décodage personnalisées peuvent appeler les fonctions d'encodage et de décodage par défaut de xpack via ces fonctions.
union
Vous pouvez utiliser des codecs personnalisés pour traiter les unions, veuillez vous référer à l'exemple
tableau
- Lors du décodage, si le nombre d'éléments dépasse la longueur du tableau, celui-ci sera tronqué.
- Les tableaux de caractères sont traités comme s'ils avaient un terminateur
# 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 ;
}
type indéfini
- Scénarios où le schéma de JSON est incertain
- Utilisez xpack::JsonData pour recevoir ces informations
- Vous pouvez vous référer à des exemples
- Les principales méthodes de xpack::JsonData sont :
- Taper. utilisé pour taper
- Série de fonctions IsXXX. Utilisé pour déterminer s'il s'agit d'un certain type, fondamentalement équivalent à return Type()==xxxx;
- Fonctions de la série GetXXX. Utilisé pour extraire des valeurs.
- Surcharger booléen. Utilisé pour déterminer s'il s'agit d'un JsonData légal.
- Taille. Utilisé pour déterminer le nombre d'éléments dans un type de tableau
-
operator [](size_t index)
est utilisé pour obtenir l'élément d'index du tableau (en commençant à 0) -
operator [](const char *key)
est utilisé pour obtenir des éléments de type Objet basé sur la clé - Commencer. Utilisé pour parcourir les éléments de Object, en prenant le premier.
- Suivant. Utilisez-le avec Begin pour obtenir l'élément suivant.
- Clé. Configurez Begin et Next à utiliser et obtenez la clé lors de la traversée
Classes et structures tierces
- Utilisez XPACK_OUT au lieu de XPACK pour inclure des variables
- XPACK_OUT doit être défini dans l'espace de noms global
# 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 ;
}
Formater le retrait
- Le json/xml généré par encode n'est pas en retrait et convient à une utilisation par le programme. S'il est lu par des personnes, il peut être en retrait.
- Les deux derniers paramètres du contrôle d'encodage
- indentCount représente le nombre de caractères pour l'indentation, <0 représente aucune indentation, 0 représente une nouvelle ligne mais aucune indentation.
- indentChar représente le caractère indenté, en utilisant des espaces ou des tabulations
Tableau XML
- Les tableaux utilisent par défaut des noms de variables comme étiquettes d'éléments, tels que "ids":[1,2,3], et le code XML correspondant est :
< ids >
< ids >1</ ids >
< ids >2</ ids >
< ids >3</ ids >
</ ids >
- Vous pouvez utiliser des alias pour contrôler les étiquettes des éléments du tableau, tels que A(ids,"xml:ids,vl@id"), vl est suivi de @xx, xx est l'étiquette du tableau et le généré le résultat est :
< ids >
< id >1</ id >
< id >2</ id >
< id >3</ id >
</ ids >
- Si vous souhaitez que le tableau soit développé directement au lieu de l'envelopper avec un calque extérieur, vous pouvez utiliser l'indicateur alias plus "sbs" pour y parvenir, comme A(ids, "xml:ids,sbs"). La balise sbs ne peut être utilisée que pour les tableaux. Autres L'utilisation locale peut planter.
< ids >1</ ids >
< ids >2</ ids >
< ids >3</ ids >
DONNÉES CD
- Pour le type CDATA, vous devez utiliser l'indicateur "cdata" à implémenter, tel que A(data, "xml:data,cdata")
- cdata ne peut être reçu qu'en utilisant std :: string
- Si le XML correspondant à la variable n'est pas une structure CDATA, il sera traité comme une chaîne normale. Par exemple,
<data>hello</data>
peut également être analysé avec succès.
Prise en charge de Qt
- Modifiez config.h et activez la macro XPACK_SUPPORT_QT (ou activez-la dans l'option de compilation)
- Prend actuellement en charge QString/QMap/QList/QVector
MySQL
- Actuellement, seul le décodage est pris en charge et l'encodage n'est pas encore pris en charge.
- Pas entièrement testé, à utiliser avec prudence
- Les types actuellement pris en charge sont :
- chaîne. Essai simple.
- Type entier. Essai simple.
- Type à virgule flottante. Pas testé.
- Utilisez un type entier (tel que time_t) pour recevoir TIME/DATETIME/TIMESTAMP. Pas testé.
- Conversion de type personnalisée, is_xpack_mysql_xtype, similaire à xtype. Pas testé.
- Il existe deux API (xpack::mysql::) :
-
static void decode(MYSQL_RES *result, T &val)
- Utilisé pour convertir MYSQL_RES en structure ou vecteur<> S'il n'est pas vectoriel, seule la première ligne sera convertie.
-
static void decode(MYSQL_RES *result, const std::string&field, T &val)
- Utilisé pour analyser un certain champ et utilisé dans des scénarios où vous souhaitez uniquement obtenir le contenu d'un certain champ, comme sélectionner l'identifiant de ma table où nom = lilei, et souhaitez simplement obtenir les informations d'identification. val prend en charge le vecteur
Remarque importante
- Essayez de ne pas commencer le nom de la variable par __x_pack, sinon cela pourrait entrer en conflit avec la bibliothèque.
- vc6 n'est pas pris en charge.
- msvc n'a pas fait beaucoup de tests, seulement des tests simples en 2019.
- La sérialisation et la désérialisation de json utilisent rapidjson.
- La désérialisation de XML utilise rapidxml
- La sérialisation du XML a été écrite par moi-même sans faire référence à la RFC, elle peut donc être différente de la norme.
- Si vous avez des questions, vous pouvez rejoindre le groupe QQ 878041110