xpack
Inglês
- Usado para converter entre estruturas C++ e json/xml/yaml/bson/mysql/sqlite
- Existem apenas arquivos de cabeçalho, nenhum arquivo de biblioteca precisa ser compilado, portanto não há Makefile.
- Suporta bson, depende de
libbson-1.0
e precisa ser instalado por você mesmo. Não totalmente testado , consulte o README para obter detalhes - Suporta MySQL e depende de
libmysqlclient-dev
, que precisa ser instalado por você mesmo. Não totalmente testado - Suporta Sqlite e depende de libsqlite3, que precisa ser instalado por você. Não totalmente testado
- Suporta yaml, depende de yaml-cpp, precisa ser instalado por você mesmo. Não totalmente testado
- Para obter detalhes, consulte o exemplo
- Uso básico
- Suporte de contêiner
- BANDEIRA
- Alias
- campo de bits
- herdar
- enumerar
- Codec personalizado
- união
- tipo indefinido
- variedade
- Aulas e estruturas de terceiros
- Recuo de formato
- Matriz XML
- CDATA
- Suporte Qt
- MySQL
- Nota importante
Uso básico
- A macro XPACK é usada após a estrutura para conter cada variável. XPACK também requer uma letra. Consulte FLAG para obter os significados das diferentes letras.
- Use xpack::json::encode para converter a estrutura para json
- Use xpack::json::decode para converter json em estrutura
# 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 ;
}
Suporte de contêiner
Atualmente, os seguintes contêineres (std) são suportados
- vetor
- definir
- lista
- mapa<string, T>
- map<integer, T> // Somente JSON, XML não é suportado
- unordered_map<string, T> (requer suporte C++ 11)
- shared_ptr (requer suporte C++ 11)
BANDEIRA
Na macro XPACK, as variáveis precisam ser incluídas com letras, como XPACK(O(a,b)). XPACK pode conter múltiplas letras, e cada letra pode conter múltiplas variáveis. As letras atualmente suportadas são:
- X. O formato é X(F(flag1, flag2...), member1, member2,...) F contém vários FLAGs, atualmente suportados são:
- 0 sem BANDEIRA
- OE omitempty, ao codificar, se a variável for 0 ou uma string vazia ou falsa, as informações da chave correspondente não serão geradas.
- EN vazio como nulo, usado para codificação de json é um campo que não gera vazio diretamente, enquanto EN gera nulo.
- M obrigatório, na decodificação, caso este campo não exista, será lançada uma exceção, utilizada para alguns campos de id.
- Atributo ATTR, ao codificar xml, coloque o valor no atributo.
- Linha única SL, quando codifica json, para arrays, coloque-os em uma linha
- C. O formato é C(customcodec, F(flag1,flags...), member1, member2,...) para funções personalizadas de codificação e decodificação. Para obter detalhes, consulte Codec personalizado.
- Ó. Equivalente a X(F(0), ...) sem qualquer FLAG.
- M. Equivalente a X(F(M),...) indicando que estes campos devem existir.
- UM. Alias, A(membro1, alias1, membro2, alias2...), usado quando os nomes de variáveis e chaves são diferentes
- AF. Alias com FLAG, AF(F(flag1, flag2,...), member1, alias1, member2, alias2...)
- B. Bitfield, B(F(flag1, flag2, ...), member1, member2, ...) bitfield não suporta aliases
- EU. Herança, I(baseclass1, baseclass2....), coloque a classe pai nela
- E. enumerar:
- Se o compilador suportar C++ 11, não há necessidade de usar E e a enumeração pode ser colocada em X/O/M/A.
- Caso contrário, a enumeração só poderá ser colocada em E e os aliases não serão suportados.
Alias
- Usado para cenários em que o nome da variável e o nome da chave são inconsistentes
- O formato é A(variável, alias....) ou AF(F(flags), variável, alias....), e o formato do alias é o formato "xt:n"
- x representa o alias global, t representa o tipo (atualmente suporta json, xml e bson) e n representa o alias sob o tipo.
- Não há necessidade de um alias global. Por exemplo
json:_id
é legal. - Não há necessidade de aliases de tipo. Por exemplo,
_id
é legal. - Se houver um alias de tipo, use o alias de tipo primeiro. Caso contrário, use o alias global. Se não houver um alias de tipo, use o nome da variável.
# 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 ;
}
campo de bits
- Use "B" para incluir variáveis de campo de bits. Os campos de bits não suportam aliases.
# 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 ;
}
herdar
- Use "I" para incluir a classe pai. Se você precisar usar as variáveis da classe pai, inclua-as. Se não precisar delas, não será necessário incluí-las.
- A classe pai da classe pai também precisa ser incluída, como class Base1:public Base2:public Base1, então I(Base1, Base) é necessário em Base2;
- A classe pai também precisa definir a 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 ;
}
enumerar
- Se o compilador suportar C++11, a enumeração terá o mesmo nome de uma variável comum e poderá ser colocada em X/O/M/A.
- Caso contrário, precisa ser colocado em E, o formato é E(F(...), membro1, membro2, ...)
# 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 personalizado
Cenários de aplicação
- Alguns tipos básicos desejam ser codificados de maneira personalizada, como o uso de strings para codificar números inteiros/ponto flutuante.
- Alguns tipos podem não querer ser codificados um por um de acordo com as variáveis de estrutura. Por exemplo, se uma estrutura de tempo for definida:
struct Time {
long ts; // unix timestamp
};
Não queremos codificá-lo no formato {"ts":1218196800}, mas queremos codificá-lo no formato "2008-08-08 20:00:00".
Existem duas maneiras aqui:
- Usando xtype, você pode consultar o exemplo
- Use C para incluir variáveis que requerem codificação e decodificação personalizadas (doravante denominado método C), você pode consultar o exemplo
Ambos os métodos implementam essencialmente codificação/decodificação por si próprios, mas existem as seguintes diferenças:
- xtype está no nível de tipo, ou seja, uma vez que um tipo é encapsulado com xtype, a codificação/decodificação personalizada terá efeito neste tipo. xtype não pode ser usado em tipos básicos (int/string, etc.)
- O método C pode suportar tipos básicos (int/string, etc.) e tipos não básicos, mas só funciona em variáveis contidas em C, como int a; ), b) ;Então a ainda usa o codec padrão e b usa o codec personalizado.
- xtype tem precedência sobre a macro XPACK, ou seja, se xtype for definido, a codificação/decodificação de xtype será usada primeiro.
- O método C tem precedência sobre o xtype, ou seja, as variáveis contidas em C usarão definitivamente os métodos de codificação e decodificação especificados em C.
Usando esses dois recursos, você pode obter alguns controles de codificação e __x_pack_decode
mais flexíveis. Por exemplo, este exemplo implementa uma função de codificação baseada em condições variáveis. Se Sub.type==1, codifique __x_pack_encode
, caso contrário, codifique seq2. XPACK As funções de decodificação/codificação adicionadas pela macro à estrutura, funções de codificação e decodificação personalizadas podem chamar as funções de codificação e decodificação padrão do xpack por meio dessas funções.
união
Você pode usar codecs personalizados para processar uniões, consulte o exemplo
variedade
- Ao decodificar, se o número de elementos exceder o comprimento do array, ele será truncado.
- Matrizes de caracteres são processadas como se tivessem um terminador
# 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 ;
}
tipo indefinido
- Cenários em que o esquema para JSON é incerto
- Use xpack::JsonData para receber essas informações
- Você pode consultar exemplos
- Os principais métodos de xpack::JsonData são:
- Tipo. usado para obter o tipo
- Série de funções IsXXX. Usado para determinar se é um determinado tipo, basicamente equivalente a return Type()==xxxx;
- Funções da série GetXXX. Usado para extrair valores.
- Sobrecarga bool. Usado para determinar se é um JsonData legal.
- Tamanho. Usado para determinar o número de elementos em um tipo de array
-
operator [](size_t index)
é usado para obter o elemento de índice da matriz (começando em 0) -
operator [](const char *key)
é usado para obter elementos do tipo Object com base na chave - Começar. Utilizado para percorrer os elementos do Object, pegando o primeiro.
- Próximo. Use-o com Begin para obter o próximo elemento.
- Chave. Configure Begin e Next para usar e obtenha a chave ao percorrer
Aulas e estruturas de terceiros
- Use XPACK_OUT em vez de XPACK para incluir variáveis
- XPACK_OUT deve ser definido no namespace 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 ;
}
Recuo de formato
- O json/xml gerado pela codificação por padrão não é indentado e é adequado para uso do programa. Se for lido por pessoas, pode ser indentado.
- Os dois últimos parâmetros de controle de codificação
- indentCount representa o número de caracteres para recuo, <0 representa nenhum recuo, 0 representa uma nova linha, mas nenhum recuo.
- indentChar representa o caractere recuado, usando espaços ou tabulações
Matriz XML
- Arrays usam nomes de variáveis como rótulos de elementos por padrão, como "ids":[1,2,3], e o xml correspondente é:
< ids >
< ids >1</ ids >
< ids >2</ ids >
< ids >3</ ids >
</ ids >
- Você pode usar aliases para controlar os rótulos dos elementos do array, como A(ids,"xml:ids,vl@id"), vl é seguido por @xx, xx é o rótulo do array e o gerado o resultado é:
< ids >
< id >1</ id >
< id >2</ id >
< id >3</ id >
</ ids >
- Se você deseja que a matriz seja expandida diretamente em vez de envolvê-la com uma camada externa, você pode usar o alias mais o sinalizador "sbs" para conseguir isso, como A ( ids, "xml:ids,sbs"). A tag sbs só pode ser usada para arrays. Outros O uso local pode travar.
< ids >1</ ids >
< ids >2</ ids >
< ids >3</ ids >
CDATA
- Para o tipo CDATA, você precisa usar o sinalizador "cdata" para implementar, como A(data, "xml:data,cdata")
- cdata só pode ser recebido usando std::string
- Se o xml correspondente à variável não for uma estrutura CDATA, ele será processado como uma string normal. Por exemplo,
<data>hello</data>
também pode ser analisado com sucesso.
Suporte Qt
- Modifique config.h e habilite a macro XPACK_SUPPORT_QT (ou habilite-a na opção de compilação)
- Atualmente suporta QString/QMap/QList/QVector
MySQL
- Atualmente, apenas a decodificação é suportada e a codificação ainda não é suportada.
- Não totalmente testado, use com cuidado
- Os tipos atualmente suportados são:
- corda. Teste simples.
- Tipo inteiro. Teste simples.
- Tipo de ponto flutuante. Não testado.
- Use o tipo inteiro (como time_t) para receber TIME/DATETIME/TIMESTAMP. Não testado.
- Conversão de tipo personalizado, is_xpack_mysql_xtype, semelhante ao xtype. Não testado.
- Existem duas APIs (xpack::mysql::):
-
static void decode(MYSQL_RES *result, T &val)
- Usado para converter MYSQL_RES em uma estrutura ou vetor<>. Se não for um vetor, apenas a primeira linha será convertida.
-
static void decode(MYSQL_RES *result, const std::string&field, T &val)
- Usado para analisar um determinado campo, usado em cenários onde você deseja apenas obter o conteúdo de um determinado campo, como selecionar id de minha tabela onde nome = lilei, e deseja apenas obter as informações de id. val suporta vetor
Nota importante
- Tente não iniciar o nome da variável com __x_pack, caso contrário poderá entrar em conflito com a biblioteca.
- vc6 não é compatível.
- msvc não fez muitos testes, apenas testes simples em 2019.
- A serialização e desserialização do json usa rapidjson.
- A desserialização do xml usa rapidxml
- A serialização do xml foi escrita por mim mesmo sem referência ao RFC, portanto pode ser diferente do padrão.
- Se você tiver alguma dúvida, pode entrar no grupo QQ 878041110