Подтвердить что ты не робот

Как изменить значение QJsonObject в иерархии QJson без использования копий?

В настоящее время я использую Qt5.0 с базовой библиотекой QJson для обработки некоторых данных для разрабатываемой программы.

Чтобы установить сцену для этого вопроса, я предоставлю вам некоторые данные JSON, которые иллюстрируют мою проблему:

{
    "CLOCKS": [
        {
            "ID": "clk",
            "MAX": 2e+08,
            "MIN": 1e+07,
            "VALUE": "no_clock"
        },
        {
            "ID": "memclk",
            "MAX": 2e+08,
            "MIN": 1e+07,
            "VALUE": "memclk"
        }
    ]
}

Здесь у нас есть родительский объект QJsonObject, содержащий один ключ "CLOCKS". Значение для этого ключа - QJsonArray QJsonObjects, который содержит несколько пар ключ/значение, которые содержат мои данные.

Если бы я хотел получить QJsonObject с id 'clk', я в настоящее время использую такой код:

// imagine m_data is my parent QJsonObject
QJsonArray clocks = m_data["CLOCKS"].toArray();
foreach (const QJsonValue & value, clocks) {
    QJsonObject obj = value.toObject();
    if (obj["ID"].toString() == "clk") {
        return obj;
    }
}

Это прекрасно работает, и библиотека до сих пор была замечательной. Однако я недавно начал сталкиваться с проблемами, когда хочу получить QJsonObject reference для модификации вместо копии.

Итак, мой вопрос заключается в том, что, учитывая предоставленные примеры данных, как получить ссылку QJsonObject, чтобы изменить пары ключ/значение в желаемом объекте данных синхронизации. Проблема проявляется, ИМО из-за того, что вы можете получить QJsonValueRefs, которые являются ссылками на записи значений... но чтобы фактически получить доступ к данным внутри этого (если это значение является другим массивом/объектом), вы должны преобразовать, используя toArray(), toObject() и т.д. Эти функции возвращают только копии, а не ссылки, создающие барьер для итерации иерархии объектов со ссылками.

Единственный способ, с которым я пришел, чтобы обойти это, - создать копию всего "CLOCKS" QJsonArray, найти объект, который я хочу, затем удалить его и вставить в него с измененными данными... и, наконец, назначьте весь массив обратно к ключу CLOCKS в родительском объекте. Это кажется мне громоздким для меня, что я чувствую, что делаю что-то неправильно, и должен быть лучший способ.

Чтобы поддержать это, вот как выглядит мой код до сих пор... просто чтобы изменить "VALUE" для одного из часов QJsonObjects:

  QJsonArray resets = m_data.value(TAG_RESETS).toArray();

  // get a copy of the QJsonObject
  QJsonObject obj;
  foreach (const QJsonValue & value, resets) {
    QJsonObject o = value.toObject();
    if (o.value(TAG_ID).toString() == id) {
      obj = o;
      break;
    }
  }

  // modify the object
  obj[TAG_VALUE] = "NEW VALUE";

  // erase the old instance of the object
  for (auto it = resets.begin(); it != resets.end(); ++it) {
    QJsonObject obj = (*it).toObject();
    if (obj.value(TAG_ID).toString() == id) {
      resets.erase(it);

      // assign the array copy which has the object deleted
      m_data[TAG_RESETS] = resets;
      break;
    }
  }   

  // add the modified QJsonObject
  resets.append(obj);

  // replace the original array with the array containing our modified object
  m_data[TAG_RESETS] = resets;

Я знаю, что это может быть сокращено немного, но все же кажется, что должен быть лучший способ изменить одно значение в иерархии объектов QJson, не прибегая к этим усилиям.

4b9b3361

Ответ 1

Согласно информации от разработчика Qt, который фактически написал QJson в Qt5 -

То, что в настоящее время включено в Qt, является реализацией только для чтения, чтобы обеспечить возможности синтаксического анализа. Он намерен продлить дизайн с поддержкой "ссылок" в будущем, но это еще не сделано.

Ответ 2

Потеряв три часа своей жизни, я могу подтвердить, что на сегодняшний день это по-прежнему невозможно с Qt 5.4. Вы можете изменять объекты JSON, но не вложенные объекты JSON.

Проблема заключается в том, что код, например:

json["aa"].toObject()["bb"] = 123;

по существу означает следующее:

QJsonObject temp = json["aa"].toObject();
temp["bb"] = 123;

и поскольку temp не является ссылкой, но объект (и toObject() не возвращает ссылку), назначение скомпилируется, но затем отбрасывается.

По сути, это ломается до того, что невозможно получить ссылку на только что созданный объект, то есть вы не можете создать их слева направо, т.е. aa [ "bb" ] → aa [ "bb" ] [ "cc" ] и т.д. - вы не можете получить ссылку на aa [ "bb" ], только копию ее значения.

Возможно, однако, воссоздать JSON с добавленной добавленной стоимостью, как описано здесь: https://forum.qt.io/topic/25096/modify-nested-qjsonvalue/4 - обратите внимание, что это сохраняется воссоздавая объект каждый раз, когда он вызывается, и по сути является катастрофой использования памяти, но это все, что позволяет Qt.