SIGSEV-Fehler in XML-basierendem Programm

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
FixLuca
Beiträge: 2
Registriert: Fr 18. Dez 2020, 13:02

SIGSEV-Fehler in XML-basierendem Programm

Beitrag von FixLuca »

Hallo erstmal,

ich schreibe gerade an einem Mathematiker-Programm zum Laden & Speichern.
Problem ist ein SIGSEV-Fehler, der auftritt nach in dem ausgeführten Programm einer der zwei Buttons gedrückt wird:

Code: Alles auswählen

procedure TfrmMathematikerLadenUndSpeichernMitXML.FormCreate(Sender: TObject);
begin
  if FileExists('MeineDatei.xml')     // Wenn Namensdatei bereits existiert
  then
  begin
       // existierende Namensdatei öffnen & Wurzelknoten bestimmen
    ReadXMLFile(GXMLDocument, 'MeineDatei.xml');     // benötigt "laz2_XMLREAD"
    GRootNode := GXMLDocument.DocumentElement;
  end
  else
  begin
       // neu anlegen einer Namensdatei
    GXMLDocument := TXMLDocument.Create;
       // Wurzelknoten "erzeugen" & an das Dokument "anfügen"
    GXMLDocument.Appendchild(GRootNode);
  end;
      // Anzahl der Datensätze angeben
  lblAnzahlDatensatze.Caption := IntToStr(GRootNode.ChildNodes.Count);
  //lblAnzahlDatensatze.Caption := '15'
end;

procedure TfrmMathematikerLadenUndSpeichernMitXML.btnSpeichernClick(Sender: TObject);
var
  LParentNode: TDOMNode;
  LChildNode: TDOMNode;
  LTextNode: TDOMNode;
begin
     // Vaterknoten erzeugen
  LParentNode := GXMLDocument.CreateElement('Datensatz');
     // Eintrag "Name":
     // Kindnoten erzeugen & mit Inhalt füllen, dann an Vaterknoten anhängen
  LChildNode := GXMLDocument.CreateElement('Name');
     // ... mit Inhalt füllen ...
  LTextNode := GXMLDocument.CreateTextNode(edtName.Text);
  LChildNode.AppendChild(LTextNode);
     // ... Kindknoten an Vaterknoten anhängen
  LParentNode.AppendChild(LChildNode);
     // Vaterknoten an Wurzelknoten anhängen
  GRootNode.AppendChild(LParentNode);

     // Eintrag "Alter":
     // Kindnoten erzeugen & mit Inhalt füllen, dann an Vaterknoten anhängen
  LChildNode := GXMLDocument.CreateElement('Alter');
     // ... mit Inhalt füllen ...
  LTextNode := GXMLDocument.CreateTextNode(edtName.Text);
  LChildNode.AppendChild(LTextNode);
     // ... Kindknoten an Vaterknoten anhängen
  LParentNode.AppendChild(LChildNode);
     // Vaterknoten an Wurzelknoten anhängen
  GRootNode.AppendChild(LParentNode);

     // Eintrag "Besondere Leistung":
     // Kindnoten erzeugen & mit Inhalt füllen, dann an Vaterknoten anhängen
  LChildNode := GXMLDocument.CreateElement('Besondere Leistung');
     // ... mit Inhalt füllen ...
  LTextNode := GXMLDocument.CreateTextNode(edtName.Text);
  LChildNode.AppendChild(LTextNode);
     // ... Kindknoten an Vaterknoten anhängen
  LParentNode.AppendChild(LChildNode);
     // Vaterknoten an Wurzelknoten anhängen
  GRootNode.AppendChild(LParentNode);

     // Anzahl der Datensätze angeben
  lblAnzahlDatensatze.Caption := IntToStr(GRootNode.ChildNodes.Count);
end;
Bin gespannt auf eure Antworten :?

Grüße!
Fix

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: SIGSEV-Fehler in XML-basierendem Programm

Beitrag von wp_xyz »

Habe jetzt nicht alles angesehen, aber schon am Anfang gibt es einen Grund für einen Crash: Wenn es die MeinDatei.xml nicht gibt, läuft das Programm in den else-Zweig der if-Anweisung, und dort steht: "GXMLDocument.Appendchild(GRootNode)". GRootNode wurde nicht erzeugt. Folge pingelig den Anweisungen im XML-Tutorial, Abschnitt "Generating an XML File": https://wiki.lazarus.freepascal.org/XML ... a_XML_file

FixLuca
Beiträge: 2
Registriert: Fr 18. Dez 2020, 13:02

Re: SIGSEV-Fehler in XML-basierendem Programm

Beitrag von FixLuca »

Erstmal, dankeschön für die schnelle Antwort!!

Kleines Update bezüglich des (gesamten Codes):

Code: Alles auswählen

unit uMathematikerXMLProgramm;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls, Laz2_DOM, laz2_XMLRead, laz2_XMLWrite;

type

  { TfrmMathematikerLadenUndSpeichernMitXML }

  TfrmMathematikerLadenUndSpeichernMitXML = class(TForm)
    btnLaden: TButton;
    btnSpeichern: TButton;
    edtDatensatzNr: TEdit;
    edtAlter: TEdit;
    edtBesondereLeistung: TEdit;
    edtName: TEdit;
    lblAlter: TLabel;
    lblAnzahlDatensaetze: TLabel;
    lblBesondereLeistung: TLabel;
    lblName: TLabel;
    lblNr: TLabel;
    pnlAlter: TPanel;
    pnlBesondereLeistung: TPanel;
    pnlName: TPanel;
    procedure btnLadenClick(Sender: TObject);
    procedure btnSpeichernClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
  private
  public
    GXMLDocument: TXMLDocument;
    GRootNode: TDOMNode;
  end;

var
  frmMathematikerLadenUndSpeichernMitXML: TfrmMathematikerLadenUndSpeichernMitXML;

implementation

{$R *.lfm}

{ TfrmMathematikerLadenUndSpeichernMitXML }

procedure TfrmMathematikerLadenUndSpeichernMitXML.FormCreate(Sender: TObject);
begin
  if FileExists('MeineDatei.xml')     // Wenn Namensdatei bereits existiert
  then
  begin
       // existierende Namensdatei öffnen & Wurzelknoten bestimmen
    ReadXMLFile(GXMLDocument, 'MeineDatei.xml');     // benötigt "laz2_XMLREAD"
    GRootNode := GXMLDocument.DocumentElement;
  end
  else
  begin
       // neu anlegen einer Namensdatei
    GXMLDocument := TXMLDocument.Create;
       // Wurzelknoten "erzeugen" & an das Dokument "anfügen"
    GRootNode := GXMLDocument.CreateElement('Datensatz');
    GXMLDocument.Appendchild(GRootNode);
  end;
      // Anzahl der Datensätze angeben
  lblAnzahlDatensaetze.Caption := IntToStr(GRootNode.ChildNodes.Count);
end;

procedure TfrmMathematikerLadenUndSpeichernMitXML.btnSpeichernClick(Sender: TObject);
var
  LParentNode: TDOMNode;
  LChildNode: TDOMNode;
  LTextNode: TDOMNode;
begin
     // Vaterknoten erzeugen
  LParentNode := GXMLDocument.CreateElement('Datensatz');
     // Eintrag "Name":
     // Kindnoten erzeugen & mit Inhalt füllen, dann an Vaterknoten anhängen
  LChildNode := GXMLDocument.CreateElement('Name');
     // ... mit Inhalt füllen ...
  LTextNode := GXMLDocument.CreateTextNode(edtName.Text);
  LChildNode.AppendChild(LTextNode);
     // ... Kindknoten an Vaterknoten anhängen
  LParentNode.AppendChild(LChildNode);
     // Vaterknoten an Wurzelknoten anhängen
  GRootNode.AppendChild(LParentNode);

     // Eintrag "Alter":
     // Kindnoten erzeugen & mit Inhalt füllen, dann an Vaterknoten anhängen
  LChildNode := GXMLDocument.CreateElement('Alter');
     // ... mit Inhalt füllen ...
  LTextNode := GXMLDocument.CreateTextNode(edtAlter.Text);
  LChildNode.AppendChild(LTextNode);
     // ... Kindknoten an Vaterknoten anhängen
  LParentNode.AppendChild(LChildNode);
     // Vaterknoten an Wurzelknoten anhängen
  GRootNode.AppendChild(LParentNode);

     // Eintrag "Besondere Leistung":
     // Kindnoten erzeugen & mit Inhalt füllen, dann an Vaterknoten anhängen
  LChildNode := GXMLDocument.CreateElement('Besondere Leistung');
     // ... mit Inhalt füllen ...
  LTextNode := GXMLDocument.CreateTextNode(edtBesondereLeistung.Text);
  LChildNode.AppendChild(LTextNode);
     // ... Kindknoten an Vaterknoten anhängen
  LParentNode.AppendChild(LChildNode);

     // Vaterknoten an Wurzelknoten anhängen
  GRootNode.AppendChild(LParentNode);

     // Anzahl der Datensätze angeben
  lblAnzahlDatensaetze.Caption := IntToStr(GRootNode.ChildNodes.Count);
end;

procedure TfrmMathematikerLadenUndSpeichernMitXML.FormClose(Sender: TObject;
  var CloseAction: TCloseAction);
begin
     // Vor dem Schließen den Inhalt des XML-Dokumentes
     // in zugewiesene Datei auf der Festplatte schreiben
  WriteXMLFile(GXMLDocument, 'MeineDatei.xml', []);     // "laz2_XMLWrite"!
     // Freigabe des Speicherbereiches des XML-Dokumentes
  GXMLDocument.Free;
end;

procedure TfrmMathematikerLadenUndSpeichernMitXML.btnLadenClick(Sender: TObject);
var
  LDatensatzNr: Integer;
  LParentNode: TDOMNode;
  LChildNode: TDOMNode;
begin
     // Datensatzummer aus Oberfläche einlesen
  LDatensatzNr := StrToInt(edtDatensatzNr.Text);
     // Vaterknoten anhand der Datensatznummer bestimmt
  LParentNode := GRootNode.ChildNodes[LDatensatzNr];
     // Kindknoten "Name" bestimmen & ausgeben
  LChildNode := LParentNode.FindNode('Name');
  pnlName.Caption := LChildNode.FirstChild.NodeValue;
     // Kindknoten "Alter" bestimmen & ausgeben
  LChildNode := LParentNode.FindNode('Alter');
  pnlAlter.Caption := LChildNode.FirstChild.NodeValue;
     // Kindknoten "Besondere Leistung" bestimmen & ausgeben
  LChildNode := LParentNode.FindNode('Besondere Leistung');
  pnlAlter.Caption := LChildNode.FirstChild.NodeValue;
end;

end.
Stand jetzt tretten diese Probleme auf:
1) Nach kompilieren & Starten des Programms, zeigt die Caption des Labels für die Anzahl der Datensätze nicht die Anzahl der Datzensätze aus "MeineDatei.xml" (15) sondern die Übergangscaption <Anzahl>

2) Beim Drücken des Buttons fürs Speichern kommt das Fenster:
"Projekt MathematikerXMLProgramm hat Exception-Klasse >>External: SIGSEGV<< ausgelöst.
In Datei 'umathematikerxmlprogramm.pas' in Zeile 77: LParentNode := GXMLDocument.CreateElement('Datensatz');

3) Beim Drücken des Buttons fürs Laden kommt das Fenster:
"Projekt MathematikerXMLProgramm hat Exception-Klasse >>External: SIGSEGV<< ausgelöst.
In Datei 'laz2_dom.pas' in Zeile 1211' "

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: SIGSEV-Fehler in XML-basierendem Programm

Beitrag von wp_xyz »

Das sind sehr spezielle Fragen, die man viel leichter beantworten könnte, wenn kompilierbarer Quelltext, also ein kleines Test-Projekt vorhanden wäre. Zum Beispiel weiß ich nicht, welcher von den zwei Buttons den Fehler auslöst. Und was Zeile 77 ist, weiß ich auch nicht. Zumindest nicht ohne Detektivarbeit. Also bitte: Nimm diesen Code und kopiere ihn in ein neues Projekt, ergänze die fehlenden Controls und prüfe, ob der Fehler noch auftritt. Wenn du dann die .pas, .lfm, lpr und lpi Dateien in ein zip packst und hier unter "Dateianhänge" hochlädst, habe ich alles, was ich brauche.

Wird das XMLDocument auch noch von anderer Stelle deines Programms aus benötigt? Wenn nicht, würde ich von der "globalen" Variablen in TfrmMathematikerLadenUndSpeichernMitXML abraten; ich würde jeweils in der Laden- und Speichern-Prozedur eine lokale Variable verwenden.

Vorsicht mit der ButtonClose-Prozedur. Close heißt im Normalfall nur, dass das Formular versteckt wird (es sei denn du gibtst im Parameter CloseAction etwas anderes an). In diesem Normalfall würden dann die XML-Variablen zerstört werden, und wenn du das Formular ein zweites mal öffnest, würde OnCreate nicht mehr durchlaufen werden, so dass diese Variablen nicht mehr wieder neu erzeugt werden. --> crash. Ein Argument gegen globale Variablen.

Antworten