Russian Qt Forum

Qt => XML => Тема начата: RustAlex от Апрель 28, 2016, 14:54



Название: JSON для key не зависящих от регистра
Отправлено: RustAlex от Апрель 28, 2016, 14:54
Можно как-то читать JSON по ключам унифицирующим регистр?

Может передаваться объект:
Код
"id":"1234"
 
или
Код
"ID":1234
 
написал метод:
Код
C++ (Qt)
QString updater::getJsonUpperStr(const QJsonObject &obj, const QString &key) const
{
   if(obj.contains(key)) {
       if( obj[key].isString() )
           return obj[key].toString();
       else if( obj[key].isDouble())
           return QString::number(obj[key].toInt());
   }
   else {
       if( obj[key.toUpper()].isString() )
           return obj[key.toUpper()].toString();
       else if( obj[key.toUpper()].isDouble())
           return QString::number(obj[key.toUpper()].toInt());
   }
}

Но выпадают случаи "Id":... и "iD":...
Нет ли готового "велосипеда"?
Переопределять operator==() для QJsonObject вроде тоже как не вариант, он же будет работать не для ключей, а для значений... так ведь?
Переопределять operator[]() - это выход?


Название: Re: JSON для key не зависящих от регистра
Отправлено: m_ax от Апрель 28, 2016, 19:23
Есть же итераторы и алгоритмы:

Код
C++ (Qt)
QString updater::getJsonUpperStr(const QJsonObject &obj, const QString &key) const
{
   auto it = std::find_if(obj.begin(), obj.end(), [&](const QJsonValueRef & elem) { return  QString::compare(key, elem.key, Qt::CaseInsensitive) == 0; } );
   if (it != obj.end())
   {
       return cast_to<QString>(*it);
   }
   return QString();
}
 
или так:
Код
C++ (Qt)
QString updater::getJsonUpperStr(const QJsonObject &obj, const QString &key) const
{
   for (const auto & elem : obj)
  {
       if (QString::compare(key, elem.key, Qt::CaseInsensitive) == 0)
          return cast_to<QString>(elem.value());
   }
   return QString();
}
 
 


Название: Re: JSON для key не зависящих от регистра
Отправлено: RustAlex от Апрель 29, 2016, 14:27
Спасибо.
Напрямую предложенный вариант не взлетел...
Вот такой вариант заработал:
Код
C++ (Qt)
QString updater::getJsonUpperStr(const QJsonObject &obj, const QString &key) const
{
   for (const auto & elem : obj.keys()) {
       if (key.compare( elem, Qt::CaseInsensitive) == 0)
           if(obj[elem].isString())
               return obj[elem].toString();
           else
               return QString::number(obj[elem].toInt());
   }
   return QString();
 


Название: Re: JSON для key не зависящих от регистра
Отправлено: RustAlex от Май 04, 2016, 13:37
Ожидал сразу же услышать критику, ведь

Код
C++ (Qt)
return obj[elem].toString();

По сути повторяет проход по JSON объекту.
Не понимаю почему не работает вариант:

Код
C++ (Qt)
   foreach (const auto & elem, obj)
   {
       if (key.compare( elem.key(), Qt::CaseInsensitive) == 0)
           if(elem.value().isString())
               return elem.value().toString();
           else
               return QString::number(elem.value().toInt());
   }
 

Этот код, на мой взгляд, должен быть эквивалентен:

Код
C++ (Qt)
  foreach (const QJsonObject::iterator & elem, obj)
   {
       if (key.compare( elem.key(), Qt::CaseInsensitive) == 0)
           if(elem.value().isString())
               return elem.value().toString();
           else
               return QString::number(elem.value().toInt());
   }
 

но это не так:
Код
C++ (Qt)
updater.cpp:1586: error: no viable conversion from 'QJsonValue' to 'const QJsonObject::iterator'
   foreach (const QJsonObject::iterator & elem, obj)
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~

хотя мне кажется что elem.value() как раз и должен вернуть QJsonValue

Где туплю?


Название: Re: JSON для key не зависящих от регистра
Отправлено: chabapok от Май 26, 2016, 21:14
По сути, предлагается искать нужные ключи последовательным перебором.

Это ж будет ужас по производительности, на сколь-нибудь больших json-ах.

Нормальный способ - подставить парсеру свою container factory, в которой отдавать наследника QJsonObject с перегруженным insert, который делал бы toLowercase.
парсер при создании json-структуры делает не напрямую new QJsonObject, а пользуется фабрикой.

Я не очень в QT, но бегло посмотрев исходники парсера, так и не смог представить, как подобное сделать.