Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   XML (https://www.delphipraxis.net/46-xml/)
-   -   Delphi XML Problem beim Einlesen (https://www.delphipraxis.net/141106-xml-problem-beim-einlesen.html)

mcmichael 2. Okt 2009 18:06


XML Problem beim Einlesen
 
Jetzt habe ich's geschafft eine XML-Datei in etwa so zu schreiben wie ich will:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<test>
<applicant_1>
<family_name>Meyer</family_name>
<given_name>Harald</given_name>
<testdate>13.03.2009</testdate>
<language>english</language>
<WR_RW>229</WR_RW>
</applicant_1>
</test>

ich kriege aber die Daten nicht wieder eingelesen, was ist hier falsch?

Delphi-Quellcode:
 
var app:IXMLNode;
begin
  XMLDocument1.LoadFromFile('d:\test.xml');
  ListBox1.Items.Clear;
  For i := 1 to 5 do
    begin
    app:=XMLDocument1.DocumentElement.ChildNodes['applicant_'+IntToStr(i)]; //hier gibt es eine Zugriffsverletzung, warum?
    ListBox1.Items.Add(app.ChildNodes['family_name'].text);
    end;
  XMLDocument1.Free;
end;
außerdem: wenn die Datei nicht da ist und ich sie neu erzeugen muß: muß ich immer die gleichen
Prozeduren aufrufen um die Struktur zu erzeugen?

Wie kann ich einen Wert einer eingelesenen XML-Datei ändern?

Delphi-Quellcode:
app.ChildNodes['family_name'].text:='Schulze'
?

himitsu 3. Okt 2009 15:53

Re: XML Problem beim Einlesen
 
Zitat:

Zitat von mcmichael
ich kriege aber die Daten nicht wieder eingelesen, was ist hier falsch?

Ganz ehrlich?
Keine Ahnung.

Bei mir verursacht dein Code keinerlei Zugriffsverletzngen.
Welche Exception wird denn bei dir ausgelöst? (den Fehlertext bitte mal nennen)

PS: Strg+C kopiert den Text des Fehlerdialogs in die Zwischenablage, wenn er grad aktiv ist und man kann ihn dann direkt als text hier einfügen.


OK, was mich erst gewundert hat ist, daß der Code nicht mindestens im zweiten Durchgang eine Exception wirft, aber in der nächsten Zeile erst.
Allerdings ist bei der Komponente standardmäßig doNodeAutoCreate gesetzt, was dieses dann erklärte.


Zitat:

Zitat von mcmichael
außerdem: wenn die Datei nicht da ist und ich sie neu erzeugen muß: muß ich immer die gleichen Prozeduren aufrufen um die Struktur zu erzeugen?

Ich weiß jetzt zwar nicht welche Prozeduren du meinst,
aber Ja?

Zitat:

Zitat von mcmichael
Wie kann ich einen Wert einer eingelesenen XML-Datei ändern?
Delphi-Quellcode:
app.ChildNodes['family_name'].text:='Schulze'

Genau so.

mcmichael 4. Okt 2009 08:48

Re: XML Problem beim Einlesen
 
Danke für den Kommentar himitsu - mit XML haben hier scheinbar nicht wo viele was am Hut.
Im Forum sind viele Threads die ohne Lösung enden.

Also: der Grund für das (scheinbare) Nicht-Funktionieren war, daß ich in ListBox1 reingeschrieben habe,
mein Blick aber auf die dafür extra eingerichtete ListBox2 geheftet war. :wall:

Die Exception kam beim zweiten Aufruf, denn am Ende des ersten Aufrufs steht: XMLDocument1.Free;

mit
Zitat:

muß ich immer die gleichen Prozeduren aufrufen um die Struktur zu erzeugen?
meinte ich was ich tun muß wenn ich die Datei nicht finde oder sie fehlerhaft ist.
Ich versuche das jetzt über den EDOMParseError zu erreichen, der angeblich
bei Active:=true erzeugt wird.
Delphi-Quellcode:
procedure TForm2.Button7Click(Sender: TObject);
var i:integer;
    app:IXMLNode;
begin
   try
     XMLDocument1.LoadFromFile('d:\texst.xml');
     XMLDocument1.Active    := True;
   except On E: EDOMParseError do
        begin
          XMLDocument1.Version   := '1.0';
          XMLDocument1.StandAlone := 'yes'; //hier kommt jetzt die Zugriffsverletzung:
          XMLDocument1.Encoding  := 'UTF-8';
          XMLDocument1.Options   := [doNodeAutoIndent];
          XMLDocument1.AddChild('WRT');
          XMLDocument1.SaveToFile('d:\Texst.xml');
        end;
  end;
  //XMLDocument1.Active:=true;
  ListBox2.Items.Clear;
  ListBox2.Items.Add(XMLDocument1.DocumentElement.NodeName);
  for i := 1 to 5 do
    begin
    app:=XMLDocument1.DocumentElement.ChildNodes['applicant_'+IntToStr(i)];
    ListBox2.Items.Add(app.ChildNodes['family_name'].text);
  end;
  XMLDocument1.Active:=false;
end;
Wenn die Datei vorhanden ist (text.xml ist vorhanden, texst.xml nicht) listet er die Inhalte auf,
ist sie nicht vorhanden kommt folgende Zugriffsverletzung:
---------------------------
Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt test_xml.exe ist eine Exception der Klasse EAccessViolation mit der Meldung 'Zugriffsverletzung bei Adresse 0049935B in Modul 'test_xml.exe'. Lesen von Adresse 00000000' aufgetreten.
---------------------------
Anhalten Fortsetzen Hilfe
---------------------------

Ich wollte an der Stelle an der klar ist, daß etwas mit der Datei nicht stimmt, die Struktur neu erzeugen um sie dann weiter zu befüllen.

Deine Bemerkung über doNodeAutoCreate kann ich nicht nachvollziehen, warum sollte diese Option eine Exception erzeugen?

himitsu 4. Okt 2009 10:24

Re: XML Problem beim Einlesen
 
Wegen des doNodeAutoCreate: Ich hatte irgendwie im Hinterkopf, daß in TXMLDocument dieses per Standard nicht gesetzt ist, aber wie ich grad sehe, ist dieses doch der Fall (kann aber auch sein, daß anderer Arten der Erzeugung eines Dokuments da andere Voreinstellungen haben :gruebel: )

Nja, jedenfalls gäbe es ohne diese Option eine Exception, da du ungeprüft auf applicant_1 bis applicant_5 zugreifst, es aber nur die applicant_1 in dem Dokument gibt.



Sooo, also theoretisch würde/könnte man bei TXMLDocument so eine Datei erstellen
Delphi-Quellcode:
XMLDocument1.Active    := True;
XMLDocument1.Version   := '1.0';
XMLDocument1.StandAlone := 'yes';
XMLDocument1.Encoding  := 'UTF-8';
XMLDocument1.Options   := [doNodeAutoIndent];
XMLDocument1.AddChild('WRT');
XMLDocument1.SaveToFile('d:\Test.xml');
Und ich hätte dieses auch so in die Exceptionbehandlung aufgenommen.

PS: LoadFromFile lößt die Exception schon aus und würde nach erfolgreichem Parsen .Active auf True setzen.
Demnach wäre ein Exprizites .Active:=True, nach erfolgreichem Parsen garnicht nötig.

.Active := True; müßte man dan aber machen, wenn man das Dokument nun nach der Exception (neu) erstellen will, da die nachfolgenden Befehle nur in einem aktiven Element richtig ausgeführt werden.

Das Fazit wäre also
Delphi-Quellcode:
var i: integer;
  app: IXMLNode;
begin
  try
    XMLDocument1.LoadFromFile('d:\texst.xml');
  except
    on E: EDOMParseError do
    begin
      XMLDocument1.Active    := True;
      XMLDocument1.Version   := '1.0';
      XMLDocument1.StandAlone := 'yes';
      XMLDocument1.Encoding  := 'UTF-8';
      XMLDocument1.Options   := [doNodeAutoIndent];
      XMLDocument1.AddChild('WRT');
      XMLDocument1.SaveToFile('d:\texst.xml');
    end;
  end;
Leider geht das aber nicht, wenn zuvor eine Exception in dieser Klasse aufgetreten ist, weil da anscheinend immernoch noch der defekte, bzw. leere XML-Text im Dokument drinsteckt und das Aktivieren + nochmal Parsen nun die Exception erneut aufrufen würde.
Leider find ich aber keinen Weg TXMLDocument irgendwie zurückzusetzen (sowas wie .Clear z.B. ) :wall:


Gut, eine Lösung wäre nun einfach ein korrektes Dokument direkt reinzuladen. :angel2:
z.B.:
Delphi-Quellcode:
var i: integer;
  app: IXMLNode;
begin
  try
    XMLDocument1.LoadFromFile('d:\texst.xml');
  except
    on E: EDOMParseError do
    begin
      XMLDocument1.LoadFromXML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><WRT/>');
      XMLDocument1.SaveToFile('d:\texst.xml');
    end;
  end;
Wenn jetzt noch weitere Subnodes direkt rein sollen, dann könnte man diese jetzt mit in diesen XML-Text einfügen oder sie danach z.B. via .AddChild hinzuzufügen.

mcmichael 4. Okt 2009 12:44

Re: XML Problem beim Einlesen
 
grandioser Trick, jetzt habe ich sogar den Sinn des "LoadFromXML" verstanden.
Zitat:

XMLDocument1.LoadFromXML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><WRT/>');
Mit dieser Prozedur kann ich jetzt also eine XML-Datei neu erstellen und
ein Element eintragen oder eine vorhandene um eines ergänzen.
Klappt hervorragend.

Delphi-Quellcode:
procedure TForm2.Button5Click(Sender: TObject); //add one XML
var i:integer;
    app_new:IXMLNode;
begin
try
  XMLDocument1.LoadFromFile('d:\test.xml');
except
  on E: EDOMParseError do
    begin
    XMLDocument1.LoadFromXML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><WRT/>');
    XMLDocument1.SaveToFile('d:\test.xml');
    end;
  end;

i:=XMLDocument1.DocumentElement.ChildNodes.Count+1;
app_new:=XMLDocument1.DocumentElement.AddChild('applicant_' + IntToStr(i));
app_new.AddChild('family_name');
app_new.AddChild('given_name');
app_new.AddChild('testdate');
app_new.AddChild('language');
app_new.ChildValues['family_name']:='Meyer'+ IntToStr(i);
app_new.ChildValues['given_name']:='Harald';
app_new.ChildValues['testdate']:='13.03.2009';
app_new.ChildValues['language']:='english';
XMLDocument1.SaveToFile('d:\Test.xml');
end;

Warum aber ist in der XML-Datei (im Gegensatz zu der in Einzelschritten erzeugten)
kein Linefeed? (und kein schönes Auto-Indent)

edit: Fehler gefunden, ich mußte bei der Neu-Erstellung noch mal
Delphi-Quellcode:
   XMLDocument1.Options:=[doNodeAutoIndent];
einfügen.Seltsam eigentlich, das war in den Optionen im Objektinspektor eigentlich so eingestellt...
<?xml version="1.0" standalone="yes"?>
<WRT><applicant_1><family_name>Meyer1</family_name><given_name>Harald</given_name>.........


Großen Dank für die Hilfe!

himitsu 4. Okt 2009 12:58

Re: XML Problem beim Einlesen
 
MSXML ist da etwas eigen.

Die Option doNodeAutoIndent sorgt erstmal für das AutoIdent (Zeilenumbruch+Einrückung),
aber nur für neu erstellte Nodes (möchte man das nachträglich ändern, dann muß man praktisch das ganze Dokument neu aufbauen ... gibt hierzu aber schon ein/zwei Threads)

Also in deinem Fall dürfte es reichen, wenn du einfach im OI bei Options dieses noch mit einträgst.
(Diese Option ist zur Speicherersparnis dort standardmäßig deaktiviert)

Options des TXMLDocument (z.B. im OI)
[doNodeAutoCreate,doNodeAutoIndent,doAttrNull,doAut oPrefix,doNamespaceDecl]


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:31 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