Как прочитать довольно простой JSON-файл в Delphi Xe4?

#json #delphi #delphi-xe4

#json #delphi #delphi-xe4

Вопрос:

Я боролся с этим некоторое время, и выполнение чего-то простого, кажется, занимает слишком много времени.

У меня есть такой файл, как этот:

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

Я хочу иметь возможность включить их в свою программу. До сих пор я работал над этой милой маленькой функцией:

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

Проблема в том, что он возвращает массив пустых строк. Кто-нибудь может указать мне правильное направление?

ТИА Марк

Комментарии:

1. Попробуйте использовать SuperObject вместо этого — это на целый мир проще.

2. SuperObject было бы так же просто, как O.AsArray[jv].S['FirstName'] и O.AsArray[jv].S['Surname']

3. Не могли бы вы выразиться более конкретно? Что вы подразумеваете под суперобъектом? Я не могу найти его в источнике Embardcadero.

4. Это потому, что он не является частью исходного кода Embarcadero, это сторонняя библиотека

Ответ №1:

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

Комментарии:

1. Ах, элегантность дженериков. И более простое имя модуля System. JSON предполагает, что JSON считается более важным.

2. К счастью, мой Xe4 имеет ту же форму, что и пример XE5. Это сработало!

Ответ №2:

Вы не считываете правильное значение из элементов массива.
Попробуйте что-то вроде этого:

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

Объект JSON содержит пары значений, но у него нет самого значения, поэтому вы получаете пустые строки. Если вам нужен весь текст объекта, вы должны использовать метод «toString».

И действительно, SuperObject или XSuperObject проще в использовании и быстрее, если вам приходится работать с большим объемом данных. Второй, похоже, также доступен для iOS / Android, хотя я им не пользовался.

Комментарии:

1. Этот код выглядит красиво и читабельно. Откуда же взялся JSONArr? Он не назначается.

2. JSONValue на самом деле должно быть JSONArr

Ответ №3:

Спасибо tz и VGeorgiev. Вот окончательная форма кода, основанная на вашем:

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