Delphi XE7: как изменить значение JSON с помощью System.JSON (по сравнению с SuperObject)
Мне нужно загрузить файл 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));
Похоже, что "SetValue" не эквивалентен методу "GetValue" в System.JSON.
2 ответа
TJSONObject
поддерживает оценку пути, аналогичную SuperObject. Таким образом, вам не придется вручную детализировать дерево значений JSON по одному объекту за раз (хотя вы, конечно, можете, если хотите).
Тем не менее System.JSON
классы на самом деле НЕ предназначены для изменения существующих данных (хотите верьте, хотите нет)! Они предназначены для анализа данных и создания новых данных. Все классы JSON, представляющие простые значения (целые числа, логические значения, строки), доступны только для чтения. К счастью, TJSONPair
Класс позволяет заменить значение, поэтому вам придется воспользоваться этим.
Попробуйте что-то вроде этого:
uses
..., System.JSON;
var
JsonFilename: string;
JO: TJSONObject;
JoX: Integer;
JoPair: TJSONPair;
begin
JsonFilename := ExtractFilePath(Application.ExeName)+'product.json';
JO := TJSONObject.ParseJSONValue(TFile.ReadAllText(JsonFilename)) as TJSONObject;
if JO = nil then raise Exception.Create('Cannot parse file: ' + JsonFilename);
try
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
JO.Free;
end;
end;
В качестве альтернативы:
uses
..., System.JSON;
var
JsonFilename: string;
JO: TJSONObject;
JoX: TJSONPair;
begin
JsonFilename := ExtractFilePath(Application.ExeName)+'product.json';
JO := TJSONObject.ParseJSONValue(TFile.ReadAllText(JsonFilename)) as TJSONObject;
if JO = nil then raise Exception.Create('Cannot parse file: ' + JsonFilename);
try
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
JO.Free;
end;
end;
Ответ Реми не работает в 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;
С теперь читает'{"Key1":"Foo","Key2":"Bar","Key3":"Foo"}'
, т.е. значение было заменено по назначению, а порядок пар остался неизменным. Согласно MadExcept, опускаяJP.JsonValue.Free
не оставил утечки памяти.