C++武艺修炼--基于Qt半自动生成解析Json

该项目是基于Qt5,利用C++11实现的半自动生成解析Json工具。

当写项目时,可能需要写大量的Json,比如有1000个结构体,需要完成其Json的生成及解析,而每写一个数据就需要实现对应的类型转换,极其繁琐,稍不注意,可能写错。如key存错,生成和解析的key不一致,可能需要花费好大的精力去排除bug。还有类型转换不一致,这个一般情况下编译器会帮查找,但是前后规则不同编译器是检查不出的,如下错误代码:

    QJsonObject obj;
    QDateTime time, timeNew;
    //生成
    obj.insert("time", time.toMSecsSinceEpoch());
    //解析
    timeNew = QDateTime::fromString(obj.value("time").toString());

难道每写一个数据,都需要程序员去检查吗?惊呼 “打工人好难呀!!!”

所以利用模板小试牛刀一下子,实现一个半自动Json工具。

直接上源码:

#include <QJsonObject>
#include <QJsonArray>
#include <QStringList>
#include <QString>
#include <QDateTime>
#include <iostream>
#include <type_traits>

#define GJSONTOOL_TOJSON(obj, Data) \
    JsonTool::CreatJson(obj, Data, JsonTool::dowithName(#Data));
#define GJSONTOOL_TOVALUE(obj, Data) \
    JsonTool::CreatValue(obj, Data, JsonTool::dowithName(#Data));

namespace JsonTool {

inline void toValue(QJsonObject& obj, QString& T_Data, const QString& strKey)
{
    T_Data = obj.value(strKey).toString();
}

template  <typename T, typename std::enable_if<std::is_same<typename std::decay<T>::type , std::string>::value, int>::type = 0>
inline void toValue(QJsonObject& obj, T& T_Data, const QString& strKey)
{
    T_Data = obj.value(strKey).toString().toStdString();
}

template  <typename T, typename std::enable_if<std::is_same<typename std::decay<T>::type , QString>::value, int>::type = 0>
inline void toValue(QJsonObject& obj, T& T_Data, const QString& strKey)
{
    T_Data = obj.value(strKey).toString();
}

template  <typename T, typename std::enable_if<std::is_same<typename std::decay<T>::type, int>::value, int>::type = 0>
inline void toValue(QJsonObject& obj, T& T_Data, const QString& strKey)
{
    T_Data = obj.value(strKey).toInt();
}

template  <typename T, typename std::enable_if<std::is_same<typename std::decay<T>::type, short>::value, int>::type = 0>
inline void toValue(QJsonObject& obj, T& T_Data, const QString& strKey)
{
    T_Data = (short)obj.value(strKey).toInt();
}

template  <typename T, typename std::enable_if<std::is_same<typename std::decay<T>::type, uint>::value, int>::type = 0>
inline void toValue(QJsonObject& obj, T& T_Data, const QString& strKey)
{
    T_Data = (uint)obj.value(strKey).toInt();
}

template  <typename T, typename std::enable_if<std::is_same<typename std::decay<T>::type, ushort>::value, int>::type = 0>
inline void toValue(QJsonObject& obj, T& T_Data, const QString& strKey)
{
    T_Data = (ushort)obj.value(strKey).toInt();
}

template  <typename T, typename std::enable_if<std::is_same<typename std::decay<T>::type, QDateTime>::value, int>::type = 0>
inline void toValue(QJsonObject& obj, T& T_Data, const QString& strKey)
{
    QString format = "yyyy-MM-ddThh:mm:ss";
    T_Data = QDateTime::fromString(obj.value(strKey).toString(), format);
}

template  <typename T, typename std::enable_if<std::is_same<typename std::decay<T>::type, QStringList>::value, int>::type = 0>
inline void toValue(QJsonObject& obj, T& T_Data, const QString& strKey)
{
    for(const auto& chil : obj.value(strKey).toArray())
    {
        T_Data.append(chil.toString());
    }
}

template  <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
inline void toValue(QJsonObject& obj, T& T_Data, const QString& strKey)
{
    T_Data = (typename std::decay<T>::type)obj.value(strKey).toDouble(); //浮点型
}

template  <typename T, typename std::enable_if<std::is_enum<typename std::decay<T>::type>::value, int>::type = 0>
inline void toValue(QJsonObject& obj, T& T_Data, const QString& strKey)
{
    T_Data = (typename std::decay<T>::type)obj.value(strKey).toInt();
}

template  <typename T, typename = void>
struct toJson
{
    void operator()(QJsonObject& obj, T&& T_Data, const QString& strKey)
    {
        obj.insert(strKey, T_Data);
    }
};

template <typename T>
struct toJson<T,  typename std::enable_if<std::is_same<typename std::decay<T>::type, QStringList>::value>::type>
{
    void operator()(QJsonObject& obj,  T&& listData, const QString& strKey)
    {
        QJsonArray arr;
        for(const auto& child : listData)
            arr.append(child);
        obj.insert(strKey, arr);
    }
};
template  <typename T>
struct toJson<T,  typename std::enable_if<std::is_same<typename std::decay<T>::type, QDateTime>::value>::type>
{
    void operator()(QJsonObject& obj, T&& TData, const QString& strKey)
    {
        QString format = "yyyy-MM-ddThh:mm:ss";
        obj.insert(strKey, TData.toString(format));
    }
};

template  <typename T>
struct toJson<T,  typename std::enable_if<std::is_same<typename std::decay<T>::type, std::string>::value>::type>
{
    void operator()(QJsonObject& obj, T&& TData, const QString& strKey)
    {
        obj.insert(strKey, QString::fromStdString(TData));
    }
};

inline QString dowithName(const QString& strName)
{
    if(strName.contains("."))
    {
        return strName.split(".").last();
    }
    else
        return strName;
}

template  <typename T>
inline void CreatJson(QJsonObject& obj, T&& TData, const QString& strKey)
{
    toJson<T>()(obj, TData, strKey);
}

template  <typename T>
inline void CreatValue(QJsonObject& obj, T& TData, const QString& strKey)
{
    toValue<T>(obj, TData, strKey);
}

}

这里用到了模板的穷举,把一些常用的类型穷举实现出来,如果大家有其他的类型,可以在此基础上进行添加。如果大家有看不懂的地方,那就去百度或者问人工智能,这里我就不一一解释了。有其他问题可以留言。

下面是进行调用:

//先定义一个结构体
//学生信息
struct stuStudent
{
    enum ENGender
    {
        ENG_Boy = 1,
        ENG_Girl
    };
    QString strName;
    std::string strNickName;
    ENGender eGen;
    int iAge;
    double dHeight;
    QStringList listLoveGirls;
    QDateTime tCurrTime;
};

//生成Json
QJsonObject builtToJson(stuStudent &stuData)
{
    QJsonObject obj;
    GJSONTOOL_TOJSON(obj, stuData.iAge);
    GJSONTOOL_TOJSON(obj, stuData.dHeight);
    GJSONTOOL_TOJSON(obj, stuData.strName);
    GJSONTOOL_TOJSON(obj, stuData.eGen);
    GJSONTOOL_TOJSON(obj, stuData.listLoveGirls);
    GJSONTOOL_TOJSON(obj, stuData.tCurrTime);
    GJSONTOOL_TOJSON(obj, stuData.strNickName);
    return obj;
}

//解析Json
void fromJsonToData(QJsonObject &obj, stuStudent &stuData)
{
    GJSONTOOL_TOVALUE(obj, stuData.iAge);
    GJSONTOOL_TOVALUE(obj, stuData.dHeight);
    GJSONTOOL_TOVALUE(obj, stuData.strName);
    GJSONTOOL_TOVALUE(obj, stuData.eGen);
    GJSONTOOL_TOVALUE(obj, stuData.listLoveGirls);
    GJSONTOOL_TOVALUE(obj, stuData.tCurrTime);
    GJSONTOOL_TOVALUE(obj, stuData.strNickName);
}

上边的调用很简单,生成只需要调用GJSONTOOL_TOJSON, 解析只需要调用GJSONTOOL_TOVALUE,不需要程序员去实现toInt,toString等等的类型转换,也不需要人为去传入key。省去大量的时间,以及调试时间。惊呼“哇哇哇!!!”

最终的调用:

int main(int argc, char *argv[])
{
    stuStudent stuData;
    stuData.strName = "王二麻子";
    stuData.strNickName = "老王";
    stuData.eGen = stuStudent::ENG_Boy;
    stuData.iAge = 18;
    stuData.dHeight = 178.88;
    stuData.listLoveGirls << "翠花" << "小花" << "小甜甜" << "苍老师" ;
    stuData.tCurrTime = QDateTime::currentDateTime();
    //生成Json
    QJsonObject obj = builtToJson(stuData);
    //解析Json
    stuStudent stuDataNew;
    fromJsonToData(obj, stuDataNew);
    int aaa = 1; //方便打断点
}

最终程序运行的结果 stuData 和 stuDataNew数据内容一模一样。大功告成!!!

读到这里就可以啦,快去好好工作吧。

--------------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------------------

下面是一些幼稚的文字,人文的东西可以让人放松一下。大概是本人2022年写的,谈不上诗,也分享一下,俗称开源。

                无题

        清水一笑芙蓉颜,
        滟波浮去碧霞间。
        恍然刹那一梦兮,
        也罢,
        逍遥归去皆随缘。

分享完毕,感谢大家的阅读哈,感谢特别感谢。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值