Einzelnen Beitrag anzeigen

Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#32

AW: JSON einlesen - Hilfe für Anfänger

  Alt 23. Dez 2021, 11:19
Ich hatte etwas Muße das nochmal detaillierter zu betrachten. Herausgekommen ist dabei eine hybride Lösung:
Delphi-Quellcode:
unit TestJSON1Unit1;

interface

uses
  System.SysUtils, System.Classes, System.Generics.Collections,
  REST.JSON.Types, REST.Json, System.JSON;

type
  TEPGInfo = class
  private
    FId: Integer;
    [JSONName('t')]
    FTitle: string;
    [JSONName('et')]
    FEpisode_Title: string;
    [JSONName('g')]
    FGenre: TArray<string>;
  public
    property Id: Integer read FId;
    property Title: string read FTitle;
    property Episode_Title: string read FEpisode_Title;
    property Genre: TArray<string> read FGenre;
  end;

type
  TChannel = class(TObjectList<TEPGInfo>)
  private
    FName: string;
  public
    property Name: string read FName write FName;
  end;
  TChannels = class(TObjectDictionary<string, TChannel>);

procedure LoadChannels(const AJson: string; Target: TChannels; const AChannels: TArray<string> = nil);

implementation

uses
  System.StrUtils;

procedure LoadChannels(const AJson: string; Target: TChannels; const AChannels: TArray<string> = nil);
var
  channel: TChannel;
  channelName: string;
  item: TJSONValue;
  jsonObj: TJSONObject;
  jsonValue: TJSONValue;
  pair: TJSONPair;
begin
  jsonValue := TJSONObject.ParseJSONValue(AJson);
  try
    jsonObj := (jsonValue as TJSONObject).Values['channels'] as TJSONObject;
    for pair in jsonObj do begin
      channelName := pair.JsonString.Value;
      if (Length(AChannels) > 0) and not MatchText(channelName, AChannels) then Continue;
      channel := TChannel.Create;
      channel.Name := channelName;
      for item in (pair.JsonValue as TJSONArray) do
        channel.Add(TJson.JsonToObject<TEPGInfo>(item as TJSONObject));
      Target.Add(channel.Name, channel);
    end;
  finally
    jsonValue.Free;
  end;
end;

end.
Aufgerufen wird das dann so:
Delphi-Quellcode:
program TestJSON1;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.IOUtils,
  System.Generics.Collections,
  TestJSON1Unit1 in 'TestJSON1Unit1.pas';

procedure ListChannels(Channels: TChannels);
{ Sender auflisten }
var
  arr: TArray<string>;
  S: string;
begin
  arr := Channels.Keys.ToArray;
  TArray.Sort<string>(arr);
  for S in arr do
    Writeln(S);
end;

procedure ListProgram(Channels: TChannels; const AName: string);
{ Programm auflisten }
var
  channel: TChannel;
  info: TEPGInfo;
begin
  channel := Channels[AName];
  if channel <> nil then begin
    Writeln(channel.Name);
    for info in channel do
      Writeln(Format('%d: %s - %s (%s)', [info.Id, info.title, info.Episode_Title, string.Join(',', info.Genre)]));
  end;
end;

procedure ParseJson();
var
  arr: TArray<string>;
  channel: TChannel;
  channels: TChannels;
  FileContent: string;
  info: TEPGInfo;
  S: string;
begin
  FileContent := TFile.ReadAllText('c:\Users\Uwe\Downloads\EPG_GUIDE\EPG_GUIDE.json');
  channels := TChannels.Create;
  try
    LoadChannels(FileContent, channels, ['ard', 'zdf']);
    ListChannels(channels);
    ListProgram(channels, 'ard');
    ListProgram(channels, 'zdf');
  finally
    channels.Free;
  end;
end;

begin
  try
    ParseJson;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Write('press enter...');
  Readln;
end.
Sollten weitere EPG-Felder benötigt werden, reicht es diese in der Klasse TEPGInfo entsprechend zu ergänzen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat