Delphi-PRAXiS
Seite 4 von 4   « Erste     234

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   XML parsen, aber wie (https://www.delphipraxis.net/192207-xml-parsen-aber-wie.html)

Edelfix 22. Jun 2021 14:33

AW: XML parsen, aber wie
 
Nicht vollständig aber als Hilfe:

Delphi-Quellcode:
procedure Test1(XMLStr: string);
var
  XmlDoc: IXmlDocument;
  Root: IXMLNode;
  s: string;
  I: Integer;
  N1: IXMLNode;
  N2: IXMLNode;
  N3: IXMLNode;
 
begin
  XMLDoc := TXMLDocument.Create(nil);
  try
    XMLDoc.XML.Text := XMLStr;
    XMLDoc.Active := true;
    Root := XmlDoc.DocumentElement;
    s := Root.NodeName; // Zum Debugen
    //--
   N1 := Root.ChildNodes.FindNode('params');
   for I := 0 to N1.ChildNodes.Count-1 do
   begin
     N2 := N1.ChildNodes[i];
     if N2.ChildNodes.FindNode('value')<>nil then
     begin
       if N2.ChildNodes.FindNode('array')<>nil then // Muss dann natürlich weiter verschachteln
      begin
        s := N2.ChildNodes.FindNode('array').Text;    
      end;
     end;
   end;
end;

TiGü 22. Jun 2021 14:59

AW: XML parsen, aber wie
 
Ich lege nach und mache ein vollständiges Beispiel:

Delphi-Quellcode:
unit GetUID;

interface

uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Net.HttpClient, System.Net.URLClient,
    System.Net.HttpClientComponent,
    Xml.xmldom, Xml.XMLDoc, Xml.XMLIntf,
    UID;

type
    TForm3 = class(TForm)
        btnSampleCall1: TButton;
        btnSampleCall2: TButton;
        NetHTTPClient1: TNetHTTPClient;
        procedure btnSampleCall1Click(Sender: TObject);
        procedure btnSampleCall2Click(Sender: TObject);
    private
        procedure ShowResponse(const URL: string);
    end;

var
    Form3: TForm3;

implementation

{$R *.dfm}

// https://evatr.bff-online.de/eVatR/xmlrpc/http
const
    SAMPLE1 = 'https://evatr.bff-online.de/evatrRPC?UstId_1=DE123456789&UstId_2=AB1234567890&Firmenname=&Ort=&PLZ=&Strasse=';
    SAMPLE2 = 'https://evatr.bff-online.de/evatrRPC?UstId_1=DE123456789&UstId_2=AB1234567890&Firmenname=Firmenname einschl. Rechtsform&Ort=Ort der Firma&PLZ=12345&Strasse=Strasse der Firma';

procedure TForm3.btnSampleCall1Click(Sender: TObject);
begin
    ShowResponse(SAMPLE1);
end;

procedure TForm3.btnSampleCall2Click(Sender: TObject);
begin
    ShowResponse(SAMPLE2);
end;

procedure TForm3.ShowResponse(const URL: string);
var
    Response: IHTTPResponse;
    XmlDoc: IXMLDocument;
    RPCAnswer: UID.IXMLParamsType;
    Param: UID.IXMLParamType;
    Value, Value2: UID.IXMLValueType;
    I, J, K: Integer;
    DbgStr: string;
begin
    Response := NetHTTPClient1.Get(URL);
    XmlDoc := NewXMLDocument();
    XmlDoc.LoadFromXML(Response.ContentAsString());
    RPCAnswer := Getparams(XmlDoc);
    DbgStr := '';
    for I := 0 to RPCAnswer.Count - 1 do
    begin
        Param := RPCAnswer.Param[I];

        DbgStr := DbgStr + 'Param: ' + I.ToString + Param.Value.String_ + sLineBreak;

        for J := 0 to Param.Value.Array_.Data.Count - 1 do
        begin
            Value := Param.Value.Array_.Data.Value[J];

            if Value.String_ <> '' then
                DbgStr := DbgStr + '....Value ' + J.ToString + ' string: ' + Value.String_ + sLineBreak;

            // weitere Schachtelungen möglich, hier aber nicht in den beiden Beispielen
            for K := 0 to Value.Array_.Data.Count - 1 do
            begin
                Value2 := Value.Array_.Data.Value[K];
                if Value2.String_ <> '' then
                    DbgStr := DbgStr + '.......Value ' + K.ToString + ' string: ' + Value2.String_ + sLineBreak;
            end;
        end;
    end;
    ShowMessage(DbgStr);
end;

end.
mit der importierten XML über den XML Data Binding Wizard (Name der Unit hier mit UID gewählt, kann aber geändert werden):

Delphi-Quellcode:

{***************************************************}
{                                                   }
{                 XML Data Binding                 }
{                                                   }
{         Generated on: 22.06.2021 13:59:22         }
{       Generated from: D:\Github-Repos\new 2.xml  }
{   Settings stored in: D:\Github-Repos\new 2.xdb  }
{                                                   }
{***************************************************}

unit UID;

interface

uses Xml.xmldom, Xml.XMLDoc, Xml.XMLIntf;

type

{ Forward Decls }

  IXMLParamsType = interface;
  IXMLParamType = interface;
  IXMLValueType = interface;
  IXMLArrayType = interface;
  IXMLDataType = interface;

{ IXMLParamsType }

  IXMLParamsType = interface(IXMLNodeCollection)
    ['{F262379E-19C8-4062-BEF9-78826C7E7FF0}']
    { Property Accessors }
    function Get_Param(Index: Integer): IXMLParamType;
    { Methods & Properties }
    function Add: IXMLParamType;
    function Insert(const Index: Integer): IXMLParamType;
    property Param[Index: Integer]: IXMLParamType read Get_Param; default;
  end;

{ IXMLParamType }

  IXMLParamType = interface(IXMLNode)
    ['{96DA74CC-1B8A-4368-AA9E-99464D25D589}']
    { Property Accessors }
    function Get_Value: IXMLValueType;
    { Methods & Properties }
    property Value: IXMLValueType read Get_Value;
  end;

{ IXMLValueType }

  IXMLValueType = interface(IXMLNode)
    ['{235C08FA-0EBB-41E4-A7FE-4123BFE0D250}']
    { Property Accessors }
    function Get_String_: UnicodeString;
    function Get_Array_: IXMLArrayType;
    procedure Set_String_(Value: UnicodeString);
    { Methods & Properties }
    property String_: UnicodeString read Get_String_ write Set_String_;
    property Array_: IXMLArrayType read Get_Array_;
  end;

{ IXMLArrayType }

  IXMLArrayType = interface(IXMLNode)
    ['{0A59A8A5-86DD-4D4B-B345-6D553493DC94}']
    { Property Accessors }
    function Get_Data: IXMLDataType;
    { Methods & Properties }
    property Data: IXMLDataType read Get_Data;
  end;

{ IXMLDataType }

  IXMLDataType = interface(IXMLNodeCollection)
    ['{B3867F76-837B-495B-AD2B-ACBCC3B50263}']
    { Property Accessors }
    function Get_Value(Index: Integer): IXMLValueType;
    { Methods & Properties }
    function Add: IXMLValueType;
    function Insert(const Index: Integer): IXMLValueType;
    property Value[Index: Integer]: IXMLValueType read Get_Value; default;
  end;

{ Forward Decls }

  TXMLParamsType = class;
  TXMLParamType = class;
  TXMLValueType = class;
  TXMLArrayType = class;
  TXMLDataType = class;

{ TXMLParamsType }

  TXMLParamsType = class(TXMLNodeCollection, IXMLParamsType)
  protected
    { IXMLParamsType }
    function Get_Param(Index: Integer): IXMLParamType;
    function Add: IXMLParamType;
    function Insert(const Index: Integer): IXMLParamType;
  public
    procedure AfterConstruction; override;
  end;

{ TXMLParamType }

  TXMLParamType = class(TXMLNode, IXMLParamType)
  protected
    { IXMLParamType }
    function Get_Value: IXMLValueType;
  public
    procedure AfterConstruction; override;
  end;

{ TXMLValueType }

  TXMLValueType = class(TXMLNode, IXMLValueType)
  protected
    { IXMLValueType }
    function Get_String_: UnicodeString;
    function Get_Array_: IXMLArrayType;
    procedure Set_String_(Value: UnicodeString);
  public
    procedure AfterConstruction; override;
  end;

{ TXMLArrayType }

  TXMLArrayType = class(TXMLNode, IXMLArrayType)
  protected
    { IXMLArrayType }
    function Get_Data: IXMLDataType;
  public
    procedure AfterConstruction; override;
  end;

{ TXMLDataType }

  TXMLDataType = class(TXMLNodeCollection, IXMLDataType)
  protected
    { IXMLDataType }
    function Get_Value(Index: Integer): IXMLValueType;
    function Add: IXMLValueType;
    function Insert(const Index: Integer): IXMLValueType;
  public
    procedure AfterConstruction; override;
  end;

{ Global Functions }

function Getparams(Doc: IXMLDocument): IXMLParamsType;
function Loadparams(const FileName: string): IXMLParamsType;
function Newparams: IXMLParamsType;

const
  TargetNamespace = '';

implementation

uses Xml.xmlutil;

{ Global Functions }

function Getparams(Doc: IXMLDocument): IXMLParamsType;
begin
  Result := Doc.GetDocBinding('params', TXMLParamsType, TargetNamespace) as IXMLParamsType;
end;

function Loadparams(const FileName: string): IXMLParamsType;
begin
  Result := LoadXMLDocument(FileName).GetDocBinding('params', TXMLParamsType, TargetNamespace) as IXMLParamsType;
end;

function Newparams: IXMLParamsType;
begin
  Result := NewXMLDocument.GetDocBinding('params', TXMLParamsType, TargetNamespace) as IXMLParamsType;
end;

{ TXMLParamsType }

procedure TXMLParamsType.AfterConstruction;
begin
  RegisterChildNode('param', TXMLParamType);
  ItemTag := 'param';
  ItemInterface := IXMLParamType;
  inherited;
end;

function TXMLParamsType.Get_Param(Index: Integer): IXMLParamType;
begin
  Result := List[Index] as IXMLParamType;
end;

function TXMLParamsType.Add: IXMLParamType;
begin
  Result := AddItem(-1) as IXMLParamType;
end;

function TXMLParamsType.Insert(const Index: Integer): IXMLParamType;
begin
  Result := AddItem(Index) as IXMLParamType;
end;

{ TXMLParamType }

procedure TXMLParamType.AfterConstruction;
begin
  RegisterChildNode('value', TXMLValueType);
  inherited;
end;

function TXMLParamType.Get_Value: IXMLValueType;
begin
  Result := ChildNodes['value'] as IXMLValueType;
end;

{ TXMLValueType }

procedure TXMLValueType.AfterConstruction;
begin
  RegisterChildNode('array', TXMLArrayType);
  inherited;
end;

function TXMLValueType.Get_String_: UnicodeString;
begin
  Result := ChildNodes['string'].Text;
end;

procedure TXMLValueType.Set_String_(Value: UnicodeString);
begin
  ChildNodes['string'].NodeValue := Value;
end;

function TXMLValueType.Get_Array_: IXMLArrayType;
begin
  Result := ChildNodes['array'] as IXMLArrayType;
end;

{ TXMLArrayType }

procedure TXMLArrayType.AfterConstruction;
begin
  RegisterChildNode('data', TXMLDataType);
  inherited;
end;

function TXMLArrayType.Get_Data: IXMLDataType;
begin
  Result := ChildNodes['data'] as IXMLDataType;
end;

{ TXMLDataType }

procedure TXMLDataType.AfterConstruction;
begin
  RegisterChildNode('value', TXMLValueType);
  ItemTag := 'value';
  ItemInterface := IXMLValueType;
  inherited;
end;

function TXMLDataType.Get_Value(Index: Integer): IXMLValueType;
begin
  Result := List[Index] as IXMLValueType;
end;

function TXMLDataType.Add: IXMLValueType;
begin
  Result := AddItem(-1) as IXMLValueType;
end;

function TXMLDataType.Insert(const Index: Integer): IXMLValueType;
begin
  Result := AddItem(Index) as IXMLValueType;
end;

end.
Ergibt bspw. für den zweiten Button:

Code:
[Window Title]
Getuidtest

[Content]
Param: 0
....Value 0 string: UstId_1
....Value 1 string: DE123456789
Param: 1
....Value 0 string: ErrorCode
....Value 1 string: 212
Param: 2
....Value 0 string: UstId_2
....Value 1 string: AB1234567890
Param: 3
....Value 0 string: Druck
....Value 1 string: nein
Param: 4
....Value 0 string: Erg_PLZ
Param: 5
....Value 0 string: Ort
....Value 1 string: Ort der Firma
Param: 6
....Value 0 string: Datum
....Value 1 string: 22.06.2021
Param: 7
....Value 0 string: PLZ
....Value 1 string: 12345
Param: 8
....Value 0 string: Erg_Ort
Param: 9
....Value 0 string: Uhrzeit
....Value 1 string: 14:59:16
Param: 10
....Value 0 string: Erg_Name
Param: 11
....Value 0 string: Gueltig_ab
Param: 12
....Value 0 string: Gueltig_bis
Param: 13
....Value 0 string: Strasse
....Value 1 string: Strasse der Firma
Param: 14
....Value 0 string: Firmenname
....Value 1 string: Firmenname einschl. Rechtsform
Param: 15
....Value 0 string: Erg_Str


[OK]

ioster 22. Jun 2021 15:04

AW: XML parsen, aber wie
 
Wenn ich die Antworten richtig verstehe, gibt es keine Möglichkeit, den String-Wert direkt von der obersten Param-Ebene zu lesen. Ich hatte mir schon eine For-Schleife konstruiert und bin nun auf Childnodes.First und Childnodes.NextSibling umgeschwenkt, um die oberste Ebene mit einer While-Schleife abzuarbeiten. Kommt im Endeffekt wohl auf dasselbe Ergebnis.

Bei Childnodes.Findnode muss ich immer wissen, wie der Name der nächsten Ebene lautet und kann eben nicht bis auf die unterste Ebene direkt zugreifen. Attributes kann ich dann wohl gänzlich aus dem Kreis der Lösungsansätze streichen.

Ich muss schauen, ob ich mir nicht eine rekursive Funktion baue, die mir das String-Paar aus der untersten Ebene nach oben zieht.

Gruß
Ingo

ioster 22. Jun 2021 15:13

AW: XML parsen, aber wie
 
Zitat:

Zitat von TiGü (Beitrag 1491384)
Ich lege nach und mache ein vollständiges Beispiel:

Delphi-Quellcode:
unit GetUID;

interface

uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Net.HttpClient, System.Net.URLClient,
    System.Net.HttpClientComponent,
    Xml.xmldom, Xml.XMLDoc, Xml.XMLIntf,
    UID;

type
    TForm3 = class(TForm)
        btnSampleCall1: TButton;
        btnSampleCall2: TButton;
        NetHTTPClient1: TNetHTTPClient;
        procedure btnSampleCall1Click(Sender: TObject);
        procedure btnSampleCall2Click(Sender: TObject);
    private
        procedure ShowResponse(const URL: string);
    end;

var
    Form3: TForm3;

implementation

{$R *.dfm}

// https://evatr.bff-online.de/eVatR/xmlrpc/http
const
    SAMPLE1 = 'https://evatr.bff-online.de/evatrRPC?UstId_1=DE123456789&UstId_2=AB1234567890&Firmenname=&Ort=&PLZ=&Strasse=';
    SAMPLE2 = 'https://evatr.bff-online.de/evatrRPC?UstId_1=DE123456789&UstId_2=AB1234567890&Firmenname=Firmenname einschl. Rechtsform&Ort=Ort der Firma&PLZ=12345&Strasse=Strasse der Firma';

procedure TForm3.btnSampleCall1Click(Sender: TObject);
begin
    ShowResponse(SAMPLE1);
end;

procedure TForm3.btnSampleCall2Click(Sender: TObject);
begin
    ShowResponse(SAMPLE2);
end;

procedure TForm3.ShowResponse(const URL: string);
var
    Response: IHTTPResponse;
    XmlDoc: IXMLDocument;
    RPCAnswer: UID.IXMLParamsType;
    Param: UID.IXMLParamType;
    Value, Value2: UID.IXMLValueType;
    I, J, K: Integer;
    DbgStr: string;
begin
    Response := NetHTTPClient1.Get(URL);
    XmlDoc := NewXMLDocument();
    XmlDoc.LoadFromXML(Response.ContentAsString());
    RPCAnswer := Getparams(XmlDoc);
    DbgStr := '';
    for I := 0 to RPCAnswer.Count - 1 do
    begin
        Param := RPCAnswer.Param[I];

        DbgStr := DbgStr + 'Param: ' + I.ToString + Param.Value.String_ + sLineBreak;

        for J := 0 to Param.Value.Array_.Data.Count - 1 do
        begin
            Value := Param.Value.Array_.Data.Value[J];

            if Value.String_ <> '' then
                DbgStr := DbgStr + '....Value ' + J.ToString + ' string: ' + Value.String_ + sLineBreak;

            // weitere Schachtelungen möglich, hier aber nicht in den beiden Beispielen
            for K := 0 to Value.Array_.Data.Count - 1 do
            begin
                Value2 := Value.Array_.Data.Value[K];
                if Value2.String_ <> '' then
                    DbgStr := DbgStr + '.......Value ' + K.ToString + ' string: ' + Value2.String_ + sLineBreak;
            end;
        end;
    end;
    ShowMessage(DbgStr);
end;

end.
mit der importierten XML über den XML Data Binding Wizard (Name der Unit hier mit UID gewählt, kann aber geändert werden):

Vielen Dank für den ausführlichen Code!! Ich bekomme nach den vielen Tipps aber immer mehr Fragezeichen auf der Stirn, weil ich die Objekte und Methoden überhaupt nicht verstehe und die Hilfe von Embarcadero auch nicht wirklich tiefschürfend ist.

Was hat es mit "RPCAnswer: UID.IXMLParamsType" auf sich? Und was ist der XML Data Binding Wizard und die generierte Datei mit den kryptischen Schlüsseln? Unter Umständen hilft dieser Thread ja künftig auch anderen, die sich mit den Zugriffsmöglichkeiten von Delphi auf ein XMLDocument beschäftigen müssen.

Viele Grüße
Ingo

TiGü 22. Jun 2021 17:15

AW: XML parsen, aber wie
 
Es ist eigentlich ganz stumpf.
Ich habe die Beispiel-XML von der Website abgespeichert und sie dann in Delphi über den besagten XML Data Binding Wizard importiert, der daraus Quelltext strickt.
http://docwiki.embarcadero.com/RADSt...rten_verwenden

Du schickst einen Request an den Service und erhälst synchron eine Antwort.
Dann lädst du aus der Antwort den String mit der XML in ein IXMLDocument und schmeißt das in die Funktion Getparams().
Zurückkonvertiert kommt dann das XML-Document als DOM-Baum, in dem du navigieren kannst.
Letztendlich gesehen sind das auch nur Wrapper mit den passenden Bezeichnern um das IXMLDocument herum.

TiGü 22. Jun 2021 17:16

AW: XML parsen, aber wie
 
Wenn du eher ein visueller Typ bist:
https://www.youtube.com/results?sear...L+Data+Binding

ioster 2. Jul 2021 09:01

AW: XML parsen, aber wie
 
Moin,

ich möchte mich an dieser Stelle bei allen bedanken, die mir über die Plattform wertvolle Tipps und Codebeispiele zum XML-Problem gesendet haben.

Die Überprüfung von USt-ID über das Bundeszentralamt für Steuern konnte ich damit erfolgreich implementieren und unter Umständen hilft mir das auch an anderer Stelle einmal weiter.

Viele Grüße
Ingo


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:06 Uhr.
Seite 4 von 4   « Erste     234

Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf