Mark Patterson
Mark Patterson

Reputation: 427

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

Upvotes: 8

Views: 22483

Answers (3)

Mark Patterson
Mark Patterson

Reputation: 427

Thanks to tz and VGeorgiev. Here is the final form of the code, based closely on yours:

function GetGeneratedNames: TArray<string>;
var data: TBytes;
    JSONValue, jv: TJSONValue;
    joName: TJSONObject;
    firstName, surname: string;
begin
  result := nil;
  data := TEncoding.ASCII.GetBytes(TFile.ReadAllText(ExePath + 'Names.json'));
  JSONValue := TJSONObject.ParseJSONValue(data, 0);
  for jv in JSONValue as TJSONArray do begin  // Returns TJSONValue
    joName := jv as TJSONObject;
    firstName := joName.Get('FirstName').JSONValue.Value;
    surname := joName.Get('Surname').JSONValue.Value;
    Append(Result, surname + ', ' + firstName);
  end{for};
end{ GetGeneratedNames};

Upvotes: 0

VGeorgiev
VGeorgiev

Reputation: 511

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.

Upvotes: 5

tz.
tz.

Reputation: 749

// 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 };

Upvotes: 11

Related Questions