![]() |
Datenbank: MySQL • Version: 5 • Zugriff über: FireDac
JSON in TFDQuery
Hallo Zusammen,
es geht zwar nicht wirklich um Datenbanken, aber Query und JSON, daher habe ich das Thema jetzt mal hier platziert. Ich greife über eine API den Status von Maschinen ab. Das habe ich bislang über FDQueries auf der Datenbak gemacht, soll aber jetzt über die API laufen... Die Abfrage soll später auf einer Serverinstance laufen, die Daten in einer Query ablegen, wo die Clients sich diese über eine Service-Abfrage rausholen... In meinem Test-Programm habe ich eine TIdHTTP Komponente, mit der ich die Daten abfrage. Ich bekomme ein JSON in einen TStream zurück. Diesen Stream möchte ich gerne in eine FDQuery mit LoadFrom Stream laden. Hier der Code:
Delphi-Quellcode:
Leider funktioniert dieser Weg neicht, denn ich bekomme immer eine Fehlermeldung:
procedure TForm1.Button1Click(Sender: TObject);
var LStream: TMemoryStream; begin LStream := TMemoryStream.Create; Try IdHTTP.Get(edt_URL.Text, LStream); FDQuery.LoadFromStream(LStream, sfJSON); Finally LStream.Free; End; end;
Delphi-Quellcode:
Ich habe dann den Stream in eine Datei gespeichert um zu sehen, was da drinsteht:
Ungültiges JSON-Speicherformat Position 1020 aufgetreten.
Code:
Über einen Online-JSON-Reader habe ich das geprüft, das scheint in Ordnung zu sein.
{"error":null,"device":{"id":"4106","name":"XL106-8PL","classId":"ID_SheetfedPress","deviceStatus":{"status":"Running","activity":"Gutproduktion","speed":15000,"totalizer":96280594,"workstep":{"id":"CV__1182420004","name":"ST118242 4/4","job":{"id":"305537","name":"Panorama","jobCustomer":{"id":"022075","name":"Life e. V."},"customerOrderId":"305537"},"status":"RUNNING","amountPlanned":75075,"wastePlanned":775,"amountProduced":30293,"wasteProduced":999,"deviceId":"4106","types":["ConventionalPrinting"],"sequenceType":"SheetfedPrinting","start":"2023-06-05T11:25:55+02:00","end":"2023-06-05T13:18:09+02:00","startPlanned":null,"endPlanned":null,"setuptimePlanned":480,"prodtimePlanned":20160,"actualTimes":[{"timeTypeGroupName":"Fertigungszeit","timeTypeName":"Ausführungszeit","duration":10413},{"timeTypeGroupName":"Fertigungszeit","timeTypeName":"Rüstzeit","duration":1304}]},"employees":[{"id":"231","name":"Rosse","firstName":"Kevin"},{"id":"233","name":"Resse","firstName":"David"}]}}}
Die Position 1020 ist die vorletzte Klammer... Hat jemand eine Idee, was ich falsch mache? Wäre eine schöne und einfache Lösung, an der jetzt schon einige Zeit scheitere... Vielen Dank Patrick |
AW: JSON in TFDQuery
Damit eine TFDQuery über JSON geladen werden kann, genügt es nicht, sie einfach mit einem in der Syntax validen JSON zu füttern. Es muss schon auch inhaltlich dem intern verwendeten JSON-Format entsprechen. Wie das aussieht bekommest du am einfachsten raus, wenn du das ResultSet einer Query als JSON-Stream abspeicherst.
Ich gehe aber mal davon aus, dass die API kein FireDAC-konformes JSON liefern soll, sondern die gezeigte Struktur. Dann kommt dein simpler Ansatz mit LoadFromStream allerdings nicht in Frage. |
AW: JSON in TFDQuery
Am simpelsten wäre es, wenn du die Speedmaster-Daten in einem Blob-Feld speicherst. Dann könnte dein Webservice einfach die empfangenen JSON-Strings aus der Datenbank an die Clients weiterleiten. Falls sich das Datenformat nicht ändert, könntest Du natürlich das JSON in die Felder deserialisieren und in entsprechende Tabellen schreiben. Dann hättest Du einfachere Auswertungsmöglichkeiten, mit dem Nachteil, dass du die Tabellendaten wieder serialisieren müsstest.
Zur Abfrage der Druckjobs solltest Du IMHO besser TRestClient / TRestRequest verwenden. |
AW: JSON in TFDQuery
Zitat:
![]() Bis bald... Thomas |
AW: JSON in TFDQuery
Wenn du den Code in der DB bereits hast, dann wäre es natürlich am Einfachstens das JSON als String (VARCHAR bzw. TEXT) übergeben.
Ja, es gibt auch einen JSON-Type. Kommt aber darauf an, wie FireDAC damit umgeht. Vermutlich wird einfach alles "Unbekannte" im FireDAC wie ein VARCHAR/TEXT behandelt. |
AW: JSON in TFDQuery
Hallo Zusammen,
Rückmeldung, wie ich das Thema vorerst angegangen bin: Nachdem es keine "einfache" Lösung gab, habe ich das JSON manuell ausgelesen:
Delphi-Quellcode:
procedure TForm1.Get_NextJSValue(Feld: string; ActJSValue: TJSONValue; var JSObj: TJSONObject; var JSValue: TJSONValue);
begin JSObj := TJSONObject(ActJSValue); if Feld <> '' then JSValue := JSObj.Values[Feld]; end; function TForm1.MyStreamToString(aStream: TStream): widestring; var SS: TStringStream; begin if aStream <> nil then begin Result := '{"data":'; SS := TStringStream.Create(''); try SS.CopyFrom(aStream, 0); Result := Result + SS.DataString; Result := Result + '}'; finally SS.Free; end; end else begin Result := ''; end; end;
Delphi-Quellcode:
var FirstJSObject: TJSONObject;
SecondJSObject: TJSONObject; ThirdJSObject: TJSONObject; FourthJSObject: TJSONObject; FivthJSObject: TJSONObject; SixthJSObject: TJSONObject; SeventhJSObject: TJSONObject; EigthJSObject: TJSONObject; FirstArr: TJSONArray; FirstJSValue: TJSONValue; SecondJSValue: TJSONValue; ThirdJSValue: TJSONValue; FourthJSValue: TJSONValue; FivthJSValue: TJSONValue; SixthJSValue: TJSONValue; SeventhJSValue: TJSONValue; EigthJSValue: TJSONValue; StreamString: widestring; j: integer; begin StreamString := Get_MData(edt_URL.Text, true); Get_FirstJSValue('data', StreamString, FirstJSObject, FirstJSValue); Try if Assigned(FirstJSValue) and (FirstJSValue is TJSONObject) then begin Get_NextJSValue('device', FirstJSValue, SecondJSObject, SecondJSValue); if Assigned(SecondJSValue) and (SecondJSValue is TJSONObject) then begin Get_NextJSValue('deviceStatus', SecondJSValue, ThirdJSObject, ThirdJSValue); if Assigned(ThirdJSValue) and (ThirdJSValue is TJSONObject) then begin Get_NextJSValue('workstep', ThirdJSValue, FourthJSObject, FourthJSValue); if Assigned(FourthJSValue) and (FourthJSValue is TJSONObject) then begin Get_NextJSValue('job', FourthJSValue, FivthJSObject, FivthJSValue); if Assigned(FivthJSValue) and (FivthJSValue is TJSONObject) then begin Get_NextJSValue('jobCustomer', FivthJSValue, SixthJSObject, SixthJSValue); if Assigned(SixthJSValue) and (SixthJSValue is TJSONObject) then begin Get_NextJSValue('', FivthJSValue, SeventhJSObject, SeventhJSValue); end; end; end; Get_NextJSValue('employees', ThirdJSValue, FourthJSObject, FourthJSValue); if Assigned(FourthJSValue) and (FourthJSValue is TJSONArray) then begin //JSONARRAY FirstArr := TJSONArray(FourthJSValue); for j := 0 to FirstArr.Count - 1 do begin if FirstArr.Items[j] is TJSONObject then begin EigthJSObject := TJSONObject(FirstArr.Items[j]); end; end; end; end; end; end; //Daten von Objekt abfragen ExtracJSValues(FirstJSObject, SecondJSObject, ThirdJSObject, FourthJSObject, FivthJSObject, SixthJSObject, SeventhJSObject, EigthJSObject, nil); finally FirstJSObject.Free; {SecondJSObject.Free; //Hier gibt es eine Zugriffs-Exception ThirdJSObject.Free; FourthJSObject.Free; FivthJSObject.Free; SixthJSObject.Free; SeventhJSObject.Free; EigthJSObject.Free;} end; end;
Delphi-Quellcode:
So weit bekomme ich die gewünschten Daten aus dem JSON raus. Jetzt muss ich die noch in geeigneter Form bereitstellen...
rocedure TForm1.ExtracJSValues(JSObj_1, JSObj_2, JSObj_3, JSObj_4, JSObj_5,
JSObj_6, JSObj_7, JSObj_8: TJSONObject; Qry: TFDQuery); var JOB_Bez, JOB_Nr, JOB_Name: string; PLANNED_GOOD_MANOUNT: integer; GOOD_CYCLES: integer; Speed: integer; PERCENT_COMPLETED: string; Start: string; Dauer: string; OperatorName: string; Operator_VName: string; Operator_NName: string; OPERATION_NAME: string; WORK_STEP_NAME: string; OPERATION_KEY: string; begin if not JSObj_4.TryGetValue<string>('activity', OPERATION_NAME) then OPERATION_NAME := ''; if not JSObj_4.TryGetValue<integer>('speed', Speed) then Speed := 0; if not JSObj_5.TryGetValue<string>('name', WORK_STEP_NAME) then WORK_STEP_NAME := ''; if not JSObj_5.TryGetValue<string>('status', OPERATION_KEY) then OPERATION_KEY := ''; if not JSObj_5.TryGetValue<string>('start', Start) then Start := ''; if not JSObj_6.TryGetValue<string>('name', JOB_Bez) then JOB_Bez := ''; if not JSObj_6.TryGetValue<string>('id', JOB_Nr) then JOB_Nr := ''; JOB_Name := JOB_Nr + ' ' + JOB_Bez; if not JSObj_8.TryGetValue<string>('firstName', Operator_VName) then Operator_VName := ''; if not JSObj_8.TryGetValue<string>('name', Operator_NName) then Operator_NName := ''; OperatorName := Operator_VName + ' ' + Operator_NName; if assigned(Qry) then begin Qry.Insert; end; end; Herzlichen Gruß und allen eine gute Woche Patrick |
AW: JSON in TFDQuery
Der Code müsste beim compilieren eigentlich Meldungen über nicht initialisierte Variablen verursachen.
Sind diese Warnungen etwa ausgeschalten? Es ist sinnvoll GetNextJSValue aufzuteilen und sinnvolle Namen für Variablen zu verwenden:
Delphi-Quellcode:
function GetFieldValue(AObject: TJSONObject; const AFieldname: string): TJSonValue;
begin if Assigned(AObject) and (AFieldname <> '') then Result := AObject.Values[Feld] else Result := nil; end; function GetSubObject(AObject: TJSONObject; const AFieldname: string): TJSONObject; var lValue: TJSONValue; begin lValue := GetFieldValue(AObject, AFieldname); if Assigned(lValue) and lValue is TJSONObject) then Result := TJSONObject(lValue) else Result := nil; end; function GetSubArray(AObject: TJSONObject; const AFieldname: string): TJSONArray; var lValue: TJSONValue; begin lValue := GetFieldValue(AObject, AFieldname); if Assigned(lValue) and lValue is TJSONArray) then Result := TJSONArray(lValue) else Result := nil; end;
Delphi-Quellcode:
Get_FirstJSValue('data', StreamString, obj_data, FirstJSValue);
Try obj_device := GetSubObject(obj_data, 'device'); obj_deviceStatus := GetSubObject(obj_device, 'deviceStatus'); obj_workstep := GetSubObject(obj_deviceStatus, 'workstep'); obj_job := GetSubObject(obj_workstep, 'job'); obj_jobCustomer := GetSubObject(obj_job, 'jobCustomer'); arr_employees := GetSubArray(obj_deviceStatus, 'employees'); if Assigned(arr_employees) then begin |
AW: JSON in TFDQuery
Zitat:
Delphi-Quellcode:
if lValue is TJSONArray then
IS prüft auf NIL. (aber Achtung, AS läßt NIL durch) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:11 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-2025 by Thomas Breitkreuz