![]() |
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:
Wie lese ich das gescheit & einfach in Schleife mit TJSONObject, TJSONArray, TJSONValue, .... aus ?
{"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 ... } ], } } |
AW: JSON einlesen - Hilfe für Anfänger
Google mal nach "delphi json reader example"
|
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ß. |
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. |
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:
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.
Blöcke
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:
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
{
"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 ] } ] }
Delphi-Quellcode:
"ansprechen" soll obwohl sie
Foo
Delphi-Quellcode:
heißen.
Bar
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; |
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
![]() 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 ![]() ![]() ![]() Bis bald... Thomas |
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 ?! |
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
|
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. |
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
![]() 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). |
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
![]() Bis bald... Thomas |
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:
Wie @mytbo schon sagt verwende dazu mORMot
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; 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. |
AW: JSON einlesen - Hilfe für Anfänger
wieder gelöscht...
|
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. |
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
Das ist was du wolltest. ;) Mehr wirst du hier wohl nicht bekommen. |
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, ....) |
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
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:
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. |
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?
|
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
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. |
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
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. 🙂 |
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. :? |
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. |
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:
Stringliste rein, Stringliste raus.
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],'"','"'); 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; 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 ;-) |
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. ![]() 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. |
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 ( ![]() 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:
Beispielausgabe:
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.
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 -------------------- |
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:
Das ist mit Bordmitteln kurz, einfach, simpel und funzt so wie ich mir das denke.
// 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; ... 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 ?! |
AW: JSON einlesen - Hilfe für Anfänger
HA - ich habs raus !
Delphi-Quellcode:
Das war zwar mit Vollgas Versuch und Irrtum, aber lüppt.
// 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; |
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
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. |
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
|
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
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; |
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. |
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:
Aufgerufen wird das dann so:
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.
Delphi-Quellcode:
Sollten weitere EPG-Felder benötigt werden, reicht es diese in der Klasse TEPGInfo entsprechend zu ergänzen.
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. |
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...) |
AW: JSON einlesen - Hilfe für Anfänger
Zitat:
|
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:
Das kompiliert, funzt 1A und ist recht fix .... aber:
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; 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