Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Json parsen problem (https://www.delphipraxis.net/206367-json-parsen-problem.html)

venice2 14. Dez 2020 23:34


Json parsen problem
 
Habe ein kleines Problem beim parsen meiner Json.

Code:
   "channels": [
      {
         "programs": [
            {
               "i_url": "http://images.zattic.com/cms/3f240530cf1a3bad8f63/format_480x360.jpg",
               "e": 1607986200,
               "g": [],
Auf channels kann ich zugreifen aber auf programs nicht.

Delphi-Quellcode:
function TZATJSON.GetJSONByNameOrIndex(const AData: Variant): TZATJSON;
begin
  case VarType(AData) and VarTypeMask of
    varString, varUString, varWord, varLongWord:
      if not FItems.TryGetValue(AData, Result) then //>>> Result ist nil weil ich nicht die korrekte Reihenfolge einhalte beim parsen. Nur wie? Wenn ich nicht an programs dran komme.
        raise EJSONUnknownFieldOrIndex.Create(format('Unknown field: %s', [AData]))
      else
        exit;
Delphi-Quellcode:
procedure TEpgDataList.FillList(aZatJson: TZATJSON);
var
  lZatJson: TZATJSON;
begin

  if assigned(aZatJson) then
  begin
    lZatJson := aZatJson.JSONByNameOrIndex['channels'];

    if assigned(lZatJson) and lZatJson.IsList then
    begin
      if lZatJson.ListItems.Count > 0 then
        addEpgData(lZatJson.ListItems[0]);
    end;
  end;
end;
Delphi-Quellcode:
procedure TEpgDataList.addEpgData(aZatJson: TZATJSON);
var
  entry: TEpgData;
  Epgloop: tEpgEntries;
  ltemp: TZATJSON;
  lEntrienames: tEpgEntryNames;
begin

  if assigned(aZatJson) then
  begin
    // Set up temporary Data
    entry := System.default(TEpgData);

    lEntrienames := EntryEpgNames;

    begin
      for Epgloop := Low(tEpgEntries) to High(tEpgEntries) do
        // Check if there is a Name.......
        if lEntrienames[Epgloop] <> '' then
        begin
          ltemp := aZatJson[lEntrienames[Epgloop]]; //>>>>>>
>> hier kracht es

wenn ich versuche 'i_url' anzusprechen ohne vorher programs initialisiert zu haben
programs will nicht nach channels und 'i_url' kann ich nicht aufrufen da es ein unterknoten von programs ist.
rufe ich programs auf ohne channels dann kracht es auch.
Also so!
Delphi-Quellcode:
lZatJson := aZatJson.JSONByNameOrIndex['programs'];

wo ist mein Fehler?

Wie kann ich also programs ansprechen damit es gefunden wird.

EDIT:
addiere ich jetzt programs zu den items die in die liste addiert werden sollen dann wird es korrekt gelesen.
Aber die untergeordneten Items werden wieder nicht erkannt.
Delphi-Quellcode:
  EntryEpgNames: TEpgEntryNames = ('programs', 'i_url', 'e', 'g', 'ry_u', 'i', 'sr_u', 'c',
    'r_e', 'rg_u', 'e_no', 's', 't', 'ser_e', 'c_ids', 'success');
grrr....

DeddyH 15. Dez 2020 06:49

AW: Json parsen problem
 
channels ist ein JSON-Array bestehend aus JSON-Objekten. So ein JSON-Objekt verfügt wiederum um ein JSON-Array namens programs, das dann wieder aus JSON-Objekten mit den Eigenschaften i_url (String), e (String) und g (JSON-Array) besteht. Ich kenne die verwendete JSON-Klasse leider nicht, daher kann ich auch nicht sagen, wie man damit die vorhandene Struktur korrekt parst, aber vielleicht war das Aufdröseln schon hilfreich.

venice2 15. Dez 2020 06:52

AW: Json parsen problem
 
Zitat:

Zitat von DeddyH (Beitrag 1479106)
channels ist ein JSON-Array bestehend aus JSON-Objekten. So ein JSON-Objekt verfügt wiederum um ein JSON-Array namens programs, das dann wieder aus JSON-Objekten mit den Eigenschaften i_url (String), e (String) und g (JSON-Array) besteht. Ich kenne die verwendete JSON-Klasse leider nicht, daher kann ich auch nicht sagen, wie man damit die vorhandene Struktur korrekt parst, aber vielleicht war das Aufdröseln schon hilfreich.

Die Klasse ist hier.. ich habe das Problem das ich nicht an programs dran komme.

Delphi-Quellcode:
{ ' UNIT uZatEPG.pas
  '--------------------------- uZatEPG -----------------------------
  ' Copyright © 2020 BrewIdeas@Emil Weiss, All Rights Reserved
  '
  ' Author(s) of this Unit: Emil Weiss
  '---------------------------------------------------------------------------- }

unit uZatEPG;

interface

{$REGION 'uses'}

uses
  Windows, Messages, SysUtils, StrUtils, VCL.Dialogs, Classes, UrlMon, ActiveX,
  uZatJson, uGlobal, CommCtrl, JsonDataObjects, Generics.Collections;
{$ENDREGION}

{$REGION 'Const/Type'}

type
  TEpgEntries = (i_url, e, g, ry_u, i, sr_u, c, r_e, rg_u, e_no, s, t,
    ser_e, c_ids, et, i_t, ts_id, id, tms_id, s_no, success);

  TEpgEntryNames = array [TEpgEntries] of string;

type
  TEpgData = record
    i_url: string;
    e: LongInt;
    g: string;
    ry_u: LongInt;
    i: string;
    sr_u: LongInt;
    c: string;
    r_e: BOOL;
    e_no: string;
    s: LongInt;
    t: string;
    ser_e: BOOL;
    c_ids: LongInt;
    et: string;
    i_t: string;
    ts_id: LongInt;
    id: LongInt;
    tms_id: string;
    s_no: LongInt;
    success: BOOL;
  end;

const
  EntryEpgNames: TEpgEntryNames = ('i_url', 'e', 'g', 'ry_u', 'i', 'sr_u', 'c',
    'r_e', 'rg_u', 'e_no', 's', 't', 'ser_e', 'c_ids', 'et', 'i_t','ts_id',
    'id', 'tms_id', 's_no', 'success');

{$ENDREGION}
{$REGION 'Class TEpgDataList'}

type
  TEpgDataList = class
  private
    EpgData: TList<TEpgData>;
    procedure addEpgData(aZatJson: TZATJSON);
    procedure fillfromJson(const aJsonString: string);
    procedure FillList(aZatJson: TZATJSON);
    function GetItems(index: integer): TEpgData;
  public
    constructor create(const aJsonString: string);
    destructor Destroy; override;
    function Count: integer;
    property Items[index: integer]: TEpgData read GetItems; default;
  end;
{$ENDREGION}

{$REGION 'Class TZatEpg'}
type
  TZatEpg = class
  private
    EpgDataList: TEpgDataList;
    function GetEpgInfoString(Path: string; Data: string; var Info: string): boolean;
    function FormatJSONStr(AString : string): string;
  public
    constructor create;
    destructor Destroy; override;
    procedure Filltitles(aitems: Tstrings);
    function GetEpgInfo(Path: string; Data: string): boolean;
    function Item(index: integer): TEpgData;
    function ValidData: boolean;
  end;
{$ENDREGION}

implementation

{$REGION 'TZatEpg'}

{ TZatEpg }

function TZatEpg.GetEpgInfo(Path: string; Data: string): boolean;
var
  lWideFileData: string;
begin
  Result := False;
  try
    if GetEpgInfoString(Path, Data, lWideFileData) then
    begin
      EpgDataList := TEpgDataList.create(lWideFileData);
    end;
    Result := ValidData;
  except
    on e: exception do
      ShowMessage(e.Message);
  end;
end;

function TZatEpg.GetEpgInfoString(Path: string; Data: string; var Info: string): boolean;
var
  TxtFile: string;
  dwBytes: DWORD;
  lstream: TFileStream;
  lutf8: UTF8String;
  List : TStringList;
begin

  Result := False;
  Info := '';

  if Path = '' then
    exit;

  TxtFile := Path + 'EPG_data.json';
  // get new Data from now
  if FileExists(TxtFile) then
    DeleteFile(TxtFile);

  List := TStringList.Create;
  try
    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);
    Info := string(lutf8);
    // Format Json
    lutf8 := UTF8String(FormatJSONStr(string(lutf8)));
    lstream.Position := 0;
    lstream.WriteBuffer(lutf8[1], length(lutf8));
    Result := True;
  finally
    lstream.free;
  end;
end;

constructor TZatEpg.create;
begin

  inherited;

end;

destructor TZatEpg.Destroy;
begin

  if Assigned(EpgDataList) then
    FreeAndNil(EpgDataList);
  inherited;
end;

procedure TZatEpg.Filltitles(aitems: Tstrings);
//var
//  I: integer;
begin

  aitems.clear;
//  for I := 0 to EpgDataList.Count - 1 do
//    aitems.add(EpgDataList[I].title);
end;

function TZatEpg.FormatJSONStr(AString: string): string;
var
  Obj: TJsonObject;
begin

  Obj := Obj.Parse(PWideChar(AString))as TJsonObject;
  result := Obj.ToJSON(False);
end;

function TZatEpg.Item(index: integer): TEpgData;
begin

  if ValidData then
    Result := EpgDataList[index];
end;

function TZatEpg.ValidData: boolean;
begin

  Result := assigned(EpgDataList) and (EpgDataList.Count > 0);
end;
{$ENDREGION}
{$REGION 'TEpgDataList'}

{ TEpgDataList }
constructor TEpgDataList.create(const aJsonString: string);
begin

  inherited create;
  EpgData := TList<TEpgData>.create;
  fillfromJson(aJsonString);
end;

destructor TEpgDataList.Destroy;
begin

  FreeAndNil(EpgData);
  inherited;
end;

procedure TEpgDataList.addEpgData(aZatJson: TZATJSON);
var
  entry: TEpgData;
  Epgloop: tEpgEntries;
  ltemp: TZATJSON;
  lEntrienames: tEpgEntryNames;
begin

  if assigned(aZatJson) then
  begin
    // Set up temporary Data
    entry := System.default(TEpgData);

    lEntrienames := EntryEpgNames;

    begin
      for Epgloop := Low(TEpgEntries) to High(TEpgEntries) do
        // Check if there is a Name.......
        if lEntrienames[Epgloop] <> '' then
        begin
          ltemp := aZatJson[lEntrienames[Epgloop]];

          if ltemp <> nil then
            case Epgloop of
              i_url: entry.i_url  := ltemp.AsString;
              e: entry.e          := ltemp.AsInteger;
              g: entry.g          := ltemp.TArray;
              ry_u: entry.ry_u    := ltemp.AsInteger;
              i: entry.i          := ltemp.AsString;
              sr_u: entry.sr_u    := ltemp.AsInteger;
              c: entry.c          := ltemp.AsString;
              r_e: entry.r_e      := ltemp.AsBoolean;
              e_no: entry.e_no    := ltemp.AsString;
              s: entry.s          := ltemp.AsInteger;
              t: entry.t          := ltemp.AsString;
              ser_e: entry.ser_e  := ltemp.AsBoolean;
              c_ids: entry.c_ids  := ltemp.AsInteger;
              et: entry.et        := ltemp.AsString;
              i_t: entry.i_t      := ltemp.AsString;
              ts_id: entry.ts_id  := ltemp.AsInteger;
              id: entry.id        := ltemp.AsInteger;
              tms_id: entry.tms_id := ltemp.AsString;
              s_no: entry.s_no    := ltemp.AsInteger;
            end;
        end;
    end;

    EpgData.add(entry);
  end;

end;

function TEpgDataList.Count: integer;
begin

  Result := EpgData.Count;
end;

procedure TEpgDataList.fillfromJson(const aJsonString: string);
Var
  lZatJson: TZATJSON;
begin

  lZatJson := TZATJSON.Parse(aJsonString);
  try
    if assigned(lZatJson) then
      FillList(lZatJson);

  finally
    lZatJson.free;
  end;
end;

procedure TEpgDataList.FillList(aZatJson: TZATJSON);
var
//  I: integer;
  lZatJson: TZATJSON;
begin

  if assigned(aZatJson) then
  begin
    lZatJson := aZatJson.JSONByNameOrIndex['channels'];
    if assigned(lZatJson) and lZatJson.IsList then
    begin
      if lZatJson.ListItems.Count > 0 then
        addEpgData(lZatJson.ListItems[1]);
    end;
  end;
end;

function TEpgDataList.GetItems(index: integer): TEpgData;
begin

  Result := EpgData[index];
end;
{$ENDREGION}

end.
Danke für die Antwort.
Das ist die Funktion welche die Daten addiert

Delphi-Quellcode:
procedure TEpgDataList.FillList(aZatJson: TZATJSON);
Und im Anhang die uZatJson.pas

DeddyH 15. Dez 2020 06:59

AW: Json parsen problem
 
Das ist mir ehrlich gesagt zu schwierig auf die Schnelle nachzuvollziehen. Vielleicht hilft aber dieses Beispiel weiter (ich selbst benutze nur System.JSON, das gab es aber unter Delphi 2010 noch nicht IIRC): https://gist.github.com/fabriciocolo...010787d86b5c65

venice2 15. Dez 2020 07:02

AW: Json parsen problem
 
Zitat:

Zitat von DeddyH (Beitrag 1479108)
Das ist mir ehrlich gesagt zu schwierig auf die Schnelle nachzuvollziehen. Vielleicht hilft aber dieses Beispiel weiter (ich selbst benutze nur System.JSON, das gab es aber unter Delphi 2010 noch nicht IIRC): https://gist.github.com/fabriciocolo...010787d86b5c65

Hmmm.. schade.
Mit dem Code kann ich leider nichts anfangen ist ja quasi das gleiche.


Edit:
Habe es mal so versucht funktioniert leider nicht.
Delphi-Quellcode:
procedure TEpgDataList.FillList(aZatJson: TZATJSON);
var
//  I: integer;
  channels: TZATJSON;
  programs: TZATJSON;
begin

  if assigned(aZatJson) then
  begin
    channels := aZatJson.JSONByNameOrIndex['channels'];
    if assigned(channels) and channels.IsList then // gibt mir den Count von 170 Sendern zurück
    begin
      programs := aZatJson.JSONByNameOrIndex['programs']; // hier kracht es
      if programs.ListItems.Count > 0 then
        addEpgData(programs.ListItems[1]);
    end;
  end;
end;

Daniel 15. Dez 2020 07:57

AW: Json parsen problem
 
Und wenn Du nicht "aZatJson", sondern "channels" nach dem Element "programs" befragst? Immerhin ist "programs" ja auch ein direktes Unterelement davon.
Delphi-Quellcode:
programs := channels.JSONByNameOrIndex['programs'];
.

venice2 15. Dez 2020 08:07

AW: Json parsen problem
 
Zitat:

Zitat von Daniel (Beitrag 1479112)
Und wenn Du nicht "aZatJson", sondern "channels" nach dem Element "programs" befragst? Immerhin ist "programs" ja auch ein direktes Unterelement davon.
Delphi-Quellcode:
programs := channels.JSONByNameOrIndex['programs'];
.

Das ist es ja warum geht es nicht.
so kann ich es nicht abfragen aber auf diese weise.

Delphi-Quellcode:
lZatJson := aZatJson.JSONByNameOrIndex['channels']; // ist ja schon die initialisierung von channels und funktioniert.


Dein Vorschlag wäre dann, falls ich dich richtig verstehe.

Delphi-Quellcode:
programs := lZatJson.JSONByNameOrIndex['programs'];

Danke für den Beitrag.

würde ich channels nehmen dann müsste ich channels als TZATJSON definieren.
habe es versucht schlägt aber ebenso fehl.


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

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