Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   RestServer Antwort Json ohne "[" Klammern (https://www.delphipraxis.net/188108-restserver-antwort-json-ohne-%5B-klammern.html)

ScharfeMietze 1. Feb 2016 14:37

RestServer Antwort Json ohne "[" Klammern
 
Ich muss euch nochmal stören.

Ich habe eine Serverantwort in Json von einem Rest server
Code:
{"result":["Test<\u00F6\u00E4\u00FC\u00F6\u00E4\u00FC>7"]}
1["Test<öäüöäü>7"]
Serverseite zum Üben

Delphi-Quellcode:
function TServerMethods1.updateEchoAttribute1(Key, Obj: string): String;
begin
Result:= Key + '<öäüöäü>' + Obj;
end;
Nun möchte ich die "reine" Antwort. Bisher habe ich das mit RegEx erschlagen und möchte es nun aber gerne über den Json way probieren.

Delphi-Quellcode:
var
  LJSONObject: TJSONObject;
  RestResponse: string;
begin
RestResponse:= '{"result":["Test<\u00F6\u00E4\u00FC\u00F6\u00E4\u00FC>7"]}';
LJSONObject := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(RestResponse), 0) as TJSONObject;
mmo1.Lines.Add(LJSONObject.Values['result'].ToString);
end;

Die schlichte Frage ist wie bekomme ich die -->[" und "]<-- Klammern/Gänsefüßchen entfernt.

Ich hoffe ihr könnt helfen.

lieben Gruß
SM;)

himitsu 1. Feb 2016 14:40

AW: RestServer Antwort Json ohne "[" Klammern
 
Kann es sein, dass es dazu vor Kurzem schonmal einen Thread gab? :?


ToString wird das JSON-"Objekt" als Text zurück geben.

Es gibt aber bestimmt ein Value oder AsString, das den Wert liefert. :stupid:

ScharfeMietze 1. Feb 2016 15:18

AW: RestServer Antwort Json ohne "[" Klammern
 
Genau das ist ja mein problemchen
Delphi-Quellcode:
mmo1.Lines.Add(LJSONObject.Values['result'].ToString);
liefert MIT besagten Zeichen
Code:
["Test<öäüöäü>7"]

Sir Rufo 1. Feb 2016 15:29

AW: RestServer Antwort Json ohne "[" Klammern
 
Delphi-Quellcode:
ToString
ist von der Definition her dafür da, die Instanz als String darzustellen.

Das willst du aber nicht, du willst den Wert.

Delphi-Quellcode:
TJSONObject.Values[...]
liefert ein
Delphi-Quellcode:
TJSONValue
und wenn das vom Type ein
Delphi-Quellcode:
TJSONString
ist, dann bekommt man bei
Delphi-Quellcode:
TJSONString.Value
auch den gesuchten String-Wert.

EDIT Stop, Kommando zurück, du hast dort ein
Delphi-Quellcode:
TJSONArray
und der erste Wert ist dann ein
Delphi-Quellcode:
TJSONString
;)

ScharfeMietze 1. Feb 2016 15:36

AW: RestServer Antwort Json ohne "[" Klammern
 
Magst mich gerade noch Aufklären wie ich mit einem solchen Array umzugehen habe?
Da bin ich noch Jungfräulich

Gruß
SM;)

himitsu 1. Feb 2016 15:38

AW: RestServer Antwort Json ohne "[" Klammern
 
Und jetzt nochmal meine Antwort lesen. :roll:
















Zitat:

Delphi-Quellcode:
function Value: string; virtual;
function ToJSON: string;
function ToString: string; override;
//uvm.


Sir Rufo 1. Feb 2016 15:47

AW: RestServer Antwort Json ohne "[" Klammern
 
Und wenn du von der gleichen Faulheit befallen bist wie ich, dann sparst du dir diesen gesamten Fuddelkram mit
Delphi-Quellcode:
unit Unit2;

interface

uses
  REST.Json.Types; // <- da sind die Json-Attribute definiert

type
  TResponseJSON = class
  private
    [ JsonName( 'result' ) ]
    FResultArray: TArray<string>;
  public
    property ResultArray: TArray<string> read FResultArray;
  end;

implementation

end.
und verarbeitest das ganz gemütlich mit
Delphi-Quellcode:
program foo;

uses
  System.SysUtils,
  REST.Json, // <- da ist TJson definiert
  Unit2 in 'Unit2.pas';

procedure Test;
var
  lResponse: TResponseJSON;
begin
  lResponse := TJson.JsonToObject<TResponseJSON>( '{"result":["Test<\u00F6\u00E4\u00FC\u00F6\u00E4\u00FC>7"]}' );
  try
    WriteLn( lResponse.ResultArray[ 0 ] );
  finally
    lResponse.Free;
  end;
end;

begin
  try
    Test;
  except
    on E: Exception do
      WriteLn( E.ClassName, ': ', E.Message );
  end;
  ReadLn;
end.
Weil einfach einfach einfach ist :stupid:

Sir Rufo 1. Feb 2016 15:56

AW: RestServer Antwort Json ohne "[" Klammern
 
TsTsTs ... muss man immer alles dreimal sagen
http://www.delphipraxis.net/1328714-post6.html

:stupid:

himitsu 1. Feb 2016 15:56

AW: RestServer Antwort Json ohne "[" Klammern
 
Nur zum Test.
Delphi-Quellcode:
S := (LJSONObject.Values['result'] as TJSONArray).Items[0].Value;
?

ScharfeMietze 1. Feb 2016 15:59

AW: RestServer Antwort Json ohne "[" Klammern
 
@himitsu

Doch gelesen habe ich es aber meine Versuche mit
Delphi-Quellcode:
mmo1.Lines.Add('2' + LJSONObject.Values['result'].Value);
scheitern. Ich bekomme '' als Antwort.

Wenn ich probiere dort gerade alles durch

edit: gerade den Post gesehen ... probier ich gleich


SirRufo :) das seh ich mir gleich mal an ^^ :)))))

Gruß
SM;)

ScharfeMietze 1. Feb 2016 16:03

AW: RestServer Antwort Json ohne "[" Klammern
 
himitsu du bist echt ein Gott/Göttin!!!
Delphi-Quellcode:
S := (LJSONObject.Values['result'] as TJSONArray).Items[0].Value; ?
funktioniert SUPER!!!!!!!!

Danke dir!!!!
Gruß
SM;)

PS: Troz allem werde ich SirRufos Code auch testen, allein um des lernens Willen !!!

himitsu 1. Feb 2016 16:54

AW: RestServer Antwort Json ohne "[" Klammern
 
Aber nimm's nicht so schwer.
Ich fand die geklaute Implementation vom Embarcadero schon vom ersten Tag an Schrott, also was das Manuelle betrifft.

Der Wrapper von/zu den Datenobjekten ist halbweg bauchbar.
Geht allerdins nur, wenn man zur Designtime die Struktur kennt und passende Records/Datenobjekte schreibt. (dynamisch, zur Laufzeit was entscheiden, ist da dann nichts)

ScharfeMietze 1. Feb 2016 17:15

AW: RestServer Antwort Json ohne "[" Klammern
 
Da ich mit dem RestServer erst beginne und ihn nur für mich privat brauchen werde, ist das zum üben vollkommen ausreichend.
Ich danke dir nochmal!!

Gruß
SM;)

Sir Rufo 1. Feb 2016 17:24

AW: RestServer Antwort Json ohne "[" Klammern
 
@himitsu

Wenn du von der API ständig überrascht wirst, was die so an Strukturen heraushaut, dann solltest du die API nochmal prüfen.

Und egal was die zurückliefert, die Struktur muss irgendwie bekannt sein, denn wie will man den Inhalt verarbeiten, wenn man nicht weiß, was der Inhalt bedeutet.

himitsu 2. Feb 2016 09:41

AW: RestServer Antwort Json ohne "[" Klammern
 
Ja, die Struktur muß bekannt sein, aber ich meine eher so, daß man bei den Klassen nicht zur Laufzeit eine andere Struktur nehmen kann, ohne schon vorher mehrere Klassen geschrieben zu haben.

Sir Rufo 2. Feb 2016 10:47

AW: RestServer Antwort Json ohne "[" Klammern
 
Zitat:

Zitat von himitsu (Beitrag 1329042)
Ja, die Struktur muß bekannt sein, aber ich meine eher so, daß man bei den Klassen nicht zur Laufzeit eine andere Struktur nehmen kann, ohne schon vorher mehrere Klassen geschrieben zu haben.

Ja ... aber das kommt doch auf das Gleiche hinaus.

Ich kann die Nachricht per Hand auseinandernehmen (dazu muss mir aber die Struktur zur DesignTime bekannt sein) oder die Nachricht in eine Klasse schreiben lassen (die ich nur schreiben kann, wenn mir die Struktur zur DesignTime bekannt ist).

Der große Unterschied ist, dass ich bei der Verwendung von Klassen mit einer Zeile Code die Nachricht in einer Struktur habe, die ich in der Anwendung sehr einfach verarbeiten kann.

Ohne schreibe ich jede Menge Code (mit potentiellen Fehlern) und schleppe eventuell sogar das JSON-Zeug kreuz und quer durch meine Anwendung.

Und wenn sich an der Nachricht etwas ändert, dann kann man an n(+?) Stellen im Code suchen, wo denn das jetzt alles geändert werden muss.

Bei der Verwendung von Klassen, kann ich diese Änderungen entweder verstecken oder finde sehr schnell die Stellen, wo mit so einer Instanz gearbeitet wird.

mquadrat 2. Feb 2016 11:49

AW: RestServer Antwort Json ohne "[" Klammern
 
Es kommt immer drauf an, wer die API geschrieben hat. Kam der Autor aus einer typsicheren Sprache, dann hält sich auch die API an ein definiertes Schema. Kommt der Autor aus einer der dynamischen Sprachen (oder kommen die Daten aus einer NoSQL-DB) dann kann sich die Struktur schon mal ändern.

Bei Shopware z.B. unterscheidet sich die Definition einer Ressource zwischen lesenden und schreibenden Zugriffen. Da hat dann z.B. ein Feld einen anderen Typ. Sowas ist furchtbar nervig, weil man für jede Variante dann eine Klasse haben muss, in die man serialisieren kann.

Sir Rufo 2. Feb 2016 13:25

AW: RestServer Antwort Json ohne "[" Klammern
 
Nunja, grundsätzlich ist das ja kein Problem (ja ein bisserl Tipparbeit mit den Klassen) wenn man es sich schon mal vorab gemütlich macht.
Delphi-Quellcode:
unit Unit1;

interface

uses
  System.Generics.Collections,
  System.SysUtils,
  REST.Json.Types;

type { internal data object }
  TFooData = class
  private
    FNumber: Integer;
  public
    property Number: Integer read FNumber write FNumber;
  end;

type { api objects }
  TFooWriteJson = class
  private
    [ JsonName( 'number_write' ) ]
    FNumber: string;
  public
    property Number: string read FNumber write FNumber;
  end;

  TFooReadJson = class
  private
    [ JsonName( 'number_read' ) ]
    FNumber: Integer;
  public
    property Number: Integer read FNumber write FNumber;
  end;

type
  TJsonSerializer = class abstract
  private type
    TConverter = record
      ClassType: TClass;
      Convert: TFunc<TObject, TObject>;
    end;
  private
    FConverterMap: TDictionary<TClass, TConverter>;
    FReverterMap : TDictionary<TClass, TConverter>;
  protected
    procedure RegisterConverter<TSource: class; TResult: class>( Converter: TFunc<TSource, TResult> );
    procedure RegisterConverterReverter<TSource: class; TResult: class, constructor>( Converter: TFunc<TSource, TResult>; Reverter: TFunc<TResult, TSource> );
    procedure RegisterReverter<TSource: class; TResult: class, constructor>( Converter: TFunc<TResult, TSource> );
  public
    constructor Create; virtual;
    destructor Destroy; override;

    function Serialize<T: class>( AObject: T ): string;
    function Deserialize<T: class>( const JsonStr: string ): T;
  end;

type
  TConcreteSerializer = class( TJsonSerializer )
  public
    constructor Create; virtual;
  end;

implementation

uses
  REST.Json,
  System.Json;

{ TJsonSerializer }

constructor TJsonSerializer.Create;
begin
  inherited;
  FConverterMap := TDictionary<TClass, TConverter>.Create;
  FReverterMap := TDictionary<TClass, TConverter>.Create;
end;

function TJsonSerializer.Deserialize<T>( const JsonStr: string ): T;
var
  lConverter: TConverter;
  lJson    : TJsonObject;
  lSerObj  : TObject;
begin
  if not FReverterMap.TryGetValue( T, lConverter )
  then
    raise Exception.Create( 'Fehlermeldung' );

  lJson := TJsonObject.ParseJSONValue( JsonStr ) as TJsonObject;
  try
    lSerObj := lConverter.ClassType.Create;
    try
      TJson.JsonToObject( lSerObj, lJson );

      Result := lConverter.Convert( lSerObj ) as T;

    finally
      lSerObj.Free;
    end;
  finally
    lJson.Free;
  end;
end;

destructor TJsonSerializer.Destroy;
begin
  FConverterMap.Free;
  FReverterMap.Free;
  inherited;
end;

procedure TJsonSerializer.RegisterConverter<TSource, TResult>( Converter: TFunc<TSource, TResult> );
var
  lConverter: TConverter;
begin
  lConverter.ClassType := TResult;
  lConverter.Convert  :=
    function( Source: TObject ): TObject
    begin
      Result := Converter( Source as TSource );
    end;
  FConverterMap.Add( TSource, lConverter );
end;

procedure TJsonSerializer.RegisterConverterReverter<TSource, TResult>( Converter: TFunc<TSource, TResult>; Reverter: TFunc<TResult, TSource> );
begin
  RegisterConverter<TSource, TResult>( Converter );
  RegisterReverter<TSource, TResult>( Reverter );
end;

procedure TJsonSerializer.RegisterReverter<TSource, TResult>( Converter: TFunc<TResult, TSource> );
var
  lConverter: TConverter;
begin
  lConverter.ClassType := TResult;
  lConverter.Convert  :=
    function( Source: TObject ): TObject
    begin
      Result := Converter( Source as TResult );
    end;
  FReverterMap.Add( TSource, lConverter );
end;

function TJsonSerializer.Serialize<T>( AObject: T ): string;
var
  lConverter: TConverter;
  lSerObj  : TObject;
begin
  if not FConverterMap.TryGetValue( AObject.ClassType, lConverter )
  then
    raise Exception.Create( 'Fehlermeldung' );

  lSerObj := lConverter.Convert( AObject );
  try
    Result := TJson.ObjectToJsonString( lSerObj );
  finally
    lSerObj.Free;
  end;
end;

{ TConcreteSerializer }

constructor TConcreteSerializer.Create;
begin
  inherited;

  RegisterConverter<TFooData, TFooWriteJson>(
    function( s: TFooData ): TFooWriteJson
    begin
      Result := TFooWriteJson.Create;
      Result.Number := IntToStr( s.Number );
    end );

  RegisterReverter<TFooData, TFooReadJson>(
    function( s: TFooReadJson ): TFooData
    begin
      Result := TFooData.Create;
      Result.Number := s.Number;
    end );
end;

end.
Dann geht das nachher alles wie von selber
Delphi-Quellcode:
procedure Test;
var
  lSer : TJsonSerializer;
  lfoo : TFooData;
  lData: string;
begin
  lSer := TConcreteSerializer.Create;
  try

    lfoo := TFooData.Create;
    try
      lfoo.Number := 42;
      lData      := lSer.Serialize( lfoo );
    finally
      lfoo.Free;
    end;

    WriteLn( lData ); // {"number_write":"42"}

    lData := '{"number_read":42}';

    lfoo := lSer.Deserialize<TFooData>( lData );
    try
      WriteLn( lfoo.Number );
    finally
      lfoo.Free;
    end;

  finally
    lSer.Free;
  end;
end;

ScharfeMietze 3. Feb 2016 11:52

AW: RestServer Antwort Json ohne "[" Klammern
 
https://www.youtube.com/watch?v=DdW8zssbQ0g
In diesem Vido wird beschrieben das auf einem Rest Server
Delphi-Quellcode:
function EchoJson: TJSONObject;
TJSONObject als Result dienen kann.
Es wird mittels
Delphi-Quellcode:
Result := TJSONObject.create erzeugt
allerdings findet sich logischerweise nirgends ein .free.

Meine Frage an die Profis ist nun ob ich das so auch gefahrlos in jeder function so verwenden kann.
Ich erinnere mich an TStringlisten als result, die dann Leaks erzeugt haben.

Grüße
SM;)

Sir Rufo 3. Feb 2016 12:00

AW: RestServer Antwort Json ohne "[" Klammern
 
Natürlich erzeugt das ein MemLeak, wenn du das nicht entsprechend behandlest und beim Aufruf der Funktion auch die LifeTime-Management-Verantwortung für das Ergebnis übernimmst.

Ist exakt das Gleiche wie bei
Delphi-Quellcode:
function BuildObject : TObject;
begin
  Result := TObject.Create;
end;

var
  lObj: TObject;
begin
  TObject.Create; // <= MemLeak
  BuildObject(); // <= MemLeak;

  // keine MemLeaks mit

  lObj := TObject.Create;
  try
    // ...
  finally
    lObj.Free;
  end;

  lObj := BuildObject();
  try
    // ...
  finally
    lObj.Free;
  end;
end;
Es gibt noch einen kleinen Unterschied:

Wenn beim Erzeugen der Instanz ein Problem auftritt, dann soll man auch dafür sorgen, dass die Instanz aufgeräumt wird (so wie das auch der
Delphi-Quellcode:
constructor
macht);
Delphi-Quellcode:
function BuildObject: TObject;
begin
  Result := TObject.Create; // <= Bei einer Excpetion gibt es keine Instanz
  try
    // hier noch beim Result-Object weitere Eigenschaften setzen
    // hier könnte es zu einer Exception kommen
  except
    Result.Free; // <= bei einer Exception, wird die Instanz verworfen
    raise; // <= und die Exception wieder ausgelöst
  end;
end;

ScharfeMietze 3. Feb 2016 12:29

AW: RestServer Antwort Json ohne "[" Klammern
 
Perfect!! Danke für die Antwort. Das sind immer diese Fehlerteufel wenn man es nicht beachtet und dann das Wundern losgeht.

Gruß
SM;)

ScharfeMietze 3. Feb 2016 13:07

AW: RestServer Antwort Json ohne "[" Klammern
 
Dann könnte die function so aussehen
Delphi-Quellcode:
function TServerMethods1.updateHddCrawler(Key: string; aJSONObject: TJSONObject): TJSONObject;
var
  LJSONObject: TJSONObject;
  s: string;
begin
Result := TJSONObject.Create;
  try
   if KeyValidation(Key) then frmHddCrawler.AnalyzeJson(aJSONObject,Result)
   else Result.AddPair('error', 'invalid key') ;
  except
   Result.Free;
   raise;
  end;
end;
Einwände?

Sir Rufo 3. Feb 2016 13:16

AW: RestServer Antwort Json ohne "[" Klammern
 
Was die Erzeugung der Result-Instanz angeht -> Nein.

Der Rest sieht seltsam aus :stupid:

ScharfeMietze 3. Feb 2016 13:50

AW: RestServer Antwort Json ohne "[" Klammern
 
Jap! Zum Testen an sich nutze ich gerne Formen. Vor allem in der Planung. Dann kann ich mir auch mal per button Inhalte ausgeben lassen, oder auch mal eine kleine Testroutine einpflegen.
Oder meintest du was anderes?

Sir Rufo 3. Feb 2016 14:08

AW: RestServer Antwort Json ohne "[" Klammern
 
Auch ...

Du willst doch etwas konkretes
Delphi-Quellcode:
frmHddCrawler.Analyze
erledigen und übergibst dafür irgendwas
Delphi-Quellcode:
TJSONObject
.

Delphi-Quellcode:
ICrawlHdd = interface
  function Analyze( request : THddCrawlerRequest ) : THddCrawlerResponse;
end;

function TServerMethods1.updateHddCrawler(Key: string; aJSONObject: TJSONObject): TJSONObject;
var
  request: THddCrawlerRequest;
  response: THddCrawlerResponse;
  error : TErrorResponse;
begin
  // Prüfung ob die Daten im Json zum Aufruf passen
  request := TJson.JsonToObject<THddCrawlerRequest>( aJSONObject );
  try
   if KeyValidation(Key) then
   begin
     // Dienst fragen
     response := HddCrawlerService.Analyze( request );
     try
       // Ergebnis in Json umwandeln
       Result := TJson.ObjectToJsonObject( response );
     finally
       response.Free;
     end;
   end
   else
     begin
       error := TErrorResponse.Create( 'invalid key' );
       try
         Result := TJson.ObjectToJsonObject( error );
       finally
         error.Free;
       end;
     end;
  finally
    request.Free;
  end;
end;
Wer jetzt den
Delphi-Quellcode:
ICrawlHdd
genau ausführt, kann dir egal sein. Und ob die Daten irgenwann mal per JSON gekommen sind, ist dem Service jetzt auch egal. Der brauchst also kein JSON mehr zu kennen.

Als Service kannst du auch eine Form verwenden:
Delphi-Quellcode:
THddCrawlerForm = class( TForm, ICrawlHdd )
private { ICrawlHdd }
  function Analyze( request: THddCrawlerRequest ): THddCrawlerResponse;
end;

ScharfeMietze 3. Feb 2016 14:28

AW: RestServer Antwort Json ohne "[" Klammern
 
Ja das macht Sinn THX :)

Gruß
SM;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:57 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