Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi JSON einlesen - Hilfe für Anfänger (https://www.delphipraxis.net/209555-json-einlesen-hilfe-fuer-anfaenger.html)

TERWI 20. Dez 2021 20:30

JSON einlesen - Hilfe für Anfänger
 
... eine absoluter JSON-Laie braucht Hilfe:
Wie lese ich einfach und schnell Daten mit folgendem Aufbau ein ?
Hab bisher mit JSON noch nix gemacht.
Die Reihenfolge der Daten in den Blöcken kann je nach Quelle unterschiedlich sein.
Speichern will ich das ganze in einer TList aus Records
Code:
{"Blöcke":
  {"Block_A":
    [{"Liste_1":[],
      "Liste_2":["Text_A"],
      "Int_1":111,
      "Txt_1":"Bla...",
      "Txt_2":"..Bla",
      "Int_2":2222,
      "Bool_1":true,
      "Liste_3":["Text_B","Text_C"],
      "Real_1":123,4,
      "Wert":null,
      "Bool_2":false,
      "Liste_4":[1,3,5,7]
     },
    ],
   "Block_B":
    [{... wie Block_A ...
     }
    ],
   ....
   "Block_Z":
    [{... wie Block_A ...
     }
    ],
  }
}
Wie lese ich das gescheit & einfach in Schleife mit TJSONObject, TJSONArray, TJSONValue, .... aus ?

freimatz 21. Dez 2021 07:47

AW: JSON einlesen - Hilfe für Anfänger
 
Google mal nach "delphi json reader example"

TERWI 21. Dez 2021 11:28

AW: JSON einlesen - Hilfe für Anfänger
 
Na logo habe ich auch schon rumgekugelt... aber finde nirgends was für Dummies, die das erste mal damit hantieren.
Zudem sehen die JSON-Daten in den Beispielen alle irgendwie anders aus (auch von den Klammerstellungen).

"Blöcke" wird hier wohl das ganze Array heissen, gibt's nur 1x im Kopf.
"Block_A" bis "Block_Z" sind die jeweiligen Namen der Array-Einträge ?!

Diese Namen kenne ich nicht und muss danach suchen, bzw. beim Durchlaufen auswerten - dazu hab ich nix gefunden.
Die Reihenfolge und Anzahl ist dazu auch beliebig.
Der Name ist aber wichtig, da ich den zum einen als Erkennung ob vorhanden benötige und mit dem Namen dann auch in meiner Liste entsprechend die Werte speichern will.

Jeder Block für sich hat dann aber wieder eine fixe Anzahl von Werten, dessen Typ und Namen ich auch kenne.
(Liste_x, Int_x, Bool_x, ...)
Und wie erkenne ich, wie viele Einträge eine Werte-Liste aus Strings oder Integern hat ? (siehe Liste_3 und Liste_4).

Ich bräuchte für den AHA-Effekt mal einen rudimentären Denkanstoß.

DeddyH 21. Dez 2021 11:43

AW: JSON einlesen - Hilfe für Anfänger
 
Du hast ein JSON-Objekt mit einem Feld "Blöcke", was wiederum ein JSON-Objekt ist. Dieses hat dann die Felder "Block_A" bis "Block_Z". Jedes dieser Block-Felder ist ein JSON-Array, bestehend aus JSON-Objekten. Diese JSON-Objekte wiederum weisen die folgenden Felder auf:
- Liste_1: JSON-Array (Datentyp nicht ersichtlich)
- Liste_2: JSON-Array vom Typ String
- Int_1: Integer
- Txt_1: String
- Int_2: Integer
- Bool_1: Boolean
- Liste_3: JSON-Array vom Typ String
- Real_1: soll wohl Single oder Double sein, Notation ist aber falsch (Punkt statt Komma als Dezimaltrenner verwenden, TJSONNumber in Delphi)
- Wert: unbekannter Datentyp, da TJSONNull im Beispiel
- Bool_2: Boolean
- Liste_4: JSON-Array vom Typ Integer

Ich hoffe, das hilft Dir schon einmal etwas weiter.

Aviator 21. Dez 2021 11:59

AW: JSON einlesen - Hilfe für Anfänger
 
Ich habe mal einen schemenhaften Aufbau gemacht. Die JSON Datei war vmtl. sowieso nur ein Beispiel von dir. Allerdings ist auch der Aufbau darin merkwürdig und manche Dinge machen auch gar keinen Sinn.

Beispielsweise ist
Delphi-Quellcode:
Blöcke
ein Objekt, das wiederum einzelne Properties hat die ein Array sind, aber nur ein Objekt beinhalten. Ich glaube, dass der Aufbau falsch herum ist. Das solltest du bei deinen Beispielen beachten. Ansonsten kann es schwierig werden zu helfen.

Ausgehend von folgendem JSON String habe ich jetzt mal eine kleine Mini-Procedure gebaut die dir helfen sollte den JSON String in ein Objekt umzuwandeln. Du musst das natürlich noch auf deine Bedürfnisse anpassen.

Disclaimer: Der Code ist nur so im Editor getippt. Also keine Gewähr auf 100%ige Funktionsfähigkeit.

Code:
{
    "Blöcke": [
        {
            "Liste_1": [
                "Text_A"
            ],
            "Int_1": 111,
            "Txt_1": "Bla...",
            "Bool_1": true,
            "Real_1": 123.4,
            "Liste_4": [
                1,
                3,
                5,
                7
            ]
        },
        {
            "Liste_1": [
                "Text_A"
            ],
            "Int_1": 111,
            "Txt_1": "Bla...",
            "Bool_1": true,
            "Real_1": 123.4,
            "Liste_4": [
                1,
                3,
                5,
                7
            ]
        }
    ]
}
Wichtig bei dem Delphi JSON Parser ist, dass die Felder mit dem Buchstaben F anfangen. Ansonsten findet der Parser diese nicht und ignoriert sie. Die Felder müssen zudem genau so benannt werden wie sie in der JSON Datei auch lauten. Solltest du sie anders benennen wollen, gibt es gewisse Attribute die du zu den Felder zuweisen kannst. Dann weiß der Parser, dass er sie mit dem Namen
Delphi-Quellcode:
Foo
"ansprechen" soll obwohl sie
Delphi-Quellcode:
Bar
heißen.

Delphi-Quellcode:
type
  TBlock = class
  private
    FListe1: TArray<string>;
    FListe4: TArray<Integer>;
    FInt_1: Integer;
    FTxt_1: string;
    FBool_1: Boolean;
    FReal_1: Real;
  public
    property Liste1: TArray<string> read FListe1 write FListe1;
    property Liste4: TArray<Integer> read FListe4 write FListe4;
    property Int_1: Integer read FInt_1 write FInt_1;
    property Txt_1: string read FTxt_1 write FTxt_1;
    property Bool_1: Boolean read FBool_1 write FBool_1;
    property Real_1: Real read FReal_1 write FReal_1;
  end;

  TBlocks = TArray<TBlock>;

procedure ParseJson();
var
  FileContent: String;
  Blocks: TBlocks;
begin
  FileContent := TFile.ReadAllText('path\to\file.json');
  Blocks := TJson.JsonToObject<TBlocks>(FileContent);
end;

mytbo 21. Dez 2021 12:02

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

Zitat von TERWI (Beitrag 1499446)
Zudem sehen die JSON-Daten in den Beispielen alle irgendwie anders aus (auch von den Klammerstellungen).

Wie dir schon selbst aufgefallen ist, sieht die gegebene JSON Struktur "gewöhnungsbedürftig" aus. Für deinen beschriebenen Fall bietet sich förmlich mORMot an. Meiner Meinung nach eine der besten und mächtigsten Libraries in der Delphi Welt. Ich würde das Ganze in eine DocVariant Struktur laden. Dann kannst du alles ohne große Probleme in kleine Happen zerlegen.

mORMot ist von D7 bis 11 verfügbar. Es reicht aus, die entsprechenden Bibliothekspfade einzufügen. Die eigentliche Arbeit ist mit mORMot oft schnell erledigt, das Problem dürfte sein, dich in mORMot einzuarbeiten. Es steht eine ausführliche Hilfe, viele Beispiele und ein freundliches Forum zur Verfügung. Hier findest du den Download.

Bis bald...
Thomas

TERWI 21. Dez 2021 12:27

AW: JSON einlesen - Hilfe für Anfänger
 
... das ist mir auch schon klar, hatte ich ja auch in etwa so geschrieben.
Die Quizfrage ist nur: Wie komm ich an die Daten & Namen in einer Schleife und Wie frage ich die Werte-Arrays im Array-Eintrag ab / prüfe die ?
Mit Denkanstoß mente ich ein paar hilfreiche Zeilen Code.


OOops - da hat sich was überschnitten.

Merkwürdig ?
Nein, die Daten sehen vom Format / Klammerstellung ( {} und [] ) exakt so aus ! Ich habe nur die Namen und ANzahl der Felder geändert / gekürzt.
Ich kann's ja ruhig sagen: Das ist eine Abfrage bei ZATTO-IPTV für die elementaren EPG-Daten. Kanal-Liste sieht ähnlich aus.
Ich könnte ja mal eine Datei anhängen ?!

Aviator 21. Dez 2021 13:44

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

Zitat von TERWI (Beitrag 1499452)
Ich könnte ja mal eine Datei anhängen ?!

Kannst du machen. Dann sehen wir zumindest mal den Aufbau. Aber du solltest mit ein bisschen Eigeninitiative mit den bereits gegebenen Antworten selbst was aufbauen können.

TERWI 21. Dez 2021 13:55

AW: JSON einlesen - Hilfe für Anfänger
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hier mal eine Testdatei mit Daten für 3 Stunden EPG.
Musste ich packen, weil zu groß.

Edith:
Lt. div. JSON-Validatoren im Netz sind die Daten gültig.
Ich bekomme auch eine hübsche Baumansicht.
Wenn es denn doch (merkwürdiges) Standard-JSON ist, sollte man das doch auch mit Bordmitteln auswerten können...

@Aviator
Meine Versuche bisher mit Copy6Paste aus dem Netz angepasst funktionieren nicht.

TiGü 21. Dez 2021 14:13

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

Zitat von TERWI (Beitrag 1499460)
Hier mal eine Testdatei mit Daten für 3 Stunden EPG.
Musste ich packen, weil zu groß.

Schau doch mal hier: https://edn.embarcadero.com/article/40882

Dieser 10 Jahre alte JSON-Parser und Viewer kann deine Datei verarbeiten.
Inzwischen haben sich ein paar Unit-Namen geändert, aber sonst passt es.
Vielleicht kannst du dir was abgucken.

Ansonsten hast du mit den Hinweisen hier, unzähligen Beispiel in der DP, auf DocWiki, Stack Overflow oder GitHub eigentlich alles was du brauchst.

Hilfreich ist immer eine Baumansicht auf die Daten, wenn man sich den Parsing-Quelltext mit der Hand zusammenstellt.
Ich empfehle hier Notepad++.
Da kann man sich bequem Plugins dazu laden, die das können (JSON Viewer in Version 1.34 oder JSTool in Version 1.2001.1).

mytbo 21. Dez 2021 15:34

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

Zitat von TERWI (Beitrag 1499452)
Mit Denkanstoß mente ich ein paar hilfreiche Zeilen Code.

Du bist zu unspezifisch. Es fängt damit an, dass du noch nicht geschrieben hast, ob du an Delphi Bordmittel gebunden bist, oder auch andere Libraries einsetzen kannst. Als Startpunkt für mORMot(1) mal dieser Sourcecode. Der gesamte Thread enthält noch mehr Beispiele.

Bis bald...
Thomas

venice2 21. Dez 2021 15:36

AW: JSON einlesen - Hilfe für Anfänger
 
Delphi-Quellcode:
function TZattoo.FormatJSONStr(AString: string): string;
var
  Obj: TJsonObject;
begin

  Obj := Obj.Parse(PWideChar(AString))as TJsonObject;
  result := Obj.ToJSON(False);
end;
Delphi-Quellcode:
procedure TZattoo.GetEPG;
var
  iRun, nRun: Integer;
  doc: TDocVariantData;
  docChannels: PDocVariantData;
  docPrograms: PDocVariantData;

  TimeEnd  : Int64;
  TimeSTart : Int64;
  SendStr  : string;
  Data     : string;
  TxtFile: string;
  dwBytes: DWORD;
  lstream: TFileStream;
  lutf8: UTF8String;
  List : TStringList;
begin

  SetLength(gEPG, 0);
  SetLength(gEpgChannels, 0);

  try
    TimeStart := DateTimeToUnix(IncHour(Now, 0), false);
    TimeEnd := DateTimeToUnix(IncDay(Now, 1), false);
    SendStr := FProvRec.URL +
      cPathEPG +
      FProvRec.PWRHASH +
      '?end=' + inttostr(TimeEnd) +
      '&start=' + inttostr(TimeStart) +
      '&format=json' + '&details=True';

    Log('GetEPG:', 'SendStr: ' + Sendstr);
    data := FHTTP.Get(SendStr);
  except
    Log('GetEPG:', 'Failed !');
    exit;
  end;

  TxtFile := ExtractFilePath(ParamStr(0)) + 'Json\EPG_data.json';
  if FileExists(TxtFile) then
    DeleteFile(TxtFile);

  List := TStringList.Create;
  try
    List.Clear;
    List.Append(Data);
    List.SaveToFile(TxtFile);
  finally
    List.Free;
  end;

  lstream := TFileStream.create(TxtFile, fmOpenReadWrite);
  try
    dwBytes := lstream.size;
    Setlength(lutf8, dwBytes);
    lstream.ReadBuffer(lutf8[1], dwBytes);
    // Format Json
    lutf8 := UTF8String(FormatJSONStr(string(lutf8)));
    lstream.Position := 0;
    lstream.WriteBuffer(lutf8[1], length(lutf8));
  finally
    lstream.free;
  end;

  nRun := 0;

  doc.InitJSONFromFile(TxtFile, JSON_OPTIONS_FAST_EXTENDED);
  if not doc.B['success'] then
    Exit;
  try
  for iRun := 0 to doc.A['channels'].Count - 1 do
  begin
    docChannels := doc.A['channels']._[iRun];
    setLength(gEpgChannels, iRun + 1);
    gEpgChannels[iRun] := docChannels.S['cid'];

    docPrograms := docChannels.A['programs']._[nRun];
    setLength(gEpg, iRun + 1);
    setLength(sStart, iRun + 1);
    setLength(SEnd, iRun + 1);

    Log('GetEPG: Current Channel = ', IntToStr(iRun) + ' ' + gEpgChannels[iRun]);
    // Image Url
    gEpg[iRun].i_url := docPrograms.S['i_url'];
    Log('GetEPG: Image Url = ', gEpg[iRun].i_url);
    // Stop Zeit
    gEpg[iRun].e := docPrograms.I['e'];
    if gEpg[iRun].e <> 0 then
      SEnd[iRun] := UnixToDateTime(gEpg[iRun].e, false)
    else
    SEnd[iRun] := 0;
    Log('GetEPG: Stop Time = ', IntToStr(gEpg[iRun].e));

    // Genre
    gEpg[iRun].g := StringReplace(docPrograms.S['g'], '[', '', [rfReplaceAll]);
    gEpg[iRun].g := StringReplace(gEpg[iRun].g, ']', '', [rfReplaceAll]);
    gEpg[iRun].g := StringReplace(gEpg[iRun].g, '"', '', [rfReplaceAll]);
    if gEpg[iRun].g = '' then
      gEpg[iRun].g := 'N/A';
    Log('GetEPG: Genre = ', gEpg[iRun].g);

    gEpg[iRun].ry_u := docPrograms.I['ry_u'];
    gEpg[iRun].i := docPrograms.S['i'];
    gEpg[iRun].sr_u := docPrograms.I['sr_u'];
    gEpg[iRun].c := docPrograms.S['c'];
    gEpg[iRun].r_e:= docPrograms.B['r_e'];
    gEpg[iRun].e_no:= docPrograms.S['e_no'];
    // Start Zeit
    gEpg[iRun].s:= docPrograms.I['s'];
    if gEpg[iRun].s <> 0 then
      sStart[iRun] := UnixToDateTime(gEpg[iRun].s, false)
    else
    sStart[iRun] := 0;
    Log('GetEPG: Start Time = ', IntToStr(gEpg[iRun].s));

    // Titel
    gEpg[iRun].t:= docPrograms.S['t'];
    Log('GetEPG: Title = ', gEpg[iRun].t);
    gEpg[iRun].ser_e:= docPrograms.B['ser_e'];
    gEpg[iRun].c_ids := docPrograms.I['c_ids'];
    // Unter Titel
    gEpg[iRun].et := docPrograms.S['et'];
    if gEpg[iRun].et = '' then
      gEpg[iRun].et := 'N/A';
    gEpg[iRun].i_t := docPrograms.S['i_t'];
    gEpg[iRun].ts_id := docPrograms.I['ts_id'];
    gEpg[iRun].id := docPrograms.I['id'];
    gEpg[iRun].tms_id := docPrograms.s['tms_id'];
    gEpg[iRun].s_no := docPrograms.I['s_no'];
  end;
  except
    on e: exception do
      Log('GetEPG:', 'Failed! with Message ' + e.Message);
  end;
end;
Wie @mytbo schon sagt verwende dazu mORMot
Ich selber mache mit Zattoo nichts mehr es nervt wenn alle paar Tage die API wieder geändert wird.
Zudem gibt es diese ja auch nicht wirklich.

TERWI 21. Dez 2021 15:51

AW: JSON einlesen - Hilfe für Anfänger
 
wieder gelöscht...

TERWI 21. Dez 2021 16:10

AW: JSON einlesen - Hilfe für Anfänger
 
Wie ich schon sagte: ... ja es gibt reichlich ....
Aber ich sehe irgendwie den Wald vor lauter JSON nicht mehr.
Ich bekomme eben noch ein JSON-Objekt aus dem String hin.
Aber wie "extrahiere" ich daraus das Array mit einer Loop ?
Und wie lese ich die Namen der Einträge (ohne Wert ?) ?
Ein kleiner 5-Zeiler oder so wäre hilfreicher als Verweise auf Libraries und Ableitungen daraus.
Oft hilft ein funktionierendes Beispiel mehr als stundenlang rumlesen (und nicht verstehen).

Ob mit Bordmitteln oder extra Lib ist eigentlich egal - einfach sollte es sein.
Beispile zu den Libs hin und/oder her: Wenn man JSON als solches nicht wirklich versteht... (weil noch nie bedarf gehabt, das verstehen zu müssen)
Siehe erster Absatz.

@venice2
Danke dir für deinen Source zum Aulesen von ZATTOO-V2.
Funzt leider nicht mehr, weil Aufbau der Daten anders.
So was in der Art hatte ich mir auch schon selbst gebastelt.

venice2 21. Dez 2021 16:16

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

Danke dir für deinen Source zum Aulesen von ZATTOO-V2.
Funzt leider nicht mehr, weil Aufbau der Daten anders.
So was in der Art hatte ich mir auch schon selbst gebastelt.
Der Source liest nicht Zattoo v2 ein sondern verarbeitet die Json Datei TxtFile EPG_data.json
Das ist was du wolltest. ;)

Mehr wirst du hier wohl nicht bekommen.

TERWI 21. Dez 2021 16:49

AW: JSON einlesen - Hilfe für Anfänger
 
Grins. Kann es sein, das der Ursprung von mir stammt ?
Liest sich im großen und ganzen wie meine Zat-Lib ... 8-)
Mein Proggie läufz ganz nett - nur leider noch ohne vollständige EPG-Übersicht.

Mit Zatto-V2 meine ich auch die Datenversion, die man von Zattoo (hier EWE-Tel) lädt.
Mittlerweile ist es V3 und das geht eben anders. Sie 1. Posting / mein Datenanhang ein paar Post weiter vorne.

Ja, ich habs gesehen das du da eine Datei einliest - ich gebe den Daten-String direkt von HTTP.Get

Ich möchte ja auch keine spezielle Hilfe beim Auseinanderbröseln von Zattoo-Daten, sondern lediglich diesen JSON String (oder auch den der Channels, EPG-Details, ....)

venice2 21. Dez 2021 17:05

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

Grins. Kann es sein, das der Ursprung von mir stammt ?
Klar stammt der von dir hast ihn mir doch geschickt.

Destotrotz arbeite ich mit dem parsen der *.json und nicht wie du alles von Hand -> Auseinandergebröselt. Pos, PosEx und Konsorte.
In meiner Pas befindet sich minimalistischer Code von dir da ich hier mit Json arbeite und nicht so wie du mit wie schon gesagt PosNext, Pos, PosEx.

Zitat:

Ich möchte ja auch keine spezielle Hilfe beim Auseinanderbröseln von Zattoo-Daten, sondern lediglich diesen JSON String (oder auch den der Channels, EPG-Details, ....)
Ach...
Schau dir doch den Source an da wird nix Auseinandergebröselt sondern der Json string geparst.
Wenn du das nicht erkennst sorry dann kann ich dir da auch nicht weiter helfen.

Viel spaß noch damit.
Bin raus da mich Zattoo nicht wirklich noch irgendwie interessiert.

Aviator 21. Dez 2021 18:02

AW: JSON einlesen - Hilfe für Anfänger
 
Also ich weiß nicht was man da sonst noch zu schreiben soll. Ich habe dir doch auch schon ein Beispiel gemacht. Oder hast du das etwa komplett überlesen?

Uwe Raabe 21. Dez 2021 18:33

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

Zitat von Aviator (Beitrag 1499502)
Also ich weiß nicht was man da sonst noch zu schreiben soll. Ich habe dir doch auch schon ein Beispiel gemacht.

Das compiliert aber so nicht. Wenn man sich damit dann nicht auskennt, wirft man es halt schnell gleich wieder weg.

Bis auf den Dateinamen für die JSON-Datei sollte es so gehen:
Delphi-Quellcode:
program TestJSON1;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.IOUtils,
  REST.Json.Types,
  REST.Json;

type
  TBlock = class
  private
    FListe1: TArray<string>;
    FListe4: TArray<Integer>;
    FInt_1: Integer;
    FTxt_1: string;
    FBool_1: Boolean;
    FReal_1: Real;
  public
    property Liste1: TArray<string> read FListe1;
    property Liste4: TArray<Integer> read FListe4;
    property Int_1: Integer read FInt_1;
    property Txt_1: string read FTxt_1;
    property Bool_1: Boolean read FBool_1;
    property Real_1: Real read FReal_1;
  end;

  TContainer = class
  private
    { ja, wir könnten hier auch FBlöcke schreiben, aber das sind so Dinge, die bringe ich einfach nicht übers Herz. }
    [JSONName('Blöcke')] // needs REST.Json.Types
    FBloecke: TArray<TBlock>;
  public
    destructor Destroy; override;
    property Bloecke: TArray<TBlock> read FBloecke;
  end;

destructor TContainer.Destroy;
var
  item: TBlock;
begin
  for item in FBloecke do
    item.Free;

  inherited;
end;

procedure ParseJson();
var
  block: TBlock;
  FileContent: String;
  Container: TContainer;
begin
  FileContent := TFile.ReadAllText('<path\to\file.json>');
  Container := TJson.JsonToObject<TContainer>(FileContent);
  try
    for block in Container.Bloecke do
      Writeln(block.Txt_1);
  finally
    Container.Free;
  end;
end;

begin
  try
    ParseJson;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

end.

Aviator 21. Dez 2021 18:40

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

Zitat von Uwe Raabe (Beitrag 1499505)
Das compiliert aber so nicht. Wenn man sich damit dann nicht auskennt, wirft man es halt schnell gleich wieder weg.

Naja ich bin mal davon ausgegangen, dass er die Klasse und die Prozedur selbst in eine Unit an die richtige Stelle schreiben kann. 😉

Was ich jetzt so beim Schreiben im Editor nicht mehr im Kopf hatte war, dass man wohl eine weitere Klasse mit einem Feld bauen muss in dass das Objekt dann konvertiert wird. 😅

Aber mit den vielen Beispielen hätte er das sicherlich hinbekommen können. 🙂

TERWI 21. Dez 2021 18:44

AW: JSON einlesen - Hilfe für Anfänger
 
@Aviator
Nein das habe ich nicht überlesen, sondern gut eine 1/2 Stunde drüber gegrübelt, wie das funktiert. Ohne Ergebnis.
Dein JSON ist auch leicht anders als meiner - siehe auch mein Anhang in #9 mit dem reellen JSON.
Ich denke der Unterschied und die Art das zu parsen ist hier sehr wichtig ?!

Problem bzw. wichtig ist:
- ich will alle Einträge (Bloack_A -> _Z) durchlaufen und deren Namen lesen
- Nicht alle (Array- ?) Eintäge sind dabei wichtig und können übersprungen werden
- Auch sind nicht alle Werte (Pairs, Arrays ?!) datunter notwendig
- Teilweise brauche ich jeweils auch unterschiedliche "Sätze" (z.B. A] Liste_1 und Int_1, B] Liste_2 und Int_2)

Ich müsste das also sozusagen schon zeilenweise in Loop's "durchkauen".

@Uwe
.... hat er aber eben nicht. :?

TERWI 21. Dez 2021 18:58

AW: JSON einlesen - Hilfe für Anfänger
 
Ich versuche noch mal, das reelle JSON in Post #9 zu beschreiben und wie ich es bisher "zu Fuß" in vorherigen Datenversion gelesen habe:

Das 'äußere' Objekt namens "channels" interessiert mich nicht.
Eine äußere Schleife liest dann alle TV-Sendernamen durch (bis ca. 150)
Die brauche ich nicht alle, nur bestimmte.

Unterhalb der jeweiligen Sendernamen liegen dann sozusagen Listen aus Records mit Daten, welche die jeweilige Sendung beschreiben. (Name, Start-/Sop-Zeit, ID's mit Verweisen auf Logos und EPG-Detail-Daten, etc.)
Auch die brauche ich nicht immer alle.

In dem Beispiel mit TBlocks müsste ich dann z.B. wissen, wie der Block heisst.

Da Zatto nicht maximale Anzahl von Daten (Sendungen für mehrere Tage) hergibt, muss man "brückchenweise" (am besten in 6-Atunden Abschnitten) wiederholte die Daten ziehen.
Daraus puzzle ich mir dann meinen EPG für ca. 2 Wochen zusammen und / oder mache Updates bei Änderungen.

So viel zum Sinn und Zweck der Veranstaltung.

Delphi.Narium 21. Dez 2021 20:28

AW: JSON einlesen - Hilfe für Anfänger
 
Irgendwie verstehe ich was Du meinst, ich verstehe jedoch nicht, wo konkret das Problem liegt.

Da ich nur ein olles Delphi 7 habe, nix JSon und passende Klassen schon mitgeliefert, hab' ich mir mal für ein konkretes "JSon-Problem" folgende Hilfroutine geschrieben:
Delphi-Quellcode:
procedure MyJSonSplit(sl : TStringList);
var
  input : TMemoryStream;
  output : TMemoryStream;
  ch    : Char;
  ch2    : Char;
  cr    : Char;
  lf    : Char;
  i     : Integer;
begin
  input := TMemoryStream.Create;
  output := TMemoryStream.Create;
  for i := 0 to sl.Count - 1 do sl[i] := AnsiReplaceText(sl[i],'&quot;','"');
  sl.SaveToStream(input);
  input.Position := 0;
  if input.Size > 0 then begin
    cr := #13;
    lf := #10;
    if input.Read(ch,1) > 0 then begin
      repeat
        case ch of
          '{','[',']','}' : begin
                              output.Write(cr,1);
                              output.Write(lf,1);
                              output.Write(ch,1);
                              output.Write(cr,1);
                              output.Write(lf,1);
                            end;
          ','            : begin
                              input.Read(ch2,1);
                              case ch2 of
                                '"' : begin
                                        output.Write(cr,1); // eventuell ersten 3 Zeilen weglassen?
                                        output.Write(lf,1);
                                        output.Write(ch,1);
                                        output.Write(cr,1);
                                        output.Write(lf,1);
                                        output.Write(ch2,1);
                                      end;
                              else
                                output.Write(ch,1);
                                input.Position := input.Position - 1;
                              end;
                            end;
        else
          output.Write(ch,1);
        end;
        if input.Position mod 1000 = 0 then Application.ProcessMessages;
      until input.Read(ch,1) = 0;
    end;
    output.Position := 0;
    sl.LoadFromStream(output);
  end;
  output.Free;
  input.Free;
end;
Stringliste rein, Stringliste raus.

Damit sind alle Daten zeilenweise aufgebröselt.

Wenn man nun diese Struktur kennt, kann man das auch entsprechend in 'ner For-Schleife auswerten, Bereiche überlesen, ...

Eventuell wäre das ja ein Ansatz für Dich.

Und nein: Eine professionelle Lösung ist das nicht, für's Hobbyprogrammieren aber ausreichend ;-)

jobo 22. Dez 2021 07:24

AW: JSON einlesen - Hilfe für Anfänger
 
Der Ansatz, JSON 'per Hand' zu zerlegen, scheint mir nicht sinnvoll oder viel zu mühevoll.
Ich habe hier ein Beispiel für Postgres SQL gemacht.

https://dbfiddle.uk/?rdbms=postgres_...04c5eefd41b168

Dort werden ein paar Beispieldaten in eine Tabelle eingefügt und zerlegt. Es sind anfangs ein paar Statements aufgeführt, die die grobe Zerlegung zeigen, am Ende dann ein paar "Anwendungsfälle".

Dort im Browser ist es etwas lahm, auf einer normalen DB geht es zumindest mit den Beispieldaten aber flott.

TiGü 22. Dez 2021 09:54

AW: JSON einlesen - Hilfe für Anfänger
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ausgehend von Uwes Konsolenprogramm und den richtigen Daten aus #9 aus dem Archiv schnell was zusammengezimmert.
Ganzes Projekt mit Beispieldaten im Anhang als ZIP-Archiv.

Mir ist bewusst, dass in diesem Ansatz die Sendernamen fehlen, da es sich hier um eine 1:1-Umsetzung der Json-Daten handelt.
Die Transformation in das gewünschte Datenformat steht noch aus, da uns dies unbekannt ist TERWI.
Kann aber ggf. durch RTTI geholt werden (https://stackoverflow.com/questions/...ss-at-run-time).
Dies überbleibt dem geneigten Leser als Fingerübung und Hausaufgabe.

Delphi-Quellcode:
program JsonZattoo;

{$APPTYPE CONSOLE}


uses
    System.SysUtils,
    System.IOUtils,
    REST.Json,
    ZattooTypes in 'ZattooTypes.pas';

procedure ParseJson();
var
    Root: TRoot;
    LChannels: TChannels;
    LChannelInfo: TChannelInfo;
    LEPGInfo: TEPGInfo;
    FileContent: string;
    Txt: string;
begin
    FileContent := TFile.ReadAllText('EPG_GUIDE.json');
    Root := TJson.JsonToObject<TRoot>(FileContent);
    try
        LChannels := Root.ChannelContainer.Channels;
        for LChannelInfo in LChannels do
        begin
            for LEPGInfo in LChannelInfo do
            begin
                Writeln('ID: ', LEPGInfo.id);
                Writeln('Title: ', LEPGInfo.title);

                if not LEPGInfo.episode_title.IsEmpty then
                begin
                    Writeln('Episode: ', LEPGInfo.episode_title);
                end;

                if Length(LEPGInfo.genre) > 0 then
                begin
                    Writeln(' Genre(s):');
                    for Txt in LEPGInfo.genre do
                    begin
                        Writeln('   ' + Txt);
                    end;
                end;
                Writeln('--------------------');
            end;
        end;
    finally
        Root.Free;
    end;
end;

begin
    ReportMemoryLeaksOnShutdown := True;
    try
        ParseJson;
    except
        on E: Exception do
                Writeln(E.ClassName, ': ', E.Message);
    end;
    Readln

end.
Delphi-Quellcode:
unit ZattooTypes;

interface

uses
    REST.Json.Types;

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 write Fid;
        property title: string read FTitle write FTitle;
        property episode_title: string read FEpisode_title write FEpisode_title;
        property genre: TArray<string> read FGenre write FGenre;
    end;

    TChannelInfo = TArray<TEPGInfo>;
    TChannels = TArray<TChannelInfo>;

    TChannelContainer = class
    private
        Fsixx_deutschland: TChannelInfo;
        Fard: TChannelInfo;
        Fdeutschesmusikfernsehen: TChannelInfo;
        F3sat: TChannelInfo;
        function GetChannels: TChannels;
    public
        destructor Destroy; override;

        property Channels: TChannels read GetChannels;

        { // optional, wenn du nur eine Handvoll Sender brauchst und den direkten Zugriff willst, ansonsten per Channels-Property
          property deutschesmusikfernsehen: TChannelInfo read Fdeutschesmusikfernsehen write Fdeutschesmusikfernsehen;
          property ard: TChannelInfo read Fard write Fard;
          property _3sat: TChannelInfo read F3sat write F3sat;
          property sixx_deutschland: TChannelInfo read Fsixx_deutschland write Fsixx_deutschland;
        }
    end;

    TRoot = class
    private
        [JSONName('channels')]
        FChannels: TChannelContainer;
    public
        destructor Destroy; override;
        property ChannelContainer: TChannelContainer read FChannels;
    end;

implementation

destructor TRoot.Destroy;
begin
    FChannels.Free;

    inherited;
end;

destructor TChannelContainer.Destroy;
var
    ChannelInfo: TChannelInfo;
    EPGInfo: TEPGInfo;
begin
    for ChannelInfo in Self.Channels do
    begin
        for EPGInfo in ChannelInfo do
        begin
            EPGInfo.Free;
        end;
    end;
    inherited;
end;

function TChannelContainer.GetChannels: TChannels;
begin
    Result := [Fsixx_deutschland, Fard, Fdeutschesmusikfernsehen, F3sat];
end;

end.
Beispielausgabe:
Code:
ID: 238874757
Title: Charmed - Zauberhafte Hexen
Episode: Vergissmeinnicht
  Genre(s):
    Drama
    Fantasy
    Mystery
--------------------
ID: 239947163
Title: Charmed - Zauberhafte Hexen
Episode: Die Ohnmacht der Drei
  Genre(s):
    Drama
    Fantasy
    Mystery
--------------------
ID: 238874759
Title: Charmed - Zauberhafte Hexen
Episode: Tödliche Liebe
  Genre(s):
    Drama
    Fantasy
    Mystery
--------------------
ID: 238874760
Title: Charmed - Zauberhafte Hexen
Episode: Opfer der Sehnsucht
  Genre(s):
    Drama
    Fantasy
    Mystery
--------------------
ID: 238906082
Title: ZDF-Mittagsmagazin
  Genre(s):
    News
    Magazine
    Society
--------------------
ID: 238906083
Title: Tagesschau
Episode: vom 21.12.2021, 14:00 Uhr
  Genre(s):
    News
    Politics
    Weather
--------------------
ID: 238906084
Title: Rote Rosen
Episode: Folge 3475
  Genre(s):
    Drama
    Soap
--------------------
ID: 238906085
Title: Tagesschau
Episode: vom 21.12.2021, 15:00 Uhr
  Genre(s):
    News
    Politics
    Weather
--------------------
ID: 238906086
Title: Sturm der Liebe
Episode: Folge 3742
  Genre(s):
    Romance & Love
    Soap
--------------------
ID: 238906087
Title: Tagesschau
Episode: vom 21.12.2021, 16:00 Uhr
  Genre(s):
    News
    Politics
    Weather
--------------------
ID: 238906088
Title: Verrückt nach Meer
Episode: Abenteuer am Öresund
  Genre(s):
    Travel
--------------------
ID: 240036356
Title: Das große Wunschkonzert
Episode: Kastelruther Spatzen
  Genre(s):
    Music
--------------------
ID: 240036357
Title: Musiktipps
  Genre(s):
    Music
--------------------
ID: 240036358
Title: Teleshopping
  Genre(s):
    Talk Show
    Home Shopping
--------------------
ID: 240036359
Title: Bianca: Ihre schönsten Lieder
  Genre(s):
    Music
--------------------
ID: 240036360
Title: Musiktipps
  Genre(s):
    Music
--------------------
ID: 240036361
Title: Teleshopping
  Genre(s):
    Talk Show
    Home Shopping
--------------------
ID: 238905942
Title: Von Sibirien nach Japan
Episode: Wildes Kamtschatka
--------------------
ID: 238905944
Title: Von Sibirien nach Japan
Episode: Im Banne der Inseln
  Genre(s):
    Nature
--------------------
ID: 238879507
Title: Spitzbergen - Leben in Europas Kühlschrank
  Genre(s):
    Nature
--------------------
ID: 238879508
Title: Zimtstern und Halbmond
  Genre(s):
    Romance & Love
    Travel
--------------------

TERWI 22. Dez 2021 11:51

AW: JSON einlesen - Hilfe für Anfänger
 
Wow, so viel Code ! Danke euch allen. Aber wie immer das ABER:

@Delphi.Narium
So was in der Art hab ich hier schon für die Vorgänger-Datenversion.
Das wollte ich eigentlich etwas einfacher und übersichtlicher haben.

@jobo
Hm, auch noch SQL/Datenbank mit ins Boot ist eigentlich weit am Ziel vorbei...
Und ja: JSON (einfach) per Hand zu zerlegen ist die Intention. Siehe weiter unten.

@TiGü
Yepp, das funzt ! Allerdings müsste ich da sicher erst mal einen extended Durchblickerkurs machen, um zu verstehen wie das funktioniert und wie man das dann ggf. noch erweitert/anpasst.
Sehe ich das richtig, das die auserwählten Sender statisch im TChannelContainer vorgegeben sind ?
Falls ja: Das sollte vom User änderbar sein (hier mit Senderlisten-Editor)

Ich hab gesten Nacht noch rumgebastelt und dabei ist folgendes herausgekommen
Delphi-Quellcode:
// https://www.generacodice.com/en/articolo/4308375/how-to-parse-nested-json-object-in-delphi-xe2
procedure TForm1.ParseJson(data : string);
var
  JsonObj  : TJSONObject;
  JsonArray : TJSONArray;
  JsonValue : TJSonValue;
  chl      : TJSonValue;
  JsonPair : TJSONPair;
  i, ii, n : integer;
  LItem    : TJSONValue;
begin
  JsonObj   := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(data),0) as TJSONObject;
  try
    JsonValue := JsonObj.Get('channels').JsonValue;
    for i := 0 to TJSONArray(JsonValue).Size - 1 do
    begin
      chl := TJSONArray(JsonValue).Get(i);
      JsonPair := TJSONPair(chl);
      // Listet den Sender-Namen
      Memo.Lines.Add(Format('Channel: %s',[JsonPair.JsonString.Value]));
      n := 1;
      for LItem in TJSONArray(JsonPair.JsonValue) do
      begin
        // Listet entsprechend Anzahl der Programme je Sender
        // .... den 'Inhalt' zwischen [ und ]
        Memo.Lines.Add('- Programm: ' + inttostr(n));
        inc(n);
        // ... wie bekomme ich hier Zugriff auf die ProgrammDaten ?
        // also den 'Inhalt' zwischen { und }

      end;
    end;
  finally
     JsonObj.Free;
  end;
end;
Das ist mit Bordmitteln kurz, einfach, simpel und funzt so wie ich mir das denke.
... fehlt nur noch die "Kleinigkeit" siehe Text. Da fehlt mir noch das Verständnis bei JSON.
Vielleicht kann da jemand aushelfen und den letzen Denkanstoß geben ?!

TERWI 22. Dez 2021 12:37

AW: JSON einlesen - Hilfe für Anfänger
 
HA - ich habs raus !
Delphi-Quellcode:
// https://www.generacodice.com/en/articolo/4308375/how-to-parse-nested-json-object-in-delphi-xe2
procedure TForm1.ParseJson(data : string);
var
  JsonObj  : TJSONObject;
  JsonValue : TJSonValue;
  chl      : TJSonValue;
  dat      : TJSonValue;
  JsonPair : TJSONPair;
  DataPair : TJSONPair;
  i, ii, n : integer;
  LItem    : TJSONValue;
begin
  Memo.Lines.BeginUpdate;
  JsonObj   := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(data),0) as TJSONObject;
  try
    JsonValue := JsonObj.Get('channels').JsonValue;
    for i :=0 to TJSONArray(JsonValue).Size - 1 do
    begin
      chl := TJSONArray(JsonValue).Get(i);
      JsonPair := TJSONPair(chl);
      Memo.Lines.Add(Format('Channel: %s',[JsonPair.JsonString.Value]));
      n := 1;
      for LItem in TJSONArray(JsonPair.JsonValue) do
      begin
        Memo.Lines.Add('--  Programm: ' + inttostr(n));
        inc(n);
        for ii := 0 to TJSONArray(LItem).Size - 1 do
        begin
          dat := TJSONArray(LItem).Get(ii);
          DataPair := TJSONPair(dat);
          Memo.Lines.Add(Format('   ---- %s : %s',[DataPair.JsonString.Value, DataPair.JsonValue.Value]));
        end;
      end;
    end;
  finally
     JsonObj.Free;
  end;
  Memo.Lines.EndUpdate;
end;
Das war zwar mit Vollgas Versuch und Irrtum, aber lüppt.

jobo 22. Dez 2021 12:38

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

Zitat von TERWI (Beitrag 1499553)

Hm, auch noch SQL/Datenbank mit ins Boot ist eigentlich weit am Ziel vorbei...
Und ja: JSON (einfach) per Hand zu zerlegen ist die Intention. Siehe weiter unten.

Naja, es sind halt Daten, die Du bearbeitest, durchsuchst, auf den Kopf stellst.
Und es ist wirklich einfach. Wenn man keine Umbenennung haben will, reichen ca 3 Zeilen SQL. Zugegeben, auf einer Apple Watch läuft es nicht.

Mir war eigentlich auch wichtig zu zeigen, dass man da nicht Buchstabe für Buchstabe dran geht. (Auch ohne DB)
Aber man kann es bestimmt auch in SQLite machen, das hat auch ganz gute JSON Funktionen und kleineren Fußabdruck.

Uwe Raabe 22. Dez 2021 13:03

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

Zitat von TiGü (Beitrag 1499541)
Ausgehend von Uwes Konsolenprogramm und den richtigen Daten aus #9 aus dem Archiv schnell was zusammengezimmert.

Meiner Meinung nach scheidet der Ansatz wegen der Verwendung der Sendernamen als Schlüssel eigentlich aus. Man könnte vermutlich einen Interceptor schreiben, der das sinnvoll auflöst, aber das wäre zu viel Aufwand.

TiGü 22. Dez 2021 13:29

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

Zitat von Uwe Raabe (Beitrag 1499568)
Zitat:

Zitat von TiGü (Beitrag 1499541)
Ausgehend von Uwes Konsolenprogramm und den richtigen Daten aus #9 aus dem Archiv schnell was zusammengezimmert.

Meiner Meinung nach scheidet der Ansatz wegen der Verwendung der Sendernamen als Schlüssel eigentlich aus. Man könnte vermutlich einen Interceptor schreiben, der das sinnvoll auflöst, aber das wäre zu viel Aufwand.

Ja, daher hier nochmal die Version zu Fuß (sollte dadurch auch schneller sein?):

Delphi-Quellcode:
procedure ParseJsonTERWI;
var
    JsonRoot, JsonChannels, JsonEPGInfo: TJSONObject;
    JsonEPGInfos, JsonEPGDetailInfoArray: TJSONArray;
    JsonValue, JsonValue2, JsonSingleChannel: TJSonValue;
    JsonPair, JsonPair2: TJSONPair;
    I, N, J: integer;
    FileContent, ProgramName: string;
begin
    FileContent := TFile.ReadAllText('EPG_GUIDE.json');
    JsonRoot := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(FileContent), 0) as TJSONObject;
    try
        JsonValue := JsonRoot.Get('channels').JsonValue;
        if JsonValue is TJSONObject then
        begin
            JsonChannels := TJSONObject(JsonValue);
            Writeln('Es gibt soviele Kanäle: ', JsonChannels.Count);
            Writeln('Enter-Taste drücken...');
            Readln;

            Writeln(sLineBreak + 'Auflistung der Kanäle...');
            N := 1;
            for JsonPair in JsonChannels do
            begin
                ProgramName := JsonPair.JsonString.Value;
                Writeln(N.ToString + '. ', ProgramName);
                Inc(N);
            end;

            Writeln(sLineBreak + 'EPG-Informationen der ersten 3 Sender...');
            Writeln('Enter-Taste drücken...');
            Readln;

            N := 1;
            for JsonPair in JsonChannels do
            begin
                if JsonPair.JsonValue is TJSONArray then
                begin
                    JsonEPGInfos := TJSONArray(JsonPair.JsonValue);
                    Writeln(sLineBreak + N.ToString + '. ', ProgramName + ' hat soviele EPG-Informationen: ', JsonEPGInfos.Count);
                    for I := 0 to JsonEPGInfos.Count - 1 do
                    begin
                        JsonValue2 := JsonEPGInfos.Items[I];
                        if JsonValue2 is TJSONObject then
                        begin
                            JsonEPGInfo := TJsonObject(JsonValue2);
                            Writeln('...die EPG-Information hat soviele Einträge: ', JsonEPGInfo.Count);
                            for JsonPair2 in JsonEPGInfo do
                            begin
                                // das hier wäre die Stelle wo du aus JsonPair2.JsonValue dir die nötigen Informationen
                                // für deine Klassenstruktur/Liste/EPG-Guide zusammenpuzzeln musst.
                                Writeln('......', JsonPair2.JsonString.Value, ': ', JsonPair2.JsonValue.ToString);

                                // Wenn JsonPair2.JsonValue ein Array ist (z.B. Genres), dann hier nochmal genauer reingucken:
                                if JsonPair2.JsonValue is TJSONArray then
                                begin
                                    JsonEPGDetailInfoArray := TJSONArray(JsonPair2.JsonValue);

                                    for J := 0 to JsonEPGDetailInfoArray.Count - 1 do
                                    begin
                                        Writeln('.........', JsonEPGDetailInfoArray.Items[J].Value);
                                    end;
                                end;
                            end;
                        end;
                    end;
                end;

                Inc(N);
                if N = 3 then
                begin
                    Writeln(sLineBreak + 'Damit es nicht zuviel wird, brechen wir hier nach 3 Sendern ab!');
                    Break;
                end;
            end;

            // Beispiel für einzelnen Sender -> hier dann wie oben auswerten!
            JsonSingleChannel := JsonChannels.GetValue('ard');
            if JsonSingleChannel is TJSONArray then
            begin
                JsonEPGInfos := TJSONArray(JsonSingleChannel);
                // usw. usf.
            end;
        end;

        Writeln('Enter-Taste drücken...');
        Readln;
    finally
        JsonRoot.Free;
    end;
end;

TERWI 22. Dez 2021 20:40

AW: JSON einlesen - Hilfe für Anfänger
 
@TiGü
...irgendwie ist das doch das gleiche wie in meinem Post #27, nur etwas anders mit mehr Info.
Was ist schneller als was ? Uwe's Version oder die von jobo oder TiGü... 'per Json-Hand filetiert' ...
Geschwindigkeit ist bei mir bei den eher kleinen Datenmengen (< 1MByte) nicht so die Wichtgkeit.
Ich lege Wert drauf, dass ich das verstanden habe was ich/andere da geproggt haben und für mich auch später bei Bedarf modifizieren kann.

Uwe Raabe 23. Dez 2021 11:19

AW: JSON einlesen - Hilfe für Anfänger
 
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.

TERWI 24. Dez 2021 15:17

AW: JSON einlesen - Hilfe für Anfänger
 
Danke dir, Uwe. Das werde ich zeitnah mal testen.

Da fehlen logo noch etliche Daten in TEPGInfo.
Die Klasse erweitern ist sicher nicht das Problem, aber ....

Die Daten (erweiterte EPG-Texte/Beschreibungen) kommen aus einer 2ten Datei separat je Sender zu laden.
Funzt das im Prinzip genauso ?
Dito die Logo's zum Sender und 'Live-Pics" vom Programm, welche sich 'im Zeitraffer' (alle 15 Sekunden ?!) ändern und ggf. nachzuladen wäre (nur prinzipiell...)

Uwe Raabe 24. Dez 2021 15:58

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

Zitat von TERWI (Beitrag 1499679)
Die Daten (erweiterte EPG-Texte/Beschreibungen) kommen aus einer 2ten Datei separat je Sender zu laden.
Funzt das im Prinzip genauso ?
Dito die Logo's zum Sender und 'Live-Pics" vom Programm, welche sich 'im Zeitraffer' (alle 15 Sekunden ?!) ändern und ggf. nachzuladen wäre (nur prinzipiell...)

Kann ich so nicht beurteilen. Dazu müsste man diese Dateien mal sehen.

TERWI 7. Jan 2022 21:43

AW: JSON einlesen - Hilfe für Anfänger
 
@TiGü, Uwe

Ich hab mir das hier zum Testen mal zusammengelaubt, nur um den Sendungsnamen zu lesen:
Delphi-Quellcode:
    jsonObj := jsonobj.Values['channels'] as TJSONObject;
    for jsonpair in jsonObj do begin
      ZATEPG.Log('UPDEPG', Format('Channel: %s',[jsonpair.JsonString.Value]));
      for item in (jsonpair.JsonValue as TJSONArray) do
      begin
        s := (item as TJSONObject).GetValue('t').Value; // <- FEHLER ???
        ZATEPG.Log('UPDEPG', ' - ' + s);

      end;
    end;
Das kompiliert, funzt 1A und ist recht fix .... aber:
Delphi meckert rum:
-> Undeklarierter Bezeichner 'Value' in Zeile ....

Warum ?


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:44 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz