Delphi XE7:如何使用System.JSON更改JSON值(相对于SuperObject)

8tntrjer  于 2023-10-18  发布在  其他
关注(0)|答案(2)|浏览(308)

我需要加载一个JSON文件,更改一个值,然后将其写回磁盘。
这很容易使用SuperObject,但我如何使用System.JSON单元做同样的事情呢?

const
  PathToX = 'AllCategories.Category[0].subCategory[0].products[0].views.view[0].x';

var
  JsonFilename: string;

  JO: ISuperObject; // from the SuperObject unit
  JV: TJsonValue;   // from the System.Json unit

begin
  JsonFilename := ExtractFilePath(Application.ExeName)+'product.json');

  // Using the SuperObject unit:
  JO := SO(TFile.ReadAllText(JsonFilename));

  WriteLn('The old value of "x" is ', JO[PathToX].AsString);
  WriteLn('Changing value of x to "123"');
  JO.S[PathToX] := '123';   // Set the value of "x"
  WriteLn('The new value of "x" is ', JO[PathToX].AsString);

  // Now trying to do the same thing using the System.Json unit:
  JV := TJSONObject.ParseJsonValue(TFile.ReadAllText(JsonFilename));

  WriteLn('The old value of "x" is ', JV.GetValue<string>(PathToX));
  WriteLn('Changing value of x to "123"');
// Question: What code should go here to set the value of "x" using System.JSON ??? 
  WriteLn('The new value of "x" is ', JV.GetValue<string>(PathToX));

在System.JSON中似乎没有与“GetValue”方法等效的“SetValue”。

7qhs6swi

7qhs6swi1#

TJSONObject支持类似于SuperObject的路径求值器。因此,您将不必手动地一次钻取一个对象到JSON值树中(尽管如果您愿意,您当然可以)。
然而,System.JSON类实际上不是为修改现有数据而设计的(信不信由你)!它们被设计用于 * 解析 * 数据和 * 创建 * 新数据。所有表示简单值(整数,布尔值,字符串)的JSON类都是只读的。幸运的是,TJSONPair类允许一个值被 * 替换 *,所以你必须利用这一点。
试试这样的方法:

uses
  ..., System.JSON;

var
  JsonFilename: string;
  JV: TJSONValue;
  JO: TJSONObject;
  JoX: Integer;
  JoPair: TJSONPair;
begin
  JsonFilename := ExtractFilePath(Application.ExeName) + 'product.json';

  JV := TJSONObject.ParseJSONValue(TFile.ReadAllText(JsonFilename));
  if JV = nil then raise Exception.Create('Cannot parse file: ' + JsonFilename);
  try
    JO := JV as TJSONObject;

    JoX := JO.GetValue<Integer>('AllCategories.Category[0].subCategory[0].products[0].colors.color[0].views.view[0].x');
    WriteLn('The old value of "x" is ', JoX);

    WriteLn('Changing value of "x" to "123"');
    JoPair := JO.GetValue<TJSONObject>('AllCategories.Category[0].subCategory[0].products[0].colors.color[0].views.view[0]').Get('x');
    JoPair.JsonValue.Free;
    JoPair.JsonValue := TJSONNumber.Create(123);
    WriteLn('The new value of "x" is ', JoPair.JsonValue.Value);

    SaveAsDialog.FileName := JsonFilename;
    if SaveAsDialog.Execute then TFile.WriteAllText(SaveAsDialog.FileName, JO.ToJSON);
  finally
    JV.Free;
  end;
end;

或者:

uses
  ..., System.JSON;

var
  JsonFilename: string;
  JV: TJSONValue;
  JO: TJSONObject;
  JoX: TJSONPair;
begin
  JsonFilename := ExtractFilePath(Application.ExeName) + 'product.json';

  JV := TJSONObject.ParseJSONValue(TFile.ReadAllText(JsonFilename));
  if JV = nil then raise Exception.Create('Cannot parse file: ' + JsonFilename);
  try
    JO := JV as TJSONObject;

    JoX := JO.GetValue<TJSONObject>('AllCategories.Category[0].subCategory[0].products[0].colors.color[0].views.view[0]').Get('x');
    WriteLn('The old value of "x" is ', JoX.JsonValue.Value);

    WriteLn('Changing value of "x" to "123"');
    JoX.JsonValue.Free;
    JoX.JsonValue := TJSONNumber.Create(123);
    WriteLn('The new value of "x" is ', JoX.JsonValue.Value);

    SaveAsDialog.FileName := JsonFilename;
    if SaveAsDialog.Execute then TFile.WriteAllText(SaveAsDialog.FileName, JO.ToJSON);
  finally
    JV.Free;
  end;
end;
3j86kqsm

3j86kqsm2#

雷米的回答在 Delphi 10.4中失败,在JO.ToJSON处存在访问冲突。去掉JoX.JsonValue.Free就解决了这个问题。这一方法:

Var S := '{"Key1":"Foo","Key2":"Foo","Key3":"Foo"}';
Var JO := TJSONObject.ParseJSONValue(S) as TJSONObject;
Var JP := JO.Get('Key2');
// JP.JsonValue.Free; DO NOT DO THIS!
JP.JsonValue := TJSONString.Create('Bar');
S := JO.ToJSON;
JO.Free;

S现在读作'{"Key1":"Foo","Key2":"Bar","Key3":"Foo"}',即按预期替换该值,并且对的顺序保持不变。根据MadExcept的说法,省略JP.JsonValue.Free并没有留下内存泄漏。

相关问题