C++ Builder XE4 - JSON
-
Hallo Zusammen,
Entweder bin ich blöde, oder es gibt für den C++ Builder XE4 entgegen aller Ankündigungen keine JSON Komponente?
Habe das XE4 Studio, aber kein Delphi installiert, laut RAD sollte es aber auch im C++ Builder die TJSONObject Komponente geben, aber beim Kompilieren erhalte ich die Fehlermeldung das TJSONObject jedoch undefiniert sei?
Kann mir da jemand helfen? Muss ich wirklich das doofe Delphi mit Installieren oder kennt jemand andere Komponenten um JSON zu verarbeiten?
Grüße,
Daniel
-
Sany1984 schrieb:
Entweder bin ich blöde, oder es gibt für den C++ Builder XE4 entgegen aller Ankündigungen keine JSON Komponente?
In RAD Studio XE Professional liegt die Komponente in $(BDS)\source\database\DBXJSON.pas . Da mußt du wohl die entsprechende Headerdatei einbinden.
Sany1984 schrieb:
Muss ich wirklich das doofe Delphi mit Installieren
Sei doch froh, daß du es hast. Delphi ist bei der Arbeit mit C++Builder sehr nützlich, weil alle VCL-(und FMX-)Komponenten in Delphi geschrieben sind; wenn du Delphi installiert hast, kann der Editor auch in .pas-Dateien "Go to definition", Code Completion und so, außerdem kannst du dann im Debugger den Delphi-Evaluator benutzen, der mit Pascal-Code naturgemäß besser funktioniert als der C++-Evaluator.
Sany1984 schrieb:
oder kennt jemand andere Komponenten um JSON zu verarbeiten?
Ich fand SuperObject von Henri Gourvest ganz brauchbar.
-
Hallo,
Okay alles gut, mit dem Update auf die XE5 habe ich nun Delphi mit installiert.
Nun bin ich seit einigen Tagen am Werkeln und habe ein Problem mit der JSON Komponente...
Ich habe folgenden Code:
void __fastcall TfrmArtikelUebersicht::FormShow(TObject *Sender) { HTTPBasicAuthenticator1->Username = frmMain->SW_API_Username; HTTPBasicAuthenticator1->Password = frmMain->SW_API_Password; RESTClient1->Authenticator = HTTPBasicAuthenticator1; RESTClient1->BaseURL = frmMain->SW_API_Basement; RESTRequest1->Response = RESTResponse1; RESTResponse1->ContentEncoding = "UTF-8"; RESTRequest1->Resource = "/articles"; RESTRequest1->Execute(); TJSONObject* jsonResponse = (TJSONObject*)RESTRequest1->Response->JSONValue; if(jsonResponse->GetValue("success")->ToString() == "true") { TJSONObject *jsonData = new TJSONObject; jsonData = (TJSONObject*)jsonResponse->GetValue("data"); RESTResponseDataSetAdapter1->UpdateDataSet(); DBGrid1->Show(); /** Kategorie Baum holen **/ RESTRequest1->Resource = "/categories"; RESTRequest1->Execute(); jsonResponse = (TJSONObject*)RESTRequest1->Response->JSONValue; TJSONObject *jsonCategories = new TJSONObject; jsonCategories = (TJSONObject*)jsonResponse->GetValue("data"); int count = StrToInt(jsonResponse->GetValue("total")->ToString()); for(int a=0; a < count; a++) { TJSONObject *jsonCategory = new TJSONObject; jsonCategory = (TJSONObject*)jsonCategories->Get(a); int Id = StrToInt(jsonCategory->GetValue("id")->Value()); bool active = StrToBool(jsonCategory->GetValue("active")->ToString()); int parentId = StrToInt(jsonCategory->GetValue("parentId")->Value()); int childrenCount = StrToInt(jsonCategory->GetValue("childrenCount")->Value()); String name = jsonCategory->GetValue("name")->Value(); TreeView1->Items->Add(NULL, name ); if(childrenCount > 0) { TJSONObject *children = new TJSONObject; children = getCategoriesById(Id); ShowMessage(children->ToString()); ShowMessage(IntToStr(children->Size())); } } } else { ShowMessage(jsonResponse->GetValue("message")->ToString()); } } //--------------------------------------------------------------------------- TJSONObject *__fastcall TfrmArtikelUebersicht::getCategoriesById(int id) { HTTPBasicAuthenticator2->Username = frmMain->SW_API_Username; HTTPBasicAuthenticator2->Password = frmMain->SW_API_Password; RESTClient2->Authenticator = HTTPBasicAuthenticator2; RESTClient2->BaseURL = frmMain->SW_API_Basement; RESTRequest2->Response = RESTResponse1; RESTResponse2->ContentEncoding = "UTF-8"; RESTRequest2->Resource = "/categories"; RESTRequest2->AddParameter("node",IntToStr(id)), RESTRequest2->Execute(); TJSONObject *response = new TJSONObject; response = (TJSONObject*)RESTRequest2->Response->JSONValue; TJSONObject *data = new TJSONObject; data = (TJSONObject*)response->GetValue("data"); return data; }
So im ersten Durchlauf ist mein TJSON Object jsonCategories noch voll (7 Items), bis Ich die Funktion getCategoriesById(int id) aufrufe zum holen der Childs, da kriege ich auch noch etwas zurück das passt auch soweit.
So, beginnt nun die for schleife von vorne, und möchte sich gerne Item 2 holen und dann plötzlich ist das jsonCategories Object leer
Nutze ich die Komponente irgendwie falsch? o.O
Danke
-
Sany1984 schrieb:
Okay alles gut, mit dem Update auf die XE5 habe ich nun Delphi mit installiert.
Super, dann kannst du ja (wenn du ohne Packages kompilierst) mit dem Debugger in den VCL-Quelltext hineinsteppen und nachsehen, was da genau passiert. Das ist jedenfalls, was ich tun würde, wenn ich das Problem lösen müßte.
Mit der Speicherverwaltung hast du's nicht so, oder? Alle deine
new
s werden nie freigegeben => Speicherlecks. Außerdem sind sie allesamt unnötig; bei näherem Hinsehen fällt dir vielleicht die inhärente Sinnlosigkeit dieser Zeilen ins Auge:TJSONObject *jsonData = new TJSONObject; jsonData = (TJSONObject*)jsonResponse->GetValue("data");
Das bringt ungefähr so viel wie
int i = 5; i = 3;
In diesem Fall würdest du sogar eine Compilerwarnung erhalten, die auf besagte Sinnfreiheit hinweist.
Vielleicht willst du übrigens doch mal die Komponente von Henri Gourvest ausprobieren. Die unterstützt nämlich in recht komfortabler Weise RTTI, so daß du in Delphi folgendes machen kannst (Codebeispiel aus einem beiliegenden Demoprojekt):
type TResult = record title: string; url: string; titleNoFormatting: string; cacheUrl: string; GsearchResultClass: string; visibleUrl: string; content: string; unescapedUrl: string; end; TResultList = array of TResult; procedure TSearchForm.goClick(Sender: TObject); var req: IXMLHttpRequest; ctx: TSuperRttiContext; response: ISuperObject; result: TResultList; ... begin ... result := ctx.AsType<TResultList>(response['responseData.results']); ... end;
Wenn ich mich nicht täusche, müßte das mittlerweile auch in C++Builder möglich sein. Suchbegriffe __declspec(delphirecord) und __declspec(delphirtti).
-
Hallo,
Danke für dein Beitrag, aber ich habe die new's extra genau deshalb so umgeschrieben um zu testen, ob das etwas bewirkt, das dass natürlich Sinnfrei ist, ist mir klar
Die Komponenten von Delphi sind im C++ Builder schon drin, da ist nich wirklich viel mit debuggen, zu mindest bin ich noch nicht sehr weit in die Komponente durch gedrungen.
Ich dachte evtl. das es eben an der Zuweisung der new's liegt, das die Objekte alles verlieren, denn Sie tun's auch in Delphi komischer weiße wie heute getestet.
Zumindest habe ich bis jetzt noch nicht herausgefunden warum die Objects sich leeren, ich werd mich gleich mal dein Vorschlag reinziehen und mal ausprobieren.
Grüße,
Daniel
-
Sany1984 schrieb:
Die Komponenten von Delphi sind im C++ Builder schon drin, da ist nich wirklich viel mit debuggen
Nur weil Embarcadero die Komponente mitliefert, muß sie nicht fehlerfrei sein, eher im Gegenteil
Allerdings geht es mir nicht darum, daß du Fehler in der Komponente suchst, sondern daß es dir helfen kann zu verstehen, was in deinem Code passiert, wenn du an der fraglichen Stelle in den Komponentencode hineinsteppst.