web-dev-qa-db-ja.com

コピーを使用せずにQJson階層のQJsonObject値を変更するにはどうすればよいですか?

私は現在、コア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"
        }
    ]
}

ここに、単一のキー「CLOCKS」を含む親QJsonObjectがあります。このキーの値は、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参照を取得する方法です。値エントリへの参照であるQJsonValueRefsを取得できるため、IMOの問題が明らかになりますが、実際にこの内部のデータにアクセスするには(値が別の配列/オブジェクトの場合)、toArrayを使用して変換する必要があります()、toObject()関数など。この関数はコピーのみを返し、参照は返さず、参照を使用してオブジェクト階層を反復する際の障壁を作成します。

これを回避するためにこれまでに思いついた唯一の方法は、「CLOCKS」QJsonArray全体のコピーを作成し、必要なオブジェクトを見つけて削除し、変更されたデータで再挿入することです...そして最後に全体を割り当てます親オブジェクトの「CLOCKS」キーに配列を戻します。これは私には十分に面倒に思えるので、私は何か間違ったことをしているように感じ、より良い方法があるに違いありません。

これをサポートするために、これまでの私のコードは次のようになっています...クロックQJsonObjectsの1つの「VALUE」を変更するだけです。

  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オブジェクト階層の単一の値を変更するより良い方法があるはずです!!!

18
user2472658

Qt5で実際にQJsonを書いたQt開発者からの情報によると-

現在Qtに含まれているのは、解析機能を提供するための「読み取り専用」実装です。彼は将来、「参照」をサポートして設計を拡張するつもりですが、まだ実行されていません。

9
evilruff

私の人生の3時間を無駄にした後、今日の時点でこれはQt5.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 "]への参照を取得することはできず、その値のコピーのみを取得します。

ここで説明するように、IS可能ですが、新しい値を追加してJSONを再作成することは可能です: https://forum.qt.io/topic/25096/modify-nested- qjsonvalue/4 -これは呼び出されるたびにオブジェクトを再作成し続け、本質的にメモリ使用量の災害ですが、これはQtが現在許可しているすべてであることに注意してください。

13
George Y.

私は数日間同様の問題を抱えていましたが、自分に合った回避策を見つけることができたので、ここで共有する必要があると思いました。

Key-Valueを更新するオブジェクトに移動できます。次に、「remove」メソッドを使用してキーと値のペアを削除してから、「insert」メソッドを使用して新しい値で再度挿入します。

これにより、オブジェクト内のキーと値のペアの順序が損なわれる可能性がありますが、とにかくキーでアクセスするため、問題にはなりません。

私が難しい方法を見つけたので、値のインプレース変更はサポートされていません:)

0
BombayBlue