Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2257496
  • 博文数量: 862
  • 博客积分: 14125
  • 博客等级: 上将
  • 技术积分: 10598
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-27 16:53
个人简介

https://github.com/zytc2009/BigTeam_learning

文章分类

全部博文(862)

文章存档

2019年(3)

2018年(1)

2017年(10)

2015年(3)

2014年(8)

2013年(3)

2012年(69)

2011年(103)

2010年(357)

2009年(283)

2008年(22)

分类: 系统运维

2011-03-17 18:41:19

QT 实现 JSON 转换的代码

转自:http://xuyuanfeilive.spaces.live.com/Blog/cns!A6231AFFEE249FFD!555.entry

QString JSONPaser::toJson(const QVariantMap& data)
{
    QStringList members;
    for(QVariantMap::ConstIterator it = data.begin(); it != data.end(); ++it)
    {
        members.append(QString("\"%1\": %2").arg(it.key()).arg(parseElement(it.value())));
    }
    return "{" + members.join(", ") + "}";
}

QString JSONPaser::parseElement(const QVariant& value)
{
    switch(value.type())
        {
        case QVariant::Bool:
            return value.toBool() ? "true" : "false";
        case QVariant::Map:
            return toJson(value.toMap());
        case QVariant::Int:
            return QString::number(value.toInt());
        case QVariant::LongLong:
            return QString::number(value.toLongLong());
        case QVariant::Double:
            return QString::number(value.toDouble());
        case QVariant::UInt:
            return QString::number(value.toUInt());
        case QVariant::ULongLong:
            return QString::number(value.toULongLong());
        case QVariant::List:
            return parseList(value.toList());
        case QVariant::String:
            return QString("\"%1\"").arg(value.toString().replace("\"", "\\\"")).replace("\n", "\\n").replace("\t", "\\t");
        case QVariant::Invalid:
            return "null";
        default:
            return QString();
    }
}

QString JSONPaser::parseList(const QVariantList& list)
{
    QStringList parts;
    Q_FOREACH(QVariant variant, list)
    {
        parts.append(parseElement(variant));
    }
    return "[" + parts.join(", ") + "]";
}

由JSON到OBJECT的程序
QVariantMap JSONPaser::toObject(const QString& json) throw(ParseException)
{
    // Store the start and end of the string
    m_next = json.constBegin();
    m_end = json.constEnd();
    // A JSON Object is the top-level item in the parse tree
    return parseObject();
}

QVariantMap JSONPaser::parseObject()
{
    /*
     * object
     *     {}
     *     { members }
     */

    QVariantMap data;

    consume('{');
    if(peekNext() != '}')
        data = parseMembers();
    consume('}');

    return data;
}

QVariantMap JSONPaser::parseMembers()
{
    /*
     * members
     *     pair
     *     pair , members
     */

    QVariantMap data;
    QPair pair;

    // loop instead of recursing
    do
    {
        // Grab a pair
        pair = parsePair();

        // Store it in our data
        data[pair.first] = pair.second;
    }
    while(tryConsume(',')); // Loop if we've got a list separator

    return data;
}

QPair JSONPaser::parsePair()
{
    /*
     * pair
     *     string : value
     */

    QString key = parseString();
    consume(':');
    QVariant value = parseValue();

    return qMakePair(key, value);
}

QVariantList JSONPaser::parseArray()
{
    /*
     * array
     *     []
     *     [ elements ]
     */

    QVariantList data;

    consume('[');
    if(peekNext() != ']')
        data = parseElements();
    consume(']');

    return data;
}

QVariantList JSONPaser::parseElements()
{
    /*
     * elements
     *     value
     *     value , elements
     */
    QVariantList data;

    // loop instead of recursing
    do
    {
        // Grab a value
        data += parseValue();
    }
    while(tryConsume(',')); // repeat if we've got a list separator

    return data;
}

QVariant JSONPaser::parseValue()
{
    /*
     * value
     *     string
     *     number
     *     object
     *     array
     *     bool
     *     null
     */

    tryConsume(':');

    // Lookahead to work out the type of value
    switch(peekNext().toAscii())
    {
        case '"':
            return parseString();
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case '-':
            return parseNumber();
        case '{':
            return parseObject();
        case '[':
            return parseArray();
        case 't': // true
        case 'f': // false
            return parseBool();
        case 'n': // null
            return parseNull();
        default:
            FAIL(QObject::tr("string, number, object, array, bool, or null"));
    }
}

QString JSONPaser::parseString()
{
    /*
     * string
     *     ""
     *     " chars "
     */

    QString data;

    // Starting quotation marks
    consume('"');

    // If it's a non-empty string, grab the contents
    if(*m_next != '"')
        data = parseChars();

    // Ending quotation marks
    consume('"');

    return data;
}

QString JSONPaser::parseChars()
{
    /*
     * chars
     *     char
     *     char chars
     */

    QString data;

    // chars contains at least one char
    data = parseChar();

    // See if there's more...
    Q_FOREVER
    {
        try { data += parseChar(); }
        catch(ParseException e)
        {
            // If not, it doesn't matter - roll back
            m_next = m_sym--;
            break;
        }
    }
    return data;
}

QChar JSONPaser::parseChar()
{
    /*
     * char
     *     any character except for ", \, or control characters
     *    \"
     *    \\
     *    \/
     *    \b
     *    \f
     *    \n
     *    \r
     *    \t
     *    \u four-hex-digits
     */

    // Grab the next character, without skipping whitespace
    consume(false);

    // We're not allowed unescaped quotation marks
    if(*m_sym == '"')
        FAIL(QObject::tr("Any unicode character except for \" or JSON escape sequences"));
   
    // But some escape sequences are allowed
    if(*m_sym == '\\')
    {
        QString digits;
        switch(consume().toAscii())
        {
            case '"':
                return '"';
            case '\\':
                return '\\';
            case 'b':
                return '\b';
            case 'f':
                return '\f';
            case 'n':
                return '\n';
            case 'r':
                return '\r';
            case 't':
                return '\t';
            case 'u':
                // Unicode 4-digit hex
                for(int i = 0; i < 4; ++i)
                {
                    digits += parseHexDigit();
                }
                return QChar(digits.toInt(0, 16));
            default:
                FAIL("[\"\\/bfnrtu]");
        }
    }
    return *m_sym;
}

QVariant JSONPaser::parseNumber()
{
    /*
     * number
     *     int
     *     int frac
     *     int exp
     *     int frac exp
     */

    // Every JSON number starts with an int
    QString data = parseInt();

    // Lookahead for fractions and exponents

    // Do we have a fraction?
    if(*m_next == '.') data += parseFrac();
    // Do we have an exponent?
    if(*m_next == 'e' || *m_next == 'E') data += parseExp();

    // Try several return types...
    bool ok;
    QVariant ret;

    ret = data.toInt(&ok); if(ok) return ret;
    ret = data.toLongLong(&ok); if(ok) return ret;
    ret = data.toDouble(&ok); if(ok) return ret;

    // If this point is reached, don't know how to convert the string
    // to an integer.
    Q_ASSERT(false);
    return QVariant();
}

QString JSONPaser::parseInt()
{
    /*
     * int
     *     digit
     *     digit1-9 digits
     *     - digit
     *     - digit1-9 digits
     */

    QString data;

    // Match any negation mark
    if(tryConsume('-'))
        data = "-";

    // Grab the first digit...
    QChar firstDigit = parseDigit();
    data += firstDigit;
    // ...if it's not zero...
    if(firstDigit != '0')
    {
        // ... try and add more digits.
        try { data += parseDigits(); }
        catch(ParseException)
        {
            // Catch, as more digits are entirely optional
            // Roll back.
            m_next = m_sym--;
        }
    }
    return data;
}

QString JSONPaser::parseFrac()
{
    /*
     * frac
     *     . digits
     */

    consume('.');
    return QString(".%1").arg(parseDigits());
}

QString JSONPaser::parseExp()
{
    /*
     * exp
     *     e digits
     */

    QString data;
    data = parseE();
    data += parseDigits();
    return data;
}

QString JSONPaser::parseDigits()
{
    /*
     * digits
     *     digit
     *     digit digits
     */

    QString data;

    // Digits has at least one digit...
    data += parseDigit();

    // ... try and get some more
    // Loop instead of recurse
    Q_FOREVER
    {
        try { data += parseDigit(); }
        catch(ParseException)
        {
            m_next = m_sym--; // roll back
            break;
        }
    }
    return data;
}

QString JSONPaser::parseE()
{
    /*
     * e
     *     e
     *     e+
     *     e-
     *     E
     *     E+
     *     E-
     */

    // Try and grab an 'e' or 'E'
    if(consume(false).toLower() == 'e')
    {
        // digits in follow[e]
        if(m_next->isDigit())
            return "e";

        // Hopefully the next is a + or -
        // grab another chracter...
        consume(false);
        // If it's not + or -, fail
        if(*m_sym != '+' && *m_sym != '-')
            FAIL("+ | -");

        // Otherwise, return e[+-]
        return QString("e%1").arg(*m_sym);
    }
    else
        FAIL("e | E");
}


QChar JSONPaser::parseDigit()
{
    /*
     * digit
     *     [0-9]
     */

    if(!consume(false).isDigit())
        FAIL("[0-9]");
    return *m_sym;
}

QChar JSONPaser::parseHexDigit()
{
    /*
     * hexdigit
     *     [0-9a-fA-F]
     */

    QChar character = consume().toLower();
    if(character.isDigit() || (character >= 'a' && character <= 'f'))
        return character;
    FAIL("[0-9a-fA-F]");
}

bool JSONPaser::parseBool()
{
    /*
     * bool
     *     true
     *     false
     */

    switch(peekNext().toAscii())
    {
        case 't':
            consume(QString("true"));
            return true;
        case 'f':
            consume(QString("false"));
            return false;
        default:
            consume(false);
            FAIL("true | false");
    }
}

QVariant JSONPaser::parseNull()
{
    /*
     * null
     *     null
     */

    consume(QString("null"));
    return QVariant();
}

QString JSONPaser::remaining()
{
    QString data;

    QString::ConstIterator it = m_sym;
    while(it != m_end) data += *it++;

    return data;
}

QChar JSONPaser::consume(bool skipWhitespace) throw(ParseException)
{
    // Read a character...
    do
    {
        if(m_next == m_end)
        {
            throw ParseException("EOF", "symbol", remaining());
        }
        m_sym = m_next++;
    }
    //...and loop while we get whitespace, if it's being skipped
    while(skipWhitespace && m_sym->isSpace());

    // Just for convenience...
    return *m_sym;
}

void JSONPaser::consume(QChar wanted) throw(ParseException)
{
    // Grab a char(ignoring whitespace), and if it's not what's
    // expected, throw
    if(consume() != wanted)
    {
        FAIL(wanted);
    }
}

void JSONPaser::consume(char wanted) throw(ParseException)
{
    // Convenience function for the above
    consume(QChar(wanted));
}

void JSONPaser::consume(QString wanted) throw(ParseException)
{
    // Keep track of where we start...
    QString::ConstIterator it = m_sym;
    // Grab wanted.length() characters, and compare them to the
    // character in the appropriate position in the parameter
    for(int i = 0; i < wanted.length(); ++i)
        if(consume(false) != wanted[i])
        {
            // If it doesn't match, roll back, and throw a
            // parse exception
            m_sym = it;
            m_next = ++it;
            FAIL(wanted);
        }
}

bool JSONPaser::tryConsume(QChar wanted) throw()
{
    // Grab the next character
    try
    {
        consume();
    }
    catch(ParseException)
    {
        // End-Of-String, rollback and return false
        m_next = m_sym--;
        return false;
    }

    // Check if it's what we want
    if(*m_sym != wanted)
    {
        // nope, something else, rollback and return false
        m_next = m_sym--;
        return false;
    }
    return true;
}

QChar JSONPaser::peekNext(bool skipWhitespace) throw(ParseException)
{
    QString::ConstIterator it = m_sym;
    do
    {
        ++it;
        if(it == m_end)
        {
            FAIL("symbol");
        }
    }
    while(skipWhitespace && it->isSpace());
    return *it;
}
阅读(1238) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~