序列化 JSON 数据 Qt

Posted

技术标签:

【中文标题】序列化 JSON 数据 Qt【英文标题】:Serializing JSON data Qt 【发布时间】:2013-01-21 20:37:14 【问题描述】:

我正在使用 Qt 并尝试获取以下内容并将其转换为 JSON 文本,但是当我尝试编译它时,我得到一个符号未找到架构错误。

我目前正在使用内置的 Qt Json 库,因为我不知道如何让 QJson 工作并静态编译到代码中,这样就没有依赖关系了。

// Create the message body
QVariantMap message;
message.insert("date", QDate::currentDate().toString());
message.insert("eventType", eventName);
message.insert("payload", messagePayload);

// Initialize the Serializer
QJson::Serializer serializer;
bool ok;

// Serialize the data
QByteArray json = serializer.serialize(message, &ok);

编译器输出如下:

Undefined symbols for architecture x86_64:
  "QJson::Serializer::serialize(QVariant const&, bool*)", referenced from:
      SWebsocketClient::sendMessage(QString, QMap<QString, QVariant>) in swebsocketclient.o

这种方法是正确的,还是有更好的方法?我知道这个问题已经在其他地方被问过,但是其他答案中链接的大多数文章已经不存在了。

【问题讨论】:

顺便说一句,QJson 库似乎不是为该架构构建的。 您是如何获得/构建 Qjson 的?你如何链接它?显示您的 .pro 文件。 @FrankOsterfeld 我没有做任何事情来构建/获得 QJson。我尝试在我的 Mac 上通过自制软件安装它,然后将“QT += sql qjson”添加到我的 .pro 文件中,但我认为 Qt 内置了一些 JSON 支持?如果没有,如果我安装它,我如何在我的项目中使用 QJson 查看自制软件? 如果它是内置的,就不需要 qjson(Json 支持是 Qt5 的一部分,但不是 Qt4 的一部分)。为了使 CONFIG += qjson (CONFIG, not QT) 工作,qjson 需要安装一个 .prf 文件,我在 repo 中没有看到。 (它使用 CMake 使这些事情变得更容易)。所以我假设你需要手动执行 LIBS += -lqjson @FrankOsterfeld 成功了!谢谢!我不知道您是否想将其发布为答案,或者我是否应该继续回答我自己的问题。但我认为你应该接受这个功劳。 【参考方案1】:

您始终可以改用这个 JSON 库:

/*
 * qvjson.h
 *
 *  Created on: Apr 23, 2010
 *      Author: drh
 */

#ifndef QVJSON_H_
#define QVJSON_H_
#include <QMap>
#include <QList>
#include <QVariant>
#include <QRegExp>

class QvJson 

public:
    QvJson();
    virtual ~QvJson();

    QVariant parseJson(const QString& jsonString);

    // The jsonObject is a QVariant that may be a --
    // -- QMap<QString, QVariant>
    // -- QList<QVariant>
    // -- QString
    // -- integer
    // -- real number
    // -- bool
    // -- null (implemented as a QVariant() object)
    // Where QVariant appears in the above list, it may recursively 
    // be one of the above.
    QString encodeJson(const QVariant& jsonObject);

private:
    enum Error 
        ErrorUnrecognizedToken,
        ErrorMustBeString,
        ErrorMissingColon,
        ErrorMissingCommaOrClose,
        ErrorNoClosingQuote,
        ErrorEndOfInput,
        ErrorInvalidNumericValue,
        ErrorInvalidHexValue,
        ErrorUnrecognizedObject
    ;

    QRegExp mNonBlank;
    QRegExp mFindQuote;

    QString nextToken(const QString& jsonString, int& position);
    QString peekToken(const QString& jsonString, int position);
    QVariant parseInternal(const QString& jsonString, int& position, int nesting);
    QVariant parseObject(const QString& jsonString, int& position, int nesting);
    QVariant parseArray(const QString& jsonString, int& position, int nesting);
    QVariant parseString(const QString& jsonString, int& position, int nesting);
    QVariant parseBool(const QString& jsonString, int& position, int nesting);
    QVariant parseNull(const QString& jsonString, int& position, int nesting);
    QVariant parseNumber(const QString& jsonString, int& position, int nesting);
    QVariant syntaxError(const QString& method, const QString& jsonString, int position, int nesting, Error error);

    QString encodeObject(const QVariant& jsonObject);
    QString encodeArray(const QVariant& jsonObject);
    QString encodeString(const QVariant& jsonObject);
    QString encodeString(const QString& value);
    QString encodeNumeric(const QVariant& jsonObject);
    QString encodeBool(const QVariant& jsonObject);
    QString encodeNull(const QVariant& jsonObject);
    QString encodingError(const QString& method, const QVariant& jsonObject, Error error);
;

#endif /* QVJSON_H_ */

/*
 * qvjson.cpp
 *
 *  Created on: Apr 23, 2010
 *      Author: drh
 */

#include "qvjson.h"
#include <QStringList>
#include <QMessageBox>

QvJson::QvJson() 
    mNonBlank = QRegExp("\\S", Qt::CaseSensitive, QRegExp::RegExp);
    mFindQuote = QRegExp("[^\\\\]\"", Qt::CaseSensitive, QRegExp::RegExp);


QvJson::~QvJson()
    
    // TODO Auto-generated destructor stub
    

QVariant QvJson::parseJson(const QString& jsonString) 

    int position = 0;
    QVariant result;

    result = parseInternal(jsonString, position, 0);

    if (result.type() == QVariant::StringList) 
        QMessageBox::critical(NULL, "", result.toString());
    

    QString token(nextToken(jsonString, position));

    if (!token.isEmpty()) 
        QMessageBox::critical(NULL, "", QObject::tr("Invalid JSON string -- remaining token %1 at position %2.").arg(token).arg(position));
    
    return result;


QString QvJson::nextToken(const QString& jsonString, int& position) 
    if (position >= jsonString.count()) 
        return QString();
    
    while (jsonString.at(position) == ' ') 
        position++;
        if (position >= jsonString.count()) 
            return QString();
        
    
    if (jsonString.at(position).isLetter()) 
        if (position + 4 < jsonString.count()) 
            QString word = jsonString.mid(position, 4);
            if ((word == "true") || (word == "null")) 
                position += 4;
                while (position < jsonString.count() && jsonString.at(position) == ' ') 
                    position++;
                
                return word;
            
            if ((word == "fals") && (position + 5 < jsonString.count()) && jsonString.at(position + 4) == 'e') 
                position += 5;
                while (position < jsonString.count() && jsonString.at(position) == ' ') 
                    position++;
                
                return "false";
            
        
    
    QString result = QString(jsonString.at(position));
    position++;
    while (position < jsonString.count() && jsonString.at(position) == ' ') 
        position++;
    
    return result;


// By virtue of its non-& position parm, this method "peeks" at the token without consuming it.
QString QvJson::peekToken(const QString& jsonString, int position) 
    return (nextToken(jsonString, position));


QVariant QvJson::parseInternal(const QString& jsonString, int& position, int nesting) 
    QString token(peekToken(jsonString, position));
    QVariant result;
    int startPosition = position;  // For debug
    Q_UNUSED(startPosition);
    if (token.isNull()) 
        result = syntaxError("parseInternal", jsonString, position, nesting + 1, ErrorEndOfInput);
    
    else if (token == "") 
        result = parseObject(jsonString, position, nesting + 1);
    
    else if (token == "[") 
        result = parseArray(jsonString, position, nesting + 1);
    
    else if (token == "\"") 
        result = parseString(jsonString, position, nesting + 1);
    
    else if ((token == "true") || (token == "false")) 
        result = parseBool(jsonString, position, nesting + 1);
    
    else if (token == "null") 
        result = parseNull(jsonString, position, nesting + 1);
    
    else if ((token == "-") || (token.at(0).isDigit())) 
        result = parseNumber(jsonString, position, nesting + 1);
    
    else 
        result = syntaxError("parseInternal", jsonString, position, nesting + 1, ErrorUnrecognizedToken);
    
    return result;


QVariant QvJson::parseObject(const QString& jsonString, int& position, int nesting) 
    QMap<QString, QVariant> resultObject;
    QString token;
    int startPosition = position;  // For debug
    Q_UNUSED(startPosition);
    token = nextToken(jsonString, position);
    Q_ASSERT(token == "");

    // Handle case of empty object
    token = peekToken(jsonString, position);
    if (token == '') 
        return QVariant(resultObject);
    

    do 

        // Next item must be a string
        token = peekToken(jsonString, position);
        if (token != "\"") 
            return syntaxError("parseObject", jsonString, position, nesting + 1, ErrorMustBeString);
        
        QVariant propName;
        propName = parseString(jsonString, position, nesting + 1);
        // Check for error
        if (propName.type() == QVariant::StringList) 
            QStringList propNameError(propName.toStringList());
            propNameError << QObject::tr("in parseObject(%1,%2)").arg(position).arg(nesting);
            return QVariant(propNameError);
        

        // Expect a ":"
        token = nextToken(jsonString, position);
        if (token != ":") 
            return syntaxError("parseObject", jsonString, position, nesting + 1, ErrorMissingColon);
        

        // Now get the value
        QVariant propValue;
        propValue = parseInternal(jsonString, position, nesting + 1);
        // Check for error
        if (propValue.type() == QVariant::StringList) 
            QStringList propValueError(propValue.toStringList());
            propValueError << QObject::tr("in parseObject(%1,%2)").arg(position).arg(nesting);
            return QVariant(propValueError);
        

        resultObject[propName.toString()] = propValue;

        // Next token must be a "," or ""
        token = nextToken(jsonString, position);
        if (token == "") 
            return QVariant(resultObject);
        
        else if (token != ",") 
            return syntaxError("parseObject", jsonString, position, nesting + 1, ErrorMissingCommaOrClose);
        
     while (true);


QVariant QvJson::parseArray(const QString& jsonString, int& position, int nesting) 
    QList<QVariant> resultArray;
    QString token;

    token = nextToken(jsonString, position);
    Q_ASSERT(token == "[");

    // Handle case of empty object
    token = peekToken(jsonString, position);
    if (token == ']') 
        return QVariant(resultArray);
    

    do 

        // Get the element of the array
        QVariant propValue;
        propValue = parseInternal(jsonString, position, nesting + 1);
        // Check for error
        if (propValue.type() == QVariant::StringList) 
            QStringList propValueError(propValue.toStringList());
            propValueError << QObject::tr("in parseObject(%1,%2)").arg(position).arg(nesting);
            return QVariant(propValueError);
        

        resultArray << propValue;

        // Next token must be a "," or "]"
        token = nextToken(jsonString, position);
        if (token == "]") 
            return QVariant(resultArray);
        
        else if (token != ",") 
            return syntaxError("parseArray", jsonString, position, nesting + 1, ErrorMissingCommaOrClose);
        
     while (true);


QVariant QvJson::parseString(const QString& jsonString, int& position, int nesting) 
    QString result;

    // Skip over the double quote character
    Q_ASSERT(jsonString.at(position) == '"');
    position++;

    do 
        if (position >= jsonString.count()) 
            return syntaxError("parseString", jsonString, position, nesting, ErrorNoClosingQuote);
        
        if (jsonString.at(position) == '"') 
            break;
        
        if (jsonString.at(position) == '\\') 
            position++;
            if (position >= jsonString.count()) 
                return syntaxError("parseString", jsonString, position, nesting, ErrorNoClosingQuote);
            
            switch (jsonString.at(position).unicode()) 
                case 'b':
                    result.append('\b');
                    break;
                case 'f':
                    result.append('\f');
                    break;
                case 'n':
                    result.append('\n');
                    break;
                case 'r':
                    result.append('\r');
                    break;
                case 't':
                    result.append('\t');
                    break;
                case 'u':
                    
                        if (position + 4 >= jsonString.count()) 
                            return syntaxError("parseString", jsonString, position, nesting, ErrorNoClosingQuote);
                        
                        QString hex = jsonString.mid(position + 1, 4);
                        bool ok;
                        int value = hex.toInt(&ok, 16);
                        if (!ok) 
                            return syntaxError("parseString", jsonString, position+1, nesting, ErrorInvalidHexValue);
                        
                        result.append(QChar(value));
                        position += 4;
                    

                default:
                    result.append(jsonString.at(position));
            
            position++;
        
        else 
            result.append(jsonString.at(position));
            position++;
        
     while(true);
    Q_ASSERT(jsonString.at(position) == '"');
    position++;
    return QVariant(result);


QVariant QvJson::parseBool(const QString& jsonString, int& position, int nesting) 
    bool resultBool;
    QString token;

    token = nextToken(jsonString, position);

    if (token == "true") 
        resultBool = true;
    
    else if (token == "false") 
        resultBool = false;
    
    else 
        Q_ASSERT(false);
    
    return QVariant(resultBool);


QVariant QvJson::parseNull(const QString& jsonString, int& position, int nesting) 
    QString token;
    token = nextToken(jsonString, position);
    Q_ASSERT(token == "null");
    Q_UNUSED(token);
    return QVariant();


QVariant QvJson::parseNumber(const QString& jsonString, int& position, int nesting) 
    int startPosition = position;

    // Allow a leading minus sign
    if (jsonString.at(position) == '-') position++;

    if (position >= jsonString.count()) 
        return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorEndOfInput);
    

    // Allow one or more decimal digits
    if (!jsonString.at(position).isDigit()) 
        return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue);
    
    while (position < jsonString.count() && jsonString.at(position).isDigit()) 
        position++;
    
    if (position >= jsonString.count() || 
        (jsonString.at(position) != '.' && jsonString.at(position) != 'e' && jsonString.at(position) != 'E')) 
        bool ok = false;
        int resultInt = jsonString.mid(startPosition, position - startPosition).toInt(&ok);
        if (!ok) 
            return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue);
        
        return QVariant(resultInt);
    

    // Consume any fraction part
    if (jsonString.at(position) == '.') 
        position++;
        while (position < jsonString.count() && jsonString.at(position).isDigit()) 
            position++;
        
    

    // Consume any exponent part
    if (jsonString.at(position) == 'e' || jsonString.at(position) == 'E') 
        position++;
        // Consume +/- if present
        if (jsonString.at(position) == '+' || jsonString.at(position) == '-') 
            position++;
        
        // Must have at least one digit
        if (!jsonString.at(position).isDigit()) 
            return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue);
        
        while (position < jsonString.count() && jsonString.at(position).isDigit()) 
            position++;
        
    

    // Should have a valid floating point value at this point
    bool ok = false;
    qreal resultReal = jsonString.mid(startPosition, position - startPosition).toDouble(&ok);
    if (!ok) 
        return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue);
    
    return QVariant(resultReal);


QVariant QvJson::syntaxError(const QString& method, const QString& jsonString, int position, int nesting, Error error) 
    QString text;
    switch (error) 
        case ErrorInvalidNumericValue:
            text = QObject::tr("Invalid numeric value");
            break;
        case ErrorInvalidHexValue:
            text = QObject::tr("Invalid hex value");
            break;
        case ErrorEndOfInput:
            text = QObject::tr("Unexpected end of input");
            break;
        case ErrorNoClosingQuote:
            text = QObject::tr("No closing quote for literal string");
            break;
        case ErrorMissingColon:
            text = QObject::tr("Missing ':' between attribute name and value");
            break;
        case ErrorMissingCommaOrClose:
            text = QObject::tr("Missing comma, '', or ']'");
            break;
        case ErrorMustBeString:
            text = QObject::tr("The name of an attribute must be a valid character string");
            break;
        case ErrorUnrecognizedToken:
            text = QObject::tr("The token was not recognized");
            break;
    default:
            Q_ASSERT(false);
    
    QString errorMsg = QObject::tr("*** Error %1 in QvJson::%2 at position %3 -- %4").arg(error).arg(method).arg(position).arg(text);
    QStringList errorList;
    errorList << errorMsg;
    return QVariant(errorList);


QString QvJson::encodeJson(const QVariant& jsonObject) 
    QVariant::Type type = jsonObject.type();
    switch (type) 
        case QVariant::Map: 
            return encodeObject(jsonObject);
        case QVariant::List:
            return encodeArray(jsonObject);
        case QVariant::String:
            return encodeString(jsonObject);
        case QVariant::Int:
        case QVariant::Double:
            return encodeNumeric(jsonObject);
        case QVariant::Bool:
            return encodeBool(jsonObject);
        case QVariant::Invalid:
            return encodeNull(jsonObject);
        default:
            return encodingError("encodeJson", jsonObject, ErrorUnrecognizedObject);
    


QString QvJson::encodeObject(const QVariant& jsonObject) 
    QString result(" ");
    QMap<QString, QVariant> map = jsonObject.toMap();
    QMapIterator<QString, QVariant> i(map);
    while (i.hasNext()) 
        i.next();
        result.append(encodeString(i.key()));

        result.append(" : ");

        result.append(encodeJson(i.value()));

        if (i.hasNext()) 
            result.append(", ");
        
    
    result.append(" ");
    return result;


QString QvJson::encodeArray(const QVariant& jsonObject) 
    QString result("[ ");
    QList<QVariant> list = jsonObject.toList();
    for (int i = 0; i < list.count(); i++) 
        result.append(encodeJson(list.at(i)));
        if (i+1 < list.count()) 
            result.append(", ");
        
    
    result.append(" ]");
    return result;


QString QvJson::encodeString(const QVariant &jsonObject) 
    return encodeString(jsonObject.toString());


QString QvJson::encodeString(const QString& value) 
    QString result = "\"";
    for (int i = 0; i < value.count(); i++) 
        ushort chr = value.at(i).unicode();
        if (chr < 32) 
            switch (chr) 
                case '\b':
                    result.append("\\b");
                    break;
                case '\f':
                    result.append("\\f");
                    break;
                case '\n':
                    result.append("\\n");
                    break;
                case '\r':
                    result.append("\\r");
                    break;
                case '\t':
                    result.append("\\t");
                    break;
                default:
                    result.append("\\u");
                    result.append(QString::number(chr, 16).rightJustified(4, '0'));
              // End switch
        
        else if (chr > 255) 
            result.append("\\u");
            result.append(QString::number(chr, 16).rightJustified(4, '0'));
        
        else 
            result.append(value.at(i));
        
    
    result.append('"');
    QString displayResult = result;  // For debug, since "result" often doesn't show
    Q_UNUSED(displayResult);
    return result;


QString QvJson::encodeNumeric(const QVariant& jsonObject) 
    return jsonObject.toString();


QString QvJson::encodeBool(const QVariant& jsonObject) 
    return jsonObject.toString();


QString QvJson::encodeNull(const QVariant& jsonObject) 
    return "null";


QString QvJson::encodingError(const QString& method, const QVariant& jsonObject, Error error) 
    QString text;
    switch (error) 
        case ErrorUnrecognizedObject: 
            text = QObject::tr("Unrecognized object type");
            break;
    default:
            Q_ASSERT(false);
    
    return QObject::tr("*** Error %1 in QvJson::%2 -- %3").arg(error).arg(method).arg(text);

【讨论】:

不确定从网络复制/粘贴另一个 Qt json 实现(不包括单元测试)会提高可维护性。 @FrankOsterfeld - 不是来自网络。从我的私人藏匿处。

以上是关于序列化 JSON 数据 Qt的主要内容,如果未能解决你的问题,请参考以下文章

Qt 自定义序列化

Qt中 使用Json 对自定义对象进行序列与反序列化 之二

Qt中 使用Json 对自定义对象进行序列与反序列化 之一

c# 多个json字符串反序列化

使用C# json 二维数组 反序列化

newtonsoft.json 反序列化