Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read fairly simple JSON file in Delphi Xe4?

I've been struggling with this for a while, and doing something simple seems to be taking too long.

I have a file like this:

[
 {
  "FirstName": "Oleg",
  "Surname": "Buckley"
 },
 {
  "FirstName": "Amery",
  "Surname": "Mcmillan"
 },
 {
  "FirstName": "Denton",
  "Surname": "Burnett"
....

I want to be able to read them into my program. So far I have worked up this pretty little function:

function GetGeneratedNames: TArray<string>;
var fileName: TFileName;
  JSONValue, jv: TJSONValue;
  JSONArray: TJSONArray;
  jo: TJSONObject;
  pair: TJSONPair;
begin
  result := nil;
  filename := ExePath + 'Names.json';
    JSONValue :=  TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(TFile.ReadAllText(filename)), 0);
    if JSONValue is TJSONArray then begin
     for jv in (JSONValue as TJSONArray) do begin
       if jv is TJSONObject then begin
         jo := jv as TJSONObject;
         for pair in jo do begin
           Append(result, jo.Value);
         end;
       end;
     end;
   end;
end{ GetGeneratedNames};

The trouble is, it returns an array of blank strings. Can anyone point me in the right direction?

TIA Mark

like image 545
Mark Patterson Avatar asked Jun 28 '14 11:06

Mark Patterson


2 Answers

// XE5- version
uses System.SysUtils, Data.DBXJSON, System.IOUtils;

function GetGeneratedNames: TArray<string>;
var
  fileName: TFileName;
  JSONValue, jv: TJSONValue;
begin
  fileName := TPath.Combine(ExePath, 'Names.json');
  JSONValue := TJSONObject.ParseJSONValue(TFile.ReadAllText(fileName));
  try
    if JSONValue is TJSONArray then
    begin
      for jv in TJSONArray(JSONValue) do
      begin
        Append(Result, (jv as TJSONObject).Get('FirstName').JSONValue.Value);
        Append(Result, (jv as TJSONObject).Get('Surname').JSONValue.Value);
      end;
    end;
  finally
    JSONValue.Free;
  end;
end { GetGeneratedNames };

// XE6+ version
uses System.SysUtils, System.JSON, System.IOUtils;

function GetGeneratedNames: TArray<string>;
var
  fileName: TFileName;
  JSONValue, jv: TJSONValue;
begin
  fileName := TPath.Combine(ExePath, 'Names.json');
  JSONValue := TJSONObject.ParseJSONValue(TFile.ReadAllText(fileName));
  try
    if JSONValue is TJSONArray then
    begin
      for jv in TJSONArray(JSONValue) do
      begin
        Append(Result, jv.GetValue<string>('FirstName'));
        Append(Result, jv.GetValue<string>('Surname'));
      end;
    end;
  finally
    JSONValue.Free;
  end;
end { GetGeneratedNames };
like image 174
tz. Avatar answered Sep 30 '22 20:09

tz.


You are not reading the correct value from the array items.
Try something like this:

//...
var
  JSONArr: TJSONArray;
  Item: TJSONValue;
  FirstName, Surname, WholeObject: String;
begin
  //...
  JSONArr := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(TFile.ReadAllText(filename)), 0);
  try
    for Item in JSONArr do
    begin
      // Get the first or last names
      FirstName := (Item as TJSONObject).GetValue('FirstName').Value;
      Surname := (Item as TJSONObject).GetValue('Surname').Value;
      // Get the whole string {"FirstName": "Oleg", "Surname": "Buckley"}
      WholeObject := Item.ToString; 
    end;
  finally
    JSONArr.Free;
  end;
  // do something with them ...
end;

The JSON object contains value pairs, but it doesn't have a value itself, so you get empty strings. If you want the whole object text you should use the "ToString" method.

And indeed SuperObject or XSuperObject are easier to use and faster if you happen to work with a large amount of data. The second one seems to also be available for iOS/Android, although I haven't used it.

like image 42
VGeorgiev Avatar answered Sep 30 '22 21:09

VGeorgiev