der Umgang mit XML-Dateien in Delphi

Daten kann man auf vielfältige Weise verwalten. In diesem Beitrag zeige ich anhand einer kleinen Adressverwaltung, wie man mit Delphi Adress- Kontakt- und Kontodaten in einer XML-Datei speichert und diese daraus auch wieder auslesen kann.

Um dieses Beispiel nachvollziehen zu können, benötigen Sie die Komponente XMLDocument, die Sie in der Komponentenpalette Internet finden.
Legen Sie als erstes ein neues Projekt an und klicken Sie sich, wie in der nächsten Abbildung zu sehen, die Oberfläche zusammen. Für dieses Beispiel werden folgende Komponenten benötigt.

  • 1 ComboBox (Standard),
  • 1 PageControl (Win32),
  • 18 Edits (Standard),
  • 19 Labels (Standard),
  • 3 Buttons (Standard),
  • 1 XMLDocument (Internet)

Die Editfelder habe ich nach den davor stehenden Labels benannt. Also das Editfeld hinter dem Label Vorname hat den Namen edVorname. Die Buttons heißen btnNew, btnDelete und btnSave. Diese sind, wie man schon an den Namen erkennen kann, zum Hinzufügen eines neuen Kunden, zum, löschen eines vorhandenen Kunden und zum Speichern von Änderungen die an einem Kunden vorgenommen werden.

private Deklarationen

private
    procedure ClearControls;
    procedure ReadXMLData;
    procedure InsertNewAdresse;
    procedure UpdateAdresse;

 

Globale Variablen

var
  Form1: TForm1;
  PATH: string;
  UPDATEADRESS: boolean;
  SelAdressIndex: integer;

 

Code für den Button btnNew (Neuer Kunde)

procedure TForm1.btnNewClick(Sender: TObject);
begin
  UPDATEADRESS := False;
  SelAdressIndex := -1;
  btnDelete.Enabled := False;
  btnSave.Enabled := True;
  btnSave.Caption := 'Speichern';
  ClearControls;
end;

 

Procedure zum auslesen der Namen aller Kunden aus der XML-Datei

procedure TForm1.ReadXMLData;
var
  xmlDoc : IXMLDocument;
  i, a: LongInt;
  s: string;
begin
  ClearControls;
  cbKunden.Clear;
  cbKunden.Items.Add('');

//XMLDocument erzeugen und xml-Datei laden
  xmlDoc := newXMLDocument;
  xmlDoc.LoadFromFile(PATH+'data.xml');
  xmlDoc.Active := true;

//Kundenname in ComboBox ausgeben und ID des Eintrags übergeben
  for i := 0 to xmlDoc.ChildNodes['Kunden'].ChildNodes.Count -1 do
  begin
    s := xmlDoc.DocumentElement.ChildNodes[i].ChildNodes['adresse'].Attributes['vorname'];
    s := s + ' '+xmlDoc.DocumentElement.ChildNodes[i].ChildNodes['adresse'].Attributes['name'];
    a := StrToInt(StringReplace(xmlDoc.DocumentElement.ChildNodes[i].NodeName, 'kunde_', '', []));
    cbKunden.Items.AddObject(s,Pointer(a));
  end;
  btnDelete.Enabled := False;
  btnSave.Caption := 'Speichern';
  PageControl1.ActivePageIndex := 0;
end;

 

Procedure zum speichern eines neuen Kunden in der XML-Datei

procedure TForm1.InsertNewAdresse;
var
  xmlDoc : IXMLDocument;
  iNode : IXMLNode;
  s: string;
begin
  xmlDoc := newXMLDocument;
  xmlDoc.LoadFromFile(PATH+'data.xml');
  xmlDoc.Active := true;

//Neuen Knoten anlegen
  s := 'kunde_'+IntToStr(Zufallszahl(0, 999999999));
  XMLDoc.DocumentElement.AddChild(s);

//Adresse
  iNode := XMLDoc.DocumentElement.ChildNodes.FindNode(s).AddChild('adresse');
  iNode.Attributes['vorname'] := edVorname.Text;
  iNode.Attributes['name'] := edNachname.Text;
  iNode.Attributes['strasse'] := edStrasse.Text;
  iNode.Attributes['hausnr'] := edHausNr.Text;
  iNode.Attributes['plz'] := edPLZ.Text;
  iNode.Attributes['ort'] := edOrt.Text;
  iNode.Text := '';

//Kontakt
  iNode := XMLDoc.DocumentElement.ChildNodes.FindNode(s).AddChild('kontakt');
  iNode.Attributes['tel1'] := edTelefon1.Text;
  iNode.Attributes['tel2'] := edTelefon2.Text;
  iNode.Attributes['fax1'] := edTelefax1.Text;
  iNode.Attributes['fax2'] := edTelefax2.Text;
  iNode.Attributes['handy1'] := edHandy1.Text;
  iNode.Attributes['handy2'] := edHandy2.Text;
  iNode.Attributes['email1'] := edEmail1.Text;
  iNode.Attributes['email2'] := edEmail2.Text;
  iNode.Text := '';

//Konto
  iNode := XMLDoc.DocumentElement.ChildNodes.FindNode(s).AddChild('konto');
  iNode.Attributes['kontonr'] := edKontoNr.Text;
  iNode.Attributes['banklz'] := edBanklz.Text;
  iNode.Attributes['bank'] := edBank.Text;
  iNode.Attributes['inhaber'] := edKontoInhaber.Text;
  iNode.Text := '';

//Speichern und Lite neu laden
  XMLDoc.SaveToFile(PATH+'data.xml');
  ReadXMLData;
end;

 

Procedure zum ändern der Daten eines Kunden in der XML-Datei

procedure TForm1.UpdateAdresse;
var
  xmlDoc : IXMLDocument;
  iNode  : IXMLNode;
begin
  xmlDoc := newXMLDocument;
  xmlDoc.LoadFromFile(PATH+'data.xml');
  xmlDoc.Active := true;

//Adresse
  iNode := xmlDoc.ChildNodes['Kunden'].ChildNodes['kunde_'+inttostr(SelAdressIndex)].ChildNodes['adresse'];
  iNode.Attributes['vorname'] := edVorname.Text;
  iNode.Attributes['name'] := edNachname.Text;
  iNode.Attributes['strasse'] := edStrasse.Text;
  iNode.Attributes['hausnr'] := edHausNr.Text;
  iNode.Attributes['plz'] := edPLZ.Text;
  iNode.Attributes['ort'] := edOrt.Text;
  iNode.Text := '';

//Kontakt
  iNode := xmlDoc.ChildNodes['Kunden'].ChildNodes['kunde_'+inttostr(SelAdressIndex)].ChildNodes['kontakt'];
  iNode.Attributes['tel1'] := edTelefon1.Text;
  iNode.Attributes['tel2'] := edTelefon2.Text;
  iNode.Attributes['fax1'] := edTelefax1.Text;
  iNode.Attributes['fax2'] := edTelefax2.Text;
  iNode.Attributes['handy1'] := edHandy1.Text;
  iNode.Attributes['handy2'] := edHandy2.Text;
  iNode.Attributes['email1'] := edEmail1.Text;
  iNode.Attributes['email2'] := edEmail2.Text;
  iNode.Text := '';

//Konto
  iNode := xmlDoc.ChildNodes['Kunden'].ChildNodes['kunde_'+inttostr(SelAdressIndex)].ChildNodes['konto'];
  iNode.Attributes['kontonr'] := edKontoNr.Text;
  iNode.Attributes['banklz'] := edBanklz.Text;
  iNode.Attributes['bank'] := edBank.Text;
  iNode.Attributes['inhaber'] := edKontoInhaber.Text;
  iNode.Text := '';

//Speichern und List neu laden
  XMLDoc.SaveToFile(PATH+'data.xml');
  ReadXMLData;
end;

 

Code für den Button btnDelete (Löschen)

procedure TForm1.btnDeleteClick(Sender: TObject);
var
  xmlDoc : IXMLDocument;
  iNode : IXMLNode;
begin
  if(mrYes = MessageDlg('Wollen Sie diese Adresse wirklich löschen?', mtInformation, [mbYes, mbNo], 0)) then
  begin
    xmlDoc := newXMLDocument;
    xmlDoc.LoadFromFile(PATH+'data.xml');
    xmlDoc.Active := true;

    iNode := xmlDoc.ChildNodes['Kunden'];
    iNode.DOMNode.removeChild(iNode.ChildNodes['kunde_'+IntToStr(SelAdressIndex)].DOMNode);

    XMLDoc.SaveToFile(PATH+'data.xml');
    ReadXMLData;
  end;
end;

 

Code für den Button btnSave (Speichern)

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  if(trim(edVorname.Text) <> '') AND (trim(edNachname.Text) <> '') AND (trim(edStrasse.Text) <> '')
  AND (trim(edPLZ.Text) <> '') AND (trim(edOrt.Text) <> '') then
  begin
    if(UPDATEADRESS = True) then UpdateAdresse else InsertNewAdresse;
  end else showmessage('Bitte füllen Sie alle Pflichtfelder aus!');

  ReadXMLData;
end;

 

Code für die ComboBox cbKunden

procedure TForm1.cbKundenSelect(Sender: TObject);
var
  xmlDoc : IXMLDocument;
  s: string;
begin
  if(cbKunden.ItemIndex > 0) then
  begin
    SelAdressIndex := Integer(cbKunden.Items.Objects[cbKunden.ItemIndex]);

    btnSave.Caption := 'Update';
    btnDelete.Enabled := True;
    UPDATEADRESS := True;

//XMLDocument erzeugen und xml-Datei laden
    xmlDoc := newXMLDocument;
    xmlDoc.LoadFromFile(PATH+'data.xml');
    xmlDoc.Active := true;

    s := 'kunde_'+IntToStr(SelAdressIndex);

//Adressdaten ausgeben
    edVorname.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['adresse'].Attributes['vorname'];
    edNachname.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['adresse'].Attributes['name'];
    edStrasse.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['adresse'].Attributes['strasse'];
    edHausNr.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['adresse'].Attributes['hausnr'];
    edPLZ.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['adresse'].Attributes['plz'];
    edOrt.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['adresse'].Attributes['ort'];

//Kontaktdaten ausgeben
    edTelefon1.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['kontakt'].Attributes['tel1'];
    edTelefon2.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['kontakt'].Attributes['tel2'];
    edTelefax1.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['kontakt'].Attributes['fax1'];
    edTelefax2.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['kontakt'].Attributes['fax2'];
    edHandy1.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['kontakt'].Attributes['handy1'];
    edHandy2.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['kontakt'].Attributes['handy2'];
    edEmail1.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['kontakt'].Attributes['email1'];
    edEmail2.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['kontakt'].Attributes['email2'];

//Kontodaten ausgeben
    edKontoNr.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['konto'].Attributes['kontonr'];
    edBanklz.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['konto'].Attributes['banklz'];
    edBank.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['konto'].Attributes['bank'];
    edKontoinhaber.Text := xmlDoc.DocumentElement.ChildNodes.FindNode(s).ChildNodes['konto'].Attributes['inhaber'];
  end
  else
  begin
    SelAdressIndex := -1;
    ClearControls;
    btnSave.Caption := 'Speichern';
    btnDelete.Enabled := False;
    UPDATEADRESS := False;
  end;
end;

 

Wenn das Hauptformular erzeugt wird, fragen wir als erstes ab, ob die Datei data.xml im Programmverzeichnis vorhanden ist. Gibt es diese noch nicht, wird sie erstellt und gespeichert.

procedure TForm1.FormCreate(Sender: TObject);
var stl: TStringList;
begin
  Randomize;
  PATH := ExtractFilePath(ParamStr(0));

  if(not fileexists(PATH+'data.xml')) then
  begin
    stl := TStringList.Create;
    try
      stl.Add('<!--?xml version="1.0"?-->');
      stl.Add('');
      stl.Add('');
    finally
      stl.SaveToFile(PATH+'data.xml');
      stl.Free;
    end;
  end;
end;

 

Kurz bevor das Hauptformular angezeigt wird, werden die Vor- und Nachnamen aller in der xml-Datei gespeicherten Kunden ausgelesen und in der ComboBox cbKunden angezeigt. Anschließend wird der Fokus auf das Eingabefeld edVorname gesetzt.

procedure TForm1.FormShow(Sender: TObject);
begin
  ReadXMLData;
  edVorname.SetFocus;
end;

 

Ein paar Hilsfunktionen zum leeren der Controls nachdem ein Kunde angelegt wurde und zum erzeugen einer Zufallszahl. Die Zufallszahl aus dem Grund dass kein Knotenname doppelt vorkommt. Gut es gibt bessere und sicherere Methoden dafür aber dies sollte erst mal reichen.

{##################################
  Zufanszahl für Knoten erzeugen  #
##################################}
function Zufallszahl(Von, Bis: Integer): Integer;
begin
  Result := Random(Succ(Bis - Von)) + Von;
end;

{########################
  Alle Controls leeren  #
########################}
procedure TForm1.ClearControls;
var i : integer;
begin
  for i := 0 to ComponentCount -1 do
    if Components[i] is TEdit then
      with Components[i] as TEdit do Clear;
end;

Das komplette XML_Adressverwaltung können Sie hier herunter laden.

Über Enrico S.

Programmierer, Webdesigner, Grafiker, Blogger, Screencaster, Arduino- und eMobility Enthusiast.

Ein Kommentar zu “der Umgang mit XML-Dateien in Delphi

  1. Pingback: Delphi Problem beim Auslesen einer XML Datei - Delphi-PRAXiS