【问题标题】:How to change QJsonObject value in a QJson hierarchy without using copies?如何在不使用副本的情况下更改 QJson 层次结构中的 QJsonObject 值?
【发布时间】:2013-06-06 17:25:21
【问题描述】:

我目前正在使用带有核心 QJson 库的 Qt5.0 来处理我正在开发的程序的一些数据。

为了解决这个问题,我将为您提供一些 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'。此键的值是 QJsonObjects 的 QJsonArray,其中包含许多包含我的数据的键/值对。

如果我想检索 ID 为“clk”的 QJsonObject,我目前正在使用如下代码:

// 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 引用以修改所需时钟数据对象中的键/值对。问题很明显,IMO 因为您可以获得 QJsonValueRefs,它们是对值条目的引用......但是要实际访问其中的数据(如果值是另一个数组/对象),您必须使用 toArray 进行转换()、toObject() 函数等。此函数仅返回副本而不是引用,从而为使用引用向下迭代对象层次结构造成障碍。

到目前为止,我想出解决此问题的唯一方法是创建整个“CLOCKS”QJsonArray 的副本,找到我想要的对象,然后将其删除并重新插入更改的数据......最后将整个数组分配回父对象中的“CLOCKS”键。这对我来说似乎很麻烦,我觉得我做错了什么,必须有更好的方法。

为了支持这一点,我的代码到目前为止是这样的......只是为了更改时钟 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 对象层次结构中的单个值,而无需付出所有这些努力!!!

【问题讨论】:

  • 我没有找到任何方法。真奇怪。旧的 QtScript 模块支持这个,你可以复制 QScriptValue。一个副本的对象修改会导致所有其他副本的修改。 QScriptObject 它不能那样工作。

标签: c++ json qt qt5 qjson


【解决方案1】:

根据实际在 Qt5 中编写 QJson 的 Qt 开发人员提供的信息 -

Qt 目前包含的是一个“只读”实现,用于提供解析工具。他打算在未来通过“参考”支持来扩展设计,但还没有完成。

【讨论】:

  • 好的,我不能修改,但是,我至少可以阅读吗?我的意思是这样的代码会起作用吗?只是为了阅读? json["aa"].toObject()["bb"].toString();
  • 跟踪此功能请求是否存在 Qt 问题?
  • 他们并不认为这是一个问题 =)
  • QTBUG-25723好像有关系,但是闲置了很久。
【解决方案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 目前允许。

【讨论】:

  • 它还没有修复。您可以在此处检查 toObject 的当前原型:doc.qt.io/qt-5/qjsonvalue.html#toObject - 只要 toObject 返回一个值而不是引用,问题就会一直存在。只有当有函数返回 QJsonObject& 时,问题才会得到解决。
  • 正确,为自己做了一些测试,确实没有修复。很烦人。
  • 好的,我不能修改,但是,我至少可以阅读吗?我的意思是这样的代码会起作用吗?只是为了阅读? json["aa"].toObject()["bb"].toString();
  • @Xsmael:是的,你可以像这样在 Qt 中读取 JSON。只是不修改。
  • 为澄清起见,Qt 5.6/5.7 中没有任何变化。
【解决方案3】:

这几天我遇到了类似的问题,我设法找到了一个适合我的解决方法,我想我应该在这里分享它。

您可以导航到要更新其键值对的对象。然后用“remove”方法删除键值对,再用“insert”方法用新值再次插入。

这可能会破坏对象中键值对的顺序,但由于您无论如何都会通过键访问,所以这应该不是问题。

不支持值的就地更改,因为我发现很难:)

【讨论】:

    猜你喜欢
    • 2019-08-31
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多