JSON parsen

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
SieGeL2k22
Beiträge: 7
Registriert: 16.05.2022 06:10
Computerausstattung: Ryzen 1800X, 16GB RAM, 1,2TB SSD, Windows 10
Wohnort: Berlin
Kontaktdaten:

JSON parsen

Beitrag von SieGeL2k22 »

Hallo Community,

ich versuche gerade eine JSON Antwort von einem Server zu parsen, aber irgendwie stelle ich mich da zu doof an :(

Evtl. kann mir da ja mal jemand auf die Sprünge helfen? Es geht um folgende JSON Struktur:

Code: Alles auswählen

{
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJJbm9Db3JlIiwiaWF0IjoxNjUyNjc0MzY2LCJleHAiOjE2NTI2Nzc5NjYsImF1ZCI6InB1cmViYXNpY0Bsb2NhbGhvc3QiLCJ1aWQiOjh9.q66RWqH3iBJsCuAdJ_XCLjWSj7i3BJhs3gmB4MC1KBk",
    "expires": {
        "date": "2022-05-16 07:12:46.098796",
        "timezone_type": 3,
        "timezone": "Europe/Berlin"
    },
    "user": {
        "id": 8,
        "email": "purebasic@localhost",
        "firstname": "Pure",
        "lastname": "Basic",
        "login_count": 115,
        "last_login": "2022-05-16 06:12:29.409009",
        "failed_login_date": null,
        "create_date": "2022-05-15 22:23:11.800488",
        "is_daemon": 0
    }
}
Wie kann ich direkt auf die einzelnen Elemente unterhalb von "expires" und "user" zugreifen? Auf "token" kann ich problemlos zugreifen, aber irgendwie raffe ich das nicht, wie man auf die Unterelemente der "expires" bzw. "user" Elemente zugreifen soll...

Meine bisherigen Ansätze scheitern immer daran, dass einige Felder leer sind??

Hier mein Code:

Code: Alles auswählen

Structure ICTExpires
  date.s
  timezone_type.l
  timezone.s
EndStructure  

Structure ICTUser
  id.l
  email.s
  firstname.s
  lastname.s
  login_count.l
  last_login.s
  failed_login_date.s
  create_date.s
  is_daemon.l
EndStructure  

Structure ICT
  token.s
  Map expires.ICTExpires()
  Map user.ICTUser()
EndStructure


HttpRequest = HTTPRequest(#PB_HTTP_Post,BASE$, "["+Chr(34)+"todo.all"+Chr(34)+"]", #PB_HTTP_Debug|#PB_HTTP_NoSSLCheck, Header$());
If HttpRequest
  HttpCode.s = HTTPInfo(HTTPRequest, #PB_HTTP_StatusCode)
  HttpResponse = HTTPInfo(HTTPRequest, #PB_HTTP_Response)
  FinishHTTP(HTTPRequest)
  
  ParseJSON(0,HttpResponse)
  ObjectValue = JSONValue(0)
  NewMap Expires.ICTExpires()
  NewMap User()
  NewMap UL.ICTUser()  
  NewMap ICT.ICT()
 Token.s = GetJSONString(GetJSONMember(JSONValue(0),"token"))

ExtractJSONMap(JSONValue(0),ICT())

Debug ICT()\expires()\date

ExtractJSONMap(GetJSONMember(JSONValue(0),"expires"),Expires())
ExtractJSONMap(GetJSONMember(JSONValue(0),"user"),User())
ExtractJSONMap(GetJSONMember(JSONValue(0),"user"),UL())

Debug "DATE: " + Expires()\date
Debug "TZ-TYPE: " + Expires()\timezone_type
Debug "TZ: " + Expires()\timezone
;Debug user("email")
;Debug Token



Else
  Debug "Request creation failed"
EndIf
Debug "---------------------------------------------"
Debug(HttpResponse);
Sobald ich auf die Unterlemente zugreifen will (z.B. ICT()\expires()\date) sind die immer leer?

Nutze ich "ExtractJSONMap(GetJSONMember(JSONValue(0),"user"),User())" - also eine leere Map - sind alle Integer Fields leer.

Definiere ich die Map "User()" als "User.s()", sind die Textfields vorhanden, dafür aber die Integerfelder nicht mehr?

Kann mir da evtl. mal jemand helfen, meinen Knoten im Kopf zu lösen?

Vielen Dank schon mal im Vorraus!
Benutzeravatar
Bisonte
Beiträge: 2425
Registriert: 01.04.2007 20:18

Re: JSON parsen

Beitrag von Bisonte »

Es klappt nicht, da es keine maps sind...

ich gehe davon aus, dass die oben genannte json struktur das ist, was bei dem http-request rauskommt, also immer ein datensatz.
daher ist es keine map sondern ganz banal nur eine struktur.

Code: Alles auswählen

Structure s_expires
  date.s
  timezone_type.i
  timezone.s
EndStructure
Structure s_user
  id.i
  email.s
  firstname.s
  lastname.s
  login_count.i
  last_login.s
  failed_login_date.s
  create_date.s
  is_daemon.i
EndStructure

Structure myStructure
  token.s
  expires.s_expires
  user.s_user
EndStructure

Procedure.i LoadJSONFile(File$, *Var.myStructure, Flag = #PB_JSON_NoCase)
  
  Protected jV, jSon = LoadJSON(#PB_Any, File$, Flag)
  Protected Result = #False
  
  If jSon
    jV = JSONValue(jSon)
    ExtractJSONStructure(jV, *Var, myStructure)
    Result = #True
    FreeJSON(jSon)
  EndIf
  
  ProcedureReturn Result
  
EndProcedure

Define a.myStructure

LoadJSONFile("R:\test.json",@a)

Debug a\user\email
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
Benutzeravatar
SieGeL2k22
Beiträge: 7
Registriert: 16.05.2022 06:10
Computerausstattung: Ryzen 1800X, 16GB RAM, 1,2TB SSD, Windows 10
Wohnort: Berlin
Kontaktdaten:

Re: JSON parsen

Beitrag von SieGeL2k22 »

@Bisonte:

Erst mal Danke für Deine schnelle Antwort!

Habe das gerade getestet und nun klappt das auch!

Ich habe in der Anleitung von json immer ein Json Object als Map gleich gesetzt, da war ich wohl schon zu müde :)

Nochmals Danke für Deine Hilfe!
Benutzeravatar
TroaX
Beiträge: 659
Registriert: 08.03.2013 14:27
Computerausstattung: PC: Ryzen 9 3950X, 96 GB RAM, RX6800XT, 2.5 TB SSD, 21:9 Display, Pop_OS! | Lappi: Ryzen 7 5800H, 16 GB RAM, 1 TB SSD, Pop_OS!
Wohnort: NRW
Kontaktdaten:

Re: JSON parsen

Beitrag von TroaX »

Generell gibt das JSON nicht genau vor, in was für eine Art Strukturtyp das ganze zu behandeln ist. Das Problem an der Stelle war nicht, das es keine Map laut JSON ist (was JSON nicht vorgibt), sondern das die Werte der Schlüssel unterschiedlichsten Typs sind. Eine Map, Liste oder ein Array müssen immer einen festen Typ haben. Entweder ein primitiver Datentyp (Integer, Long, String etc.) oder eine Struktur als Typ. Wenn also alle Werte vom Typ String gewesen wären, dann hätte es auch als Map geklappt. Was noch interessant wäre, ob die JSON-Lib bei der Nutzung als Map oder List mit dem Typ String die Zahlen automatisch zu einem String konvertiert. Das müsste ich nachher mal testen. Sonst ist JSON eine ziemlich eklige Angelegenheit mit PB
PC: Ryzen 9 3950X | 96 GB RAM | RX6800XT | 2,5 TB NVMe | Pop_OS!
Notebook: 16" 3:2 | Ryzen 7 5800H | 16 GB RAM | Radeon Vega | 1TB NVMe | Pop_OS!
NAS: Fritz.Box :lol:
Coding: Purebasic 6.04 | PHP | HTML | CSS | Javascript
Benutzeravatar
SieGeL2k22
Beiträge: 7
Registriert: 16.05.2022 06:10
Computerausstattung: Ryzen 1800X, 16GB RAM, 1,2TB SSD, Windows 10
Wohnort: Berlin
Kontaktdaten:

Re: JSON parsen

Beitrag von SieGeL2k22 »

Also ich hatte das ja zuerst mit den Maps probiert, da war es dann halt so, dass die Integer Werte bei Nutzung einer string-basierten Map allesamt leer waren.
Mir war nicht bewusst, das eine Map immer einen gleichen Datentyp haben muss?!
Ich hatte das eher wie einen Key-Value Speicher angesehen, der unabhängig vom Datentyp arbeitet (so wie z.B. bei PHP die assoziativen Arrays).

Aber Danke noch mal für die Erklärung, das werde ich mir auf alle Fälle merken!
Benutzeravatar
TroaX
Beiträge: 659
Registriert: 08.03.2013 14:27
Computerausstattung: PC: Ryzen 9 3950X, 96 GB RAM, RX6800XT, 2.5 TB SSD, 21:9 Display, Pop_OS! | Lappi: Ryzen 7 5800H, 16 GB RAM, 1 TB SSD, Pop_OS!
Wohnort: NRW
Kontaktdaten:

Re: JSON parsen

Beitrag von TroaX »

Alle Elemente einer Map sind vom Typ bei der Initialisierung. Erstellst du eine String-Map, sind auch alle Elemente der Map vom Typ String. Ohne Angabe eines Typs müsste sie immer vom Typ Integer sein. Ein Test bzgl. Autocast kann ich mir nach einem kurzen Blick in die Hilfe sparen:
Wenn der JSON-Wert Elemente enthält, die nicht den richtigen Typ haben, um mit der Map() übereinzustimmen, dann werden sie ignoriert und das zugehörige Map-Element bleibt leer.
Das ist im Grunde das, was du beobachtet hast. Es ist also nicht ganz trivial, mit den Maps zu hantieren.
PC: Ryzen 9 3950X | 96 GB RAM | RX6800XT | 2,5 TB NVMe | Pop_OS!
Notebook: 16" 3:2 | Ryzen 7 5800H | 16 GB RAM | Radeon Vega | 1TB NVMe | Pop_OS!
NAS: Fritz.Box :lol:
Coding: Purebasic 6.04 | PHP | HTML | CSS | Javascript
Antworten