AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Rückgabe-Typ anpassen?

Ein Thema von milos · begonnen am 30. Mär 2015 · letzter Beitrag vom 7. Apr 2015
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von milos
milos

Registriert seit: 14. Jul 2008
Ort: Bern (CH)
509 Beiträge
 
Delphi 11 Alexandria
 
#1

Rückgabe-Typ anpassen?

  Alt 30. Mär 2015, 15:45
Hallo,

ich arbeite gerade an einem JSON-Parser.

Dies wäre eigentlich kein Problem, wenn ich nicht verschiedene Datentypen einbauen wollen würde

Hier ein kommentiertes Beispiel aus wiki:
Code:
{
  "id": 1, // integer
  "name": "Foo", // string
  "price": 123, // integer
  "tags": [ // array
    "Bar", // array
    "Eek"  // array
  ],
  "stock": {
    "warehouse": 300, // string
    "retail": 20      // string
  }
}
Wie kann ich das am besten Lösen, dass ich alle Werte in der selben Klasse speichern kann, aber einen anderen Typen abspeichere?

Freundliche Grüsse
Milos
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: Rückgabe-Typ anpassen?

  Alt 30. Mär 2015, 16:25
Ähm, du willst einen JSON-Parser erstellen oder benutzen?

Eigentlich gibt es schon genug JSON-Parser für Delphi ...

Im Übrigen sind die Kommentare nicht ganz korrekt:
Code:
{
  "id": 1, // integer
  "name": "Foo", // string
  "price": 123, // number
  "tags": [ // array
    "Bar", // array-item string
    "Eek" // array-item string
  ],
  "stock": { // object
    "warehouse": 300, // number
    "retail": 20      // number
  }
}
Zwingende Basis-Lektüre ist hier auch http://json.org
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo (30. Mär 2015 um 16:37 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#3

AW: Rückgabe-Typ anpassen?

  Alt 30. Mär 2015, 16:32
Zitat:
Code:
  "stock": { // object
    "warehouse": 300, // integer
    "retail": 20      // integer
  }


[add]
Zwingende Basis-Lektüre ist hier auch http://json.org
Ich glaub diese Lektüre haben zu viele JSON-Parser-Entwickler (außerhalb der Welt von JavaScript und kompatiblen dynamischen Sprachen) zu wörtlich genommen.
True und False als einzelne Objekte
[/add]

Zitat:
Ähm, du willst einen JSON-Parser erstellen oder benutzen?
Gute Frage ... wenn wirklch "erstellen", dann:



Variant und TValue können mehrere "Typen" speichern

oder du reagierst auf den Typen und speicherst dann den "Wert" in einer entsprechenden Variable, ähnlich einem varianten Array.
> String, Double, Array/Objekt, ...

Aber warum schaust du nicht einfach bei anderen Delphi-JSON-Libs ab?
z.B. http://sourceforge.net/projects/lkjson/

(ich weiß jetzt nicht, welche Lib Delphi integriert hat)






Warum baut eigentlich jeder einen JSON-Parser?



*hust*
http://svn.geheimniswelten.de:8080/svn/JSON/ (nicht fertig)
Ich hab mich entschieden die "Werte" als String zu speichern. (im Prinzip ist es im JSON dann eh alles ein String)


Wobei ich keinen JSON-Parser bastel (OK, der TJSONReader ist eine Art SAXParser), sondern ein echtes DOM, welches vollständig bearbeitbar ist.
Das Projekt war aber eigentlich entstanden, um die Speicherverwaltung im Multiplattform an einem praktischen Beispiel zu testen.
Siehe die vielen Tickets ala http://www.delphipraxis.net/184063-m...interface.html

Es gibt dazu dbald auch mal einen Artikel über JSON, JavaScript, Delphi, wie das drüben ist, also im JavaScript und vielleicht auch anderswo, und warum das JavaScript-Objekt-Model-Prinzip (nur serialisieren und deserialisieren) nicht unbedingt mit Delphi kompatibel ist.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (30. Mär 2015 um 16:38 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: Rückgabe-Typ anpassen?

  Alt 30. Mär 2015, 16:43
Warum sollte da was mit Delphi nicht kompatibel sein?

Wenn dem so ist, dann ist Delphi auch nicht mit XML bis hin zu einem Binär-Daten-Format kompatibel (ja, serialisieren).
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#5

AW: Rückgabe-Typ anpassen?

  Alt 30. Mär 2015, 16:57
Weil Delphi keine dynamischen Typen erlaubt?
'ne Variable, wo wirklich alles rein passt und das beliebig verschachtelbar ... das kennt Pascal nativ erstmal nicht.

Ein Variant kann zwar einfache Typen und Arrays enthalten und Objekte, aber nativ keine benamten Objekte, außer man klemmt z.B. ein Dictionary dazwschen.

In JavaScript kann man JSON einfach so deserialisieren und JS baut dann dynmaisch ein Objekt auf, Anhand der gefundenen "Property"-Namen.
Dort ist es eben möglich zur Laufzeit das Objekt umzubauen, was in einer statischen Sprache, wie z.B. Delphi, einfach nicht möglich ist, außer man baut sich dort entsprechende Wrapper-Klassen, so wie sie in fast jedem JSON-Parser enthalten sind.

Entweder man muß der JSON-Deserialisierung geziehlt ein Objkekt/Klasse geben, was schon vorher die nötige Struktur besitzt, oder man baut eben Datenhaltungsklassen in den Baum (ala TJsonObject oder TJsonValuse, wie sie meistens heißen).
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (30. Mär 2015 um 17:03 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: Rückgabe-Typ anpassen?

  Alt 30. Mär 2015, 17:00
Ja, das gleiche Problem hat man mit XML, CSV, Ini-Dateien, ... Binär-Daten.

Aber Java scheint ja eine Zaubersprache zu sein. Da kann man einfach so irgendein JSON rüberschicken und schwupps kann die Anwendung sofort das korrekt interpretieren?

Oder muss selbst bei Java der Kontext klar sein? Was bringt mir die dynamische Instanz, wenn die Anwendung die Eigenschaft "wuppdi" nicht kennt und somit nicht verarbeiten kann? Ich würde mal sagen: Nichts.

Denn die statische Klasse ohne wuppdi Eigenschaft ist genauso gut/schlecht wie die dynamische Klasse mit der Eigenschaft, die aber von der Anwendung nicht berücksichtigt wird.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo (30. Mär 2015 um 17:08 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#7

AW: Rückgabe-Typ anpassen?

  Alt 30. Mär 2015, 17:14
Nein, CSV und XML sind per se "nur" ein Datenformat und in diesem Format ist keine Implementierung vorgegeben, wie man das im Programm verarbeiten soll.

JSON ist eine Serialisierung von JavaScript-Klassen/Variablen und Delphi kann mit derartigen dynamischen Objektstrukturen nix anfangen.
Daß man dieses jetzt für einen systemübergreifenden Datentransfer und somit als "Datenformat" benutzt, ist eine andere Sache.

Die meisten Delphi-Implementationen sind "nur" zum Auslesen oder Erstellen, bzw. Serialaisieren/Deserialisieren gedacht, aber zum direkten Verarbeiten sind Viele einfach ungeeignet/umständlich.



Genau darum bastel ich mir auch ein JSON-DOM, ähnlich den bekannten XML-DOMs, um das einfacher benutzten und vorallem "editieren" zu können, ohne daß man das JSON erst in ein externes "unbekanntes" Delphi-Objekt deserialisieren muß, bzw. ohne das neu aufbauen/kopieren zu müssen.

Fast alle JSON-ReaderImplementationen für Delphi sind quasi read-only oder write-only und es ist, vorallem bei den delphieigenen JSON-Klassen (siehe DBX/DataSnap), recht umständlich aus einem True ein False zu machen.
Ist ja so, als wenn man XML als String mit Pos und Copy versucht zu verarbeiten.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (30. Mär 2015 um 17:27 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von milos
milos

Registriert seit: 14. Jul 2008
Ort: Bern (CH)
509 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Rückgabe-Typ anpassen?

  Alt 3. Apr 2015, 01:14
Habe nun einen kleinen Parser gebastelt der ohne Variant Booleans, Integers und Strings zurückgeben kann.
Leider habe ich keine Ahnung wie ich damit nochmal ein ganzes Objekt oder Variable zurückgeben kann.

Ich habe vor die Klasse zum lesen und schreiben benutzen zu können.
Ist mein Ansatz brauchbar?
Source Code: (Projektdaten auch hochgeladen)
Delphi-Quellcode:
unit JsonObject;

interface

uses
  System.SysUtils, Generics.Collections;

type
  TJsonType = ( jntBoolean,
                jntInteger,
                jntString );

  TJsonValue = class
  private
    FValue : string;
    function FGetType : TJsonType;
  public
    procedure GetBoolean(var AOutput : boolean);
    procedure GetInteger(var AOutput : integer);
    procedure GetString(var AOutput : string);

    procedure Assign(AValue : string);
    property ValueType : TJsonType read FGetType;
  end;

  TJsonNodes = class
  protected
  public
    Values : TDictionary<string, TJsonValue>;
    constructor Create();
  end;

  TJsonParser = class(TJsonNodes)
  private
  protected
    FJson : string;
  public
    constructor Create();
    procedure Assign(AJson : string);
    procedure Parse(AJson : string); overload;
    procedure Clear();
    procedure Parse(); overload;
    property Json : string read FJson;
  end;

implementation

{ TJsonParser }

procedure TJsonParser.Assign(AJson: string);
begin
  FJson := AJson;
end;

procedure TJsonParser.Parse(AJson: string);
begin
  FJson := AJson;
  Parse();
end;

procedure TJsonParser.Clear;
var
  CurrentCharIndex: Integer;
  CurrentChar : char;
  OutputString : string;
  InString : boolean;
begin
  InString := False;

  for CurrentCharIndex := 1 to Length(FJson) do
  begin
    CurrentChar := FJson[CurrentCharIndex];

    if (CurrentChar = '"') then
      InString := not InString;

    if ((CurrentChar = ' ') and (InString = false)) or
       ((CurrentChar = #10) or (CurrentChar = #13)) then
      Continue;

    OutputString := OutputString + CurrentChar;
  end;
  FJson := OutputString;
end;

constructor TJsonParser.Create;
begin
  inherited Create;

end;

procedure TJsonParser.Parse;
var
  CurrentCharIndex: Integer;
  CurrentChar : char;

  LineStarted : boolean;

  IndexDone : boolean;
  InIndex : boolean;

  InValue : boolean;
  ValueDone : Boolean;

  InString : boolean;

  LJsonValue : TJsonValue;

  StringBuffer : string;

  LastAdded : string;
begin
  Clear;

  LineStarted := false;

  IndexDone := false;
  InIndex := false;

  InValue := false;
  ValueDone := false;

  InString := False;

  for CurrentCharIndex := 1 to Length(FJson) do
  begin
    CurrentChar := FJson[CurrentCharIndex];


   if (CurrentChar = ',') or (CurrentChar = '}') then
    begin
      if InString then
        raise Exception.Create('String should be ended')
      else if InIndex then
        raise Exception.Create('Index should be ended')
      else if IndexDone and not ValueDone then
        raise Exception.Create('Value should be setted')
      else
      begin
        LineStarted := false;

        IndexDone := false;
        InIndex := false;

        InValue := false;
        ValueDone := false;

        InString := False;


            Values[LastAdded].Assign(StringBuffer);
            StringBuffer := '';
            InValue := false;

        StringBuffer := '';
      end;
    end;


    if not LineStarted then
    begin
      if CurrentChar = '"then
      begin
        InIndex := true;
        LineStarted := true;

        LJsonValue := TJsonValue.Create;

        Continue;
      end;
    end;

    if LineStarted then
    begin
      if (InIndex) and (not InValue) then
      begin
        if not(CurrentChar = '"') then
        begin
          StringBuffer := StringBuffer + CurrentChar;
          Continue;
        end
        else
        begin
          InIndex := false;
          Values.Add(StringBuffer, LJsonValue);
          LastAdded := StringBuffer;
          StringBuffer := '';
          Continue;
        end;
      end
      else if (not InIndex) and (not InValue) then
      begin
        if CurrentChar = ':then
        begin
          InValue := true;
          Continue;
        end;
      end
      else if (not InIndex) and (InValue) then
      begin
        StringBuffer := StringBuffer + CurrentChar;
      end;

    end;


  end;
end;

{ TJsonValue }

procedure TJsonValue.Assign(AValue: string);
begin
  FValue := AValue;
end;

function TJsonValue.FGetType: TJsonType;
begin
  if (FValue = 'true') or
     (FValue = 'false') then
     Result := jntBoolean;

end;

procedure TJsonValue.GetBoolean(var AOutput: boolean);
begin
  if (FValue = 'true') then
    AOutput := True
  else if (FValue = 'false') then
    AOutput := false
  else
    raise Exception.Create(FValue + ' is no Boolean');
end;

procedure TJsonValue.GetInteger(var AOutput: integer);
begin
  AOutput := StrToInt(FValue);
end;

procedure TJsonValue.GetString(var AOutput: string);
begin
  if (FValue[1] = '"') and
     (FValue[Length(FValue)] = '"') then
     AOutput := Copy(FValue, 2, Length(FValue)-2);
end;

{ TJsonNodes }

constructor TJsonNodes.Create;
begin
  Values := TDictionary<string, TJsonValue>.Create();
end;

end.
Delphi-Quellcode:
...

    Json : TJsonParser;

...

procedure TForm1.btn1Click(Sender: TObject);
var
  LValueID : integer;
  LValueAge : integer;
  LValueName : string;
  LValueURL : string;
  LValueValid : Boolean;
begin
  Json := TJsonParser.Create;
  Json.Assign(mmo1.Text);
  Json.Parse;
  mmo1.Text := Json.Json;


  Json.Values['id'].GetInteger(LValueID);
  Json.Values['age'].GetInteger(LValueAge);

  Json.Values['name'].GetString(LValueName);
  Json.Values['url'].GetString(LValueURL);

  Json.Values['valid'].GetBoolean(LValueValid);

  Showmessage(IntToStr(LValueID));
  Showmessage(IntToStr(LValueAge));
  Showmessage(LValueName);
  Showmessage(LValueURL);

  if LValueValid then
    Showmessage('Valid')
  else
    Showmessage('Invalid');

end;
Json code der so funktioniert:
Code:
{
  "id": 1,
  "age": 18,
  "name": "Milos",
  "url": "http://delphipraxis.net",
  "valid": true
}
Was haltet ihr von dem ansatz?
Was würdet ihr anders machen?

MfG
Angehängte Dateien
Dateityp: zip JsonTest.zip (58,2 KB, 2x aufgerufen)
Milos

Geändert von milos ( 3. Apr 2015 um 01:30 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#9

AW: Rückgabe-Typ anpassen?

  Alt 3. Apr 2015, 08:07
Dein Zurückgeben geht und man kann es auch so machen,
wobei es natrülich etwas doppelt gemoppelt ist, da der Compiler anhand der Signatur (die Typen der Parameter, aber nicht des Results) auch automatisch unterscheiden kann. (overload)
Delphi-Quellcode:
procedure GetValue(var AOutput : boolean); overload;
procedure GetValue(var AOutput : integer); overload;
procedure GetValue(var AOutput : string); overload;
Delphi-Quellcode:
function GetBoolean: boolean;
function GetInteger: integer;
function GetString: string;
Leider habe ich keine Ahnung wie ich damit nochmal ein ganzes Objekt oder Variable zurückgeben kann.
Was ist Variable?

procedure GetValue(AOutput TMyObject); overload;
Hier kann man bei einem besehendem Objekt die Parameter auslesen, man kann auch Parameter zuwisen/ändern und natürlich Methoden aufrufen,
aber die Instanz muß extern erstellt und reingegeben werden.
Die Instanz wird natürlich auch extern freigegeben, am Besten in der selben Ebene, wie das Erstellen.
procedure GetValue(var AOutput TMyObject); overload;
Wie vorherriges, außer daß man z.B. bei if noch Assigned(AOutput) then intern eine neue Instanz erstellen kann.
Von extern kommt also entweder ein Objekt oder nil rein. Und man kann intern das externe Objekt auch freigeben (FreeAndNil) und/oder ein Neues erstellen.
function GetOject: TMyObject;
Hier wird das Objekt ausschließlich intern erstellt.
Freigeben muß es dann entweder der Aufrufer und ruft am Ende Free auf. (siehe Delphi-Referenz durchsuchenGetMemory)
Oder der Ersteller ist Owner, verwaltet es intern und gibt es am Ende selbst frei, z.B. wenn er selber freigegeben wird. (siehe Memo.Lines oder Memo.Font).
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 3. Apr 2015 um 08:14 Uhr)
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#10

AW: Rückgabe-Typ anpassen?

  Alt 3. Apr 2015, 11:03
Ähm, du willst einen JSON-Parser erstellen oder benutzen?

Eigentlich gibt es schon genug JSON-Parser für Delphi ...
Mal etwas OT. Ist die Aussage richtig? Als ich das letzte Mal auf die Idee kam mal JSON auszuprobieren, hat nichts, aber auch wirklich nichts mit Delphi 7 problemlos funktioniert. Irgendwann gab ich es auf. Gibt es inzwischen so große Auswahl, dass ich es erneut versuchen kann und der TE drauf verzichten kann etwas neues zu schreiben?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:36 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