Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Json Array of String: Wie Array-Items per Schleife auslesen (https://www.delphipraxis.net/213743-json-array-string-wie-array-items-per-schleife-auslesen.html)

juergen 18. Sep 2023 18:36

Json Array of String: Wie Array-Items per Schleife auslesen
 
Hallo,

mir fällt der Umgang mit Json noch ziemlich schwer. Ich habe 1 String-Array in der Json-Datei.
Folgendes Json (gekürzt).
Code:
{
    "Database": {
        "DB-ServerName": "",
        "DB-Name": "",
        "DB-User": "",
        "DB-User-Pw": 0,
        "DB-Provider": 0
    },
    "ShorthandSymbol": [
        "UxRT",
        "KuZT",
        "KpZR",
        "BFRS",
        "HKJD",
        "UDTR",
        "SI",
        "dgws",
        "DEFdg",
        "EIZ",
        "ITFd"
    ]
}
Ich habe den Json-Dateiinhalt in einem Json-Objekt:
Delphi-Quellcode:
...  
VAR
  my_jsonObj: TJSONObject;
BEGIN
 IF FileExists( ExtractFilePath( ParamStr( 0 ) ) + 'Settings.json' ) THEN
    BEGIN
      my_jsonObj := TJSONObject.ParseJSONValue( TFile.ReadAllText( ExtractFilePath( ParamStr( 0 ) ) + 'Settings.json' ) ) AS TJSONObject;
...
Jetzt muss ich irgendwie über eine Schleife (?) die einzelnen Stringwerte aus dem Array auslesen.

Wie komme ich an die einzelnen Json-String-Array-Werte?

Vielen Dank schon mal vorab.

Uwe Raabe 18. Sep 2023 19:13

AW: Json Array of String: Wie Array-Items per Schleife auslesen
 
Mit
Delphi-Quellcode:
my_jsonObj.Values['ShorthandSymbol'] as TJSONArray
kommst du schon mal an das Array. Dort kannst du dann einfach über den Index auf die einzelnen Elemente zugreifen.

juergen 18. Sep 2023 22:06

AW: Json Array of String: Wie Array-Items per Schleife auslesen
 
Vielen Dank, Uwe! :thumb:

Ich habe jetzt folgende Art einer Lösung:
Delphi-Quellcode:
ShowMessage( ( ( my_jsonObj.Values['ShorthandSymbol'] AS TJSONArray ).Items[1] ).ToString );
Das Ganze scheint zu funktionieren, aber irgendwie fühlt sich das für mich noch nicht richtig an.

mytbo 18. Sep 2023 23:12

AW: Json Array of String: Wie Array-Items per Schleife auslesen
 
Zitat:

Zitat von juergen (Beitrag 1527087)
Das Ganze scheint zu funktionieren, aber irgendwie fühlt sich das für mich noch nicht richtig an.

Lösung mit mORMot. Wenn die Eigenschaftsnamen in der JSON-Datei nach den Regeln für Pascal Feldnamen benannt sind, lässt es sich automatisch mappen:
Delphi-Quellcode:
uses
  mormot.core.base,
  mormot.core.text,
  mormot.core.json,
  mormot.core.os;

type
  TDBSettings = packed record
    DataBase: record
      DBServerName: String; // statt "DB-ServerName"
      DBName: String;
      DBUser: String;
      DBUserPw: Integer;
      DBProvider: Integer;
    end;
    ShorthandSymbol: TStringDynArray; // array of String
    function LoadFromFile(const pmcFileName: TFileName): Boolean;
    procedure SaveToFile(const pmcFileName: TFileName);
  end;

function TDBSettings.LoadFromFile(const pmcFileName: TFileName): Boolean;
begin
  Result := RecordLoadJson(Self, StringFromFile(pmcFileName), TypeInfo(TDBSettings));
end;

procedure TDBSettings.SaveToFile(const pmcFileName: TFileName);
begin
  FileFromString(RecordSaveJson(Self, TypeInfo(TDBSettings)), pmcFileName);
end;
Im Beispiel ist das nicht der Fall, es muss ein Custom-Serializer registriert werden:
Delphi-Quellcode:
uses
  mormot.core.base,
  mormot.core.data,
  mormot.core.text,
  mormot.core.json,
  mormot.core.rtti,
  mormot.core.os;

type
  TDBSettingDataBase = class(TObject)
  private
    FDBServerName: String;
    FDBName: String;
    FDBUser: String;
    FDBUserPw: Integer;
    FDBProvider: Integer;
  protected
    class procedure ReadDataBaseJson(var pmvContext: TJsonParserContext; pmValue: TObject);
    class procedure WriteDataBaseJson(pmWriter: TJsonWriter; pmValue: TObject; pmOptions: TTextWriterWriteObjectOptions);
  public
    property DBServerName: String
      read FDBServerName write FDBServerName;
    property DBName: String
      read FDBName write FDBName;
    property DBUser: String
      read FDBUser write FDBUser;
    property DBUserPw: Integer
      read FDBUserPw write FDBUserPw;
    property DBProvider: Integer
      read FDBProvider write FDBProvider;
  end;

  TDBSettings = class(TSynAutoCreateFields)
  private
    FDataBase: TDBSettingDataBase;
    FShorthandSymbol: TStringDynArray;
  public
    function LoadFromFile(const pmcFileName: TFileName): Boolean;
    procedure SaveToFile(const pmcFileName: TFileName);
  published
    property DataBase: TDBSettingDataBase
      read FDataBase;
    property ShorthandSymbol: TStringDynArray
      read FShorthandSymbol;
  end;

class procedure TDBSettingDataBase.ReadDataBaseJson(var pmvContext: TJsonParserContext; pmValue: TObject);
var
  values: array[0..4] of TValuePUtf8Char;
begin
  if pmvContext.ParseObject(['DB-ServerName', 'DB-Name', 'DB-User', 'DB-User-Pw', 'DB-Provider'], @values) then
  begin
    with TDBSettingDataBase(pmValue) do
    begin
      DBServerName := values[0].ToString;
      DBName := values[1].ToString;
      DBUser := values[2].ToString;
      DBUserPw := values[3].ToInteger;
      DBProvider := values[4].ToInteger;
    end;
  end;
end;

class procedure TDBSettingDataBase.WriteDataBaseJson(pmWriter: TJsonWriter; pmValue: TObject; pmOptions: TTextWriterWriteObjectOptions);
begin
  with TDBSettingDataBase(pmValue) do
    pmWriter.AddJsonEscape(['DB-ServerName', DBServerName, 'DB-Name', DBName, 'DB-User', DBUser, 'DB-User-Pw', DBUserPw, 'DB-Provider', DBProvider]);
end;

function TDBSettings.LoadFromFile(const pmcFileName: TFileName): Boolean;
begin
  Result := ObjectLoadJson(Self, StringFromFile(pmcFileName));
end;

procedure TDBSettings.SaveToFile(const pmcFileName: TFileName);
begin
  FileFromString(ObjectToJson(Self), pmcFileName);
end;

initialization
  TRttiJson.RegisterCustomSerializerClass(TDBSettingDataBase, TDBSettingDataBase.ReadDataBaseJson, TDBSettingDataBase.WriteDataBaseJson);
Und so anwenden:
Delphi-Quellcode:
with TDBSettings.Create do
try
  LoadFromFile('settings.json');
  ShowMessage(DataBase.DBServerName);

  DataBase.DBServerName := 'TestServer';
  SaveToFile('settings.json');
finally
  Free;
end;
Bis bald...
Thomas

himitsu 18. Sep 2023 23:26

AW: Json Array of String: Wie Array-Items per Schleife auslesen
 
Diese JSON-Klassen können auch sowas wie XPath.

https://docwiki.embarcadero.com/Libr...JSONPathParser
https://docwiki.embarcadero.com/Libr...ject.FindValue
...

mytbo 18. Sep 2023 23:39

AW: Json Array of String: Wie Array-Items per Schleife auslesen
 
Zitat:

Zitat von himitsu (Beitrag 1527095)
Diese JSON-Klassen können auch sowas wie XPath.

Etwa so:
Delphi-Quellcode:
var
  doc: TDocVariantData;
begin
  doc.InitJsonFromFile('settings.json');
  ShowMessage(doc.P['DataBase.DB-ServerName']);
Bis bald...
Thomas

juergen 19. Sep 2023 16:53

AW: Json Array of String: Wie Array-Items per Schleife auslesen
 
Zunächst vielen Dank!

@mytbo,
Je länger ich mir das anschaue, desto mehr gefällt es mir!:thumb:

Ich werde das heute Abend mal mit mORMot angehen.

mytbo 19. Sep 2023 17:37

AW: Json Array of String: Wie Array-Items per Schleife auslesen
 
Zitat:

Zitat von juergen (Beitrag 1527113)
Ich werde das heute Abend mal mit mORMot angehen.

mORMot gehört zu den qualitativ hochwertigsten Bibliotheken im Pascal Universum. Es sind unzählige Klassen und Funktionen zu finden. Um schnell ein Erfolgserlebnis zu haben, sollte man sich zu Beginn nur auf einen Teilbereich konzentrieren. In deinem Beispiel die JSON Serialisierung. Die Units sind wohl geordnet und strukturell logisch aufgebaut. Wenn man es verstanden hat, fügt sich alles wunderbar zusammen. Nur der Anfang, der ist schwer.

Die mORMot Bibliothek muss nicht installiert werden. Den aktuellen Commit und die static binaries aus dem letzten Tag herunterladen. In Delphi die entsprechenden Bibliotheks- und Suchpfade setzen. Beim Erstellen hilft dieses Muster:
Code:
// Die Doppelpunkte einfach durch den Speicherpfad ersetzten
..\src;..\src\app;..\src\core;..\src\crypt;..\src\db;..\src\lib;..\src\misc;..\src\net;..\src\orm;..\src\rest;..\src\script;..\src\soa;..\src\tools\ecc;..\src\ui;
Die aktuelle Entwicklung ist mORMot2. mORMot ist gut dokumentiert. Die Hilfe bezieht sich noch auf mORMot1. Die Namen für Klassen und Funktionen können sich leicht unterscheiden. Sie umfasst mehr als 2500 Seiten. Davon enthalten die ersten ca. 650 Seiten einen sehr lesenswerten allgemeinen Teil, der Rest ist API Dokumentation.

Bis bald...
Thomas

mytbo 19. Sep 2023 18:43

AW: Json Array of String: Wie Array-Items per Schleife auslesen
 
Um das Ganze abzuschließen, im konkreten Fall würde es reichen, die Eigenschaftsnamen für das Lesen und Schreiben der JSON-Datei zu ändern:
Delphi-Quellcode:
uses
  mormot.core.base,
  mormot.core.data,
  mormot.core.text,
  mormot.core.json,
  mormot.core.rtti,
  mormot.core.unicode,
  mormot.core.variants,
  mormot.core.os;
 
type
  TDBSettingDataBase = class(TSynPersistent)
  private
    FDBServerName: String;
    FDBName: String;
    FDBUser: String;
    FDBUserPw: Integer;
    FDBProvider: Integer;
  published
    property DBServerName: String
      read FDBServerName write FDBServerName;
    property DBName: String
      read FDBName write FDBName;
    property DBUser: String
      read FDBUser write FDBUser;
    property DBUserPw: Integer
      read FDBUserPw write FDBUserPw;
    property DBProvider: Integer
      read FDBProvider write FDBProvider;
  end;
 
  TDBSettings = class(TSynAutoCreateFields)
  private
    FDataBase: TDBSettingDataBase;
    FShorthandSymbol: TStringDynArray;
  public
    function LoadFromFile(const pmcFileName: TFileName): Boolean;
    procedure SaveToFile(const pmcFileName: TFileName);
  published
    property DataBase: TDBSettingDataBase
      read FDataBase;
    property ShorthandSymbol: TStringDynArray
      read FShorthandSymbol;
  end;

function TDBSettings.LoadFromFile(const pmcFileName: TFileName): Boolean;
begin
  Result := ObjectLoadJson(Self, StringFromFile(pmcFileName));
end;

procedure TDBSettings.SaveToFile(const pmcFileName: TFileName);
begin
  FileFromString(ObjectToJson(Self), pmcFileName);
end;
 
initialization
  Rtti.ByClass[TDBSettingDataBase].Props.NameChanges(
    ['DBServerName', 'DBName', 'DBUser', 'DBUserPw', 'DBProvider'],
    ['DB-ServerName', 'DB-Name', 'DB-User', 'DB-User-Pw', 'DB-Provider']);
Als Ausführung mit Records wie folgt:
Delphi-Quellcode:
type
  TDBSettingDataBase = packed record
    DBServerName: String;
    DBName: String;
    DBUser: String;
    DBUserPw: Integer;
    DBProvider: Integer;
  end;

  TDBSettings = packed record
    DataBase: TDBSettingDataBase;
    ShorthandSymbol: TStringDynArray; // array of String
    function LoadFromFile(const pmcFileName: TFileName): Boolean;
    procedure SaveToFile(const pmcFileName: TFileName);
  end;

function TDBSettings.LoadFromFile(const pmcFileName: TFileName): Boolean;
begin
  Result := RecordLoadJson(Self, StringFromFile(pmcFileName), TypeInfo(TDBSettings));
end;

procedure TDBSettings.SaveToFile(const pmcFileName: TFileName);
begin
  FileFromString(RecordSaveJson(Self, TypeInfo(TDBSettings)), pmcFileName);
end;

initialization
  Rtti.ByTypeInfo[TypeInfo(TDBSettingDataBase)].Props.NameChanges(
    ['DBServerName', 'DBName', 'DBUser', 'DBUserPw', 'DBProvider'],
    ['DB-ServerName', 'DB-Name', 'DB-User', 'DB-User-Pw', 'DB-Provider']);
Anwendung so:
Delphi-Quellcode:
var
  rec: TDBSettings;
begin
  rec.LoadFromFile('settings.json');
  ShowMessage(rec.DataBase.DBServerName);

  rec.DataBase.DBServerName := 'TestServer';
  rec.SaveToFile('settings.json');
Bis bald...
Thomas

Uwe Raabe 19. Sep 2023 20:43

AW: Json Array of String: Wie Array-Items per Schleife auslesen
 
Diesen Ansatz mit dem JSON-Class-Mapping kann man auch ohne externe Bibliothek nur mit Delphi-Bordmitteln realisieren:
Delphi-Quellcode:

interface

uses
  System.Types,
  REST.Json.Types; // wegen des Attributs

type
  TDBSettings = class
  type
    TDataBase = class
    private
      [JSONName('DB-Name')]
      FDBName: String;
      [JSONName('DB-Provider')]
      FDBProvider: Integer;
      FDBServerName: String;
      [JSONName('DB-User')]
      FDBUser: String;
      [JSONName('DB-User-Pw')]
      FDBUserPw: Integer;
    public
      property DBName: String read FDBName write FDBName;
      property DBProvider: Integer read FDBProvider write FDBProvider;
      property DBServerName: String read FDBServerName write FDBServerName;
      property DBUser: String read FDBUser write FDBUser;
      property DBUserPw: Integer read FDBUserPw write FDBUserPw;
    end;
  private
    FDatabase: TDataBase;
  public
    ShorthandSymbol: TStringDynArray;
    constructor Create;
    destructor Destroy; override;
    class function LoadFromFile(const pmcFileName: string): TDBSettings;
    procedure SaveToFile(const pmcFileName: string);
    property Database: TDataBase read FDatabase;
  end;

implementation

constructor TDBSettings.Create;
begin
  inherited Create;
  FDatabase := TDataBase.Create();
end;

destructor TDBSettings.Destroy;
begin
  FDatabase.Free;
  inherited Destroy;
end;
In der Anwendung sieht das dann in etwa so aus:
Delphi-Quellcode:
uses
  System.IOUtils, System.SysUtils,
  REST.Json;

const
  cFileName = 'c:\temp\settings.json';

begin
  var settings := TJson.JsonToObject<TDBSettings>(string.Join(sLineBreak, cArr));
  try
    TFile.WriteAllText(cFileName, TJson.ObjectToJsonString(settings));
  finally
    settings.Free;
  end;

begin
  var settings := TJson.JsonToObject<TDBSettings>(TFile.ReadAllText(cFileName));
  try
    ...
  finally
    settings.Free;
  end;
end;
Nebenbei: Das StringArray als Feld anstatt Property ist zumindest zu hinterfragen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:24 Uhr.
Seite 1 von 2  1 2      

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