Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   XML (https://www.delphipraxis.net/46-xml/)
-   -   Delphi Objekte in XML speichern (https://www.delphipraxis.net/67754-objekte-xml-speichern.html)

EConvertError 19. Apr 2006 13:19


Objekte in XML speichern
 
Hallo!

Nachdem ich hier den Versuch, meine Objekte automatisiert in XML zu speichern aufgegeben habe, möchte ich die selbige Aufgabe "ganz normal" lösen.

Ich habe verschiedenste Objekte, deren Einstellungen ich im XML-Format abspeichern/auslesen will. Deshalb frage ich mich nun, wie ich das am Besten mache.

Meine Ideen:
  • Ich könnte alle Eigenschaften direkt auf ein DOM-Objekt (z.B. IXMLDocument) mappen (eventuell sogar mit GetDocBinding arbeiten?). Ist das empfehlenswert? Das braucht doch sicher viele Ressourcen und macht vielleicht nur bei Anwendungseinstellungen oder ähnlichem Sinn?
  • Die Eigenschaften erst mit LoadFromXml/SaveToXml in die Xml-Datei schreiben. Wenn dieser Ansatz zu bevorzugen ist: Soll ich mit einem DOM-Objekt arbeiten, oder lieber über SAX?

EDIT: Und wie manage ich am besten die untergeordneten Objekte, welche ebenfalls gespeichert werden müssen?

Hoffentlich habt ihr einige Vorschläge, wie ich das machen sollte...

Vielen Dank,
Andreas

Eisenherz 19. Apr 2006 15:17

Re: Objekte in XML speichern
 
Hallo Andreas,

nachdem du in dem anderen Thread bereits auf mein RakBinaryStreamData hingewiesen wurdest, nehme ich an, dass Du zumindest grob weißt wofür man es verwenden kann.

Um dein XML-Problem zu lösen kannst du prinzipiell genauso vorgehen, wie ich bei RakBinaryStreamData. Der Unterschied besteht in der Hauptsache darin, dass bei dir ein XML-Format und bei RakBinaryStreamData ein binäres Format abgespeichert wird. Bei beiden Wegen kann man mit Hilfe von Tags eine hierarchische Struktur anlegen, womit das Problem der Unterobjekte gelöst wäre.
Ich gehe immer gern den Weg, dass die Klassen selbst wissen, wie sie sich "abspeichern" können. Das ist jetzt vielleicht etwas missverständlich, da die meisten unter "Abspeichern", das Speichern in einer Datei oder eine andere Serialisierung verstehen. Das "Abspeichern" ist im ersten Schritt aber noch keine Serialisierung, sondern ein Umwandlen in ein anderes Datenformat. Bei RakBinaryStreamData werden die Daten der Objekte in eine hierarchische Objektstruktur der Klassen von RakBinaryStreamData umgehängt. Bei XML werden die Daten der Objekte in eine hierarchische Objektstruktur der von dir verwendeten XML-Klassen umgehängt.
Erst danach wird durch den Aufruf der entsprechenden Methode die Serialisierung durchgeführt. Bei RakBinaryStreamData kommt dabei ein binärer KuddelMuddel heraus, bei XML eine Textdatei.

Aber wieder zurück dazu, dass die Klassen die Daten selbst "abspeichern", sprich in ein anderes Format umhängen. Dazu verpasse ich den Klassen immer die Methode

Code:
procedure SaveToBinaryTag(Tag: TRakBinaryTag);
Für XML hattest du in dem anderen Thread ja schon etwas ähnliches angedacht, nämlich

Code:
procedure SaveToXML(const XmlDoc: IXMLDocument);
Hier darfst du als Parameter aber nicht die Document-Klasse verwenden, sondern die Tag-Klasse deines XML-"Parser". (so nebenbei: ich verwende bevorzugt OpenXML)


Ich hoffe das reicht als Anstoß

EConvertError 19. Apr 2006 18:24

Re: Objekte in XML speichern
 
Danke für die Antwort!

Dein Vorschlag ist mir soweit klar, bis auf diesen Satz:
Zitat:

Hier darfst du als Parameter aber nicht die Document-Klasse verwenden, sondern die Tag-Klasse deines XML-"Parser".
Meinst du, dass ich lieber so eine Methode haben sollte:
Delphi-Quellcode:
SaveToXml(const ParentNode: IXMLNode);
Wenn ich es mir recht überlege, ist das sicher eine gute Idee, da ich damit schon das Problem mit den untergeordneten Objekten gelöst hätte. Dann habe ich sozusagen ein Basisklasse, von der ich mir alle zu speichernden Klassen ableite, und eine "Serialisierer"-Klasse, die das XML-Dokument erzeugt und die Speicherroutinen aufruft. Und die Eigenschaften sollen nicht direkt auf ein XML-Dokument gemappt werden?

Habe ich das richtig verstanden?

Zitat:

so nebenbei: ich verwende bevorzugt OpenXML
Damit wären wir bei meinem zweiten Problem: Wie soll ich die XML-Dateien lesen/schreiben? Soll ich lieber einen SAX-Ansatz probieren, oder soll ich lieber den DOM-Ansatz (welche Implementation ist ja egal und OT) verwenden?

Vielen Dank,
Andreas

marabu 19. Apr 2006 19:17

Re: Objekte in XML speichern
 
Hallo Andreas,

deine erste Frage hast du dir schon fast selbst beantwortet: nimmst du das Document als Parameter für die Serialisierung, dann wirst du Probleme beim Speichern von Substrukturen und endlich rekursiven Strukturen bekommen.

DOM oder SAX? Das Document Object Model bietet dir Zugriffsmethoden und einfache Transformationsmöglichkeiten, baut aber seinen Content komplett im Hauptspeicher auf. Der SAX-Parser arbeitet mit einer Ereignis-Schnittstelle und kann XML-Dokumente im streaming mode verarbeiten. Da deine Daten bereits eine interne Repräsentation besitzen, wäre ein DOM-Document nur eine weitere Darstellung und damit Speicherverschwendung - es sei denn du nutzt die DOM features irgendwie.

Grüße vom marabu

EConvertError 20. Apr 2006 19:16

Re: Objekte in XML speichern
 
Danke für die Antwort.

Ok, somit ist die erste Frage für mich ausreichend geklärt. Dankeschön.

Dann werde ich versuchen, das ganze mittels SAX zu lösen. Leider habe ich mit SAX noch keine Erfahrung (die Grundprinzipien sind mir bekannt, mehr leider auch schon nicht). Wie funktioniert das beispielsweise mit folgender Funktion:
Delphi-Quellcode:
procedure SaveToXml(const IXMLNode)
IXMLNode gibt es ja nur in DOM...
Wie manage ich untergeordnete Objekte mit SAX?

Besitzt Delphi 7 Professional eine eingebaute SAX-Implementation (so wie es für DOM IXMLDocument, bzw. TXMLDocument gibt), oder muss ich auf externe Komponenten, etc. zurückgreifen?
Wenn es das nicht gibt, ist es eine gute Idee MSXML (Typbibliothek importieren) zu nutzen?

Andreas

marabu 20. Apr 2006 19:38

Re: Objekte in XML speichern
 
Du kannst die MS SAX-Implementierung verwenden, wenn du die MSXML?.DLL importierst. Um mit SAX warm zu werden, solltest du Zugriff auf den Platform SDK haben. Oder lade dir den XML SDK - der ist bedeutend kleiner (etwa 6 MB, wenn ich mich nicht irre).

Baue nicht gleich deine Anwendung um, sondern überlege was du brauchst und schreibe dir eine Demo-Anwendung, die das umsetzt. Das macht es auch einfacher dir zu helfen, falls du noch Hilfe brauchst.

Grüße vom marabu

EConvertError 21. Apr 2006 13:25

Re: Objekte in XML speichern
 
Vielen Dank für die Antwort!

Ok, da es keine Delphi-SAX-Lösung (keine ohne Zusatzkomponenten, zumindest) gibt, werde ich wohl die MS-SAX-Implementation nutzen.

Ich werde mich da mal schlau lesen, was SAX betrifft und bei Fragen einen neuen Thread aufmachen. Klar baue ich nicht gleich meine gesamte Anwendung um. :wink:

Vielen Dank,
Andreas

EConvertError 22. Apr 2006 18:56

Re: Objekte in XML speichern
 
Hallo noch einmal!

Noch eine Frage:
Kann ich MSXML 6.0 auch auf Windows NT Rechnern installieren? Das fertige Programm soll auch unter Windows NT laufen.

Danke,
Andreas

mirage228 22. Apr 2006 19:00

Re: Objekte in XML speichern
 
Zitat:

Zitat von EConvertError
Hallo noch einmal!

Noch eine Frage:
Kann ich MSXML 6.0 auch auf Windows NT Rechnern installieren? Das fertige Programm soll auch unter Windows NT laufen.

Danke,
Andreas

Hi,

Laut der Downloadseite von Microsoft zu MSXML 6 nicht:
http://www.microsoft.com/downloads/d...displaylang=en

mfG
mirage228

marabu 22. Apr 2006 19:12

Re: Objekte in XML speichern
 
Hallo.

Da überschneiden sich die Anforderungen etwas. MS liefert MSXML6 nur als Installer Package aus und dieses verlangt den Installer 3.1, der erst ab Win2K eingesetzt werden kann. Auf Seiten von MSXML6 selbst ist von MS keine Aussage mehr zu NT zu erwarten, da dieses Betriebssystem aus Sicht von MS bereits gestorben ist. Würde mich nicht wundern, wenn sich die etwa drei libraries auf NT per Hand installieren ließen, aber warum den Aufwand - MSXML4 tut es auch noch eine Weile.

Grüße vom marabu

EConvertError 22. Apr 2006 19:15

Re: Objekte in XML speichern
 
Das auf der Downloadseite habe ich auch schon gesehen, aber ich habe doch noch irgendwie gehofft. :wink:
Egal, wie marabu schon geschrieben hat, ist MSXML auch noch OK.

Ich lese gerade in der MSDN Library für Visual Studio 2005 über die SAX-Implementation von MSXML.
Dort steht, dass SAX nur zum Lesen, aber nicht zum Schreiben geeignet ist. Besitzt MSXML nichts, was mit dem XmlWriter aus .net vergleichbar ist?

Einfach eine Klasse, mit der man Xml-Dateien schreiben kann, ohne sich ein DOM-Objekt erzeugen zu müssen...

Andreas

marabu 22. Apr 2006 19:25

Re: Objekte in XML speichern
 
Ab SAX Version 2 gibt es den MXXMLWriter - der sollte das sein, was du suchst. In der Dokumentation wird er manchmal als SAXXMLWriter bezeichnet...

marabu

EConvertError 23. Apr 2006 16:00

Re: Objekte in XML speichern
 
Ok, werde ich mir gleich anschauen...

EConvertError 23. Apr 2006 17:23

Re: Objekte in XML speichern
 
So, ich habe mich jetzt etwas mit SAX auseinandergesetzt.

Habe ich folgendes richtig verstanden:
Wenn ich SAX verwende, schreibe ich in ein XML-Dokument so wie z.B. in einen Stream. Das heißt, um meine untergeordneten Objekte in das XML-Dokument zu speichern, übergebe ich der Methode meinen MXXMLWriter und mein Objekt schreibt sich an die aktuelle Stelle im MXXMLWriter.

Wenn ich also einen genauen ParentNode angeben will, muss ich DOM verwenden. Selbiges gilt natürlich auch für das Lesen. Das bringt mich zum Überlegen, ob ich nicht doch DOM verwenden sollte. :gruebel:


Außerdem habe ich ein Problem mit dem MXXMLWriter:
Der unterstützt von Haus aus die Methoden zum Schreiben des XML-Dokuments nicht. Aber man kann die Handler-Interfaces zum MXXMLWriter-Objekt casten. Das Codebeispiel aus der MSDN Library ist aber leider in Visual Basic und dieser Sprache bin ich leider nicht mächtig.
Dort werden die Interfaces IVBSAXContentHandler, IVBSAXDTDHandler, IVBSAXLexicalHandler, IVBSAXDeclHandler, IVBSAXErrorHandler dem MXXMLWriter zugewiesen.
Code:
Set cnth = wrt 'Dim cnth As IVBSAXContentHandler
Wenn ich das in Delphi versuche, erhalte ich die Exception 'Schnittstelle nicht unterstützt'. Ich habe auch die Interfaces ISAXContentHandler, etc. (also ohne VB probiert) - ohne Erfolg.

Andreas

EConvertError 26. Apr 2006 18:41

Re: Objekte in XML speichern
 
*push*

marabu 26. Apr 2006 21:35

Re: Objekte in XML speichern
 
Hallo Andreas,

fertigen Code für SAX2 kann ich dir heute keinen geben, vielleicht komme ich morgen dazu. Er wird sich in etwa so anfühlen:

Delphi-Quellcode:
uses
  MSXML2;

type
  TDemoClass = class(Tobject)
    FSomeInteger: Integer;
    FSomeString: String;
    FDemoClass: TDemoClass;
    procedure Serialize(cnth: ISAXContentHandler);
    procedure Deserialize(cnth: ISAXContentHandler);
  end;
Dazu kommt noch soetwas:

Delphi-Quellcode:
procedure TDemoForm.ButtonClick(Sender: TObject);
var
  wrt: IMXWriter;
  cnth: ISAXContentHandler;
begin
  wrt := CoMXXMLWriter.Create;
  cnth := wrt as ISAXContentHandler;
  cnth.startDocument;
  // ...
end;
Für die DOM-Schnittstelle kannst du vielleicht selbst etwas bauen - oder doch nicht?

Gute Nacht

marabu

marabu 27. Apr 2006 18:59

Re: Objekte in XML speichern
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Andreas,

ich habe eine kleine Demo erstellt, welche dir zeigt, wie du ein verschachteltes Objekt mit SAX2 speichern kannst - das Laden habe ich erstmal weggelassen. Bei Bedarf musst du dich halt nochmal bemerkbar machen.

Grüße vom marabu

EConvertError 27. Apr 2006 19:12

Re: Objekte in XML speichern
 
Danke für die Antwort!

Wahnsinn, eien Demo wäre super! *freu*
Edit: *Demo gleich anschau*

Ob ich jetzt DOM oder SAX benutze überlege ich mir selbst, aber SAX möchte (muss?) ich sowieso lernen.

Klar, DOM ist mir schon in allen Varianten vertraut (Delphi's "eingebaute" Lösung, MSXML).

Andreas

EConvertError 27. Apr 2006 19:23

Re: Objekte in XML speichern
 
Sieht soweit sehr vielversprechend für mich aus!

Muss ich wrt.output "manuell" in einen FileStream schreiben, oder besitzt die MXXMLWriter-Klasse eine Funktion, die das direkt macht? Oder kann ich Output auf meinen FileStream umleiten?

Könntest du mir erklären, was das für eine Art von String-Paramemter-Übergabe ist:
Delphi-Quellcode:
cnth.endElement(Word(sEmpty[1]), 0, Word(sEmpty[1]), 0, Word(sElement[1]), Length(sElement));
Ich bin es eher gewöhnt, einen String als PChar an eine API-Funktion zu übergeben...

Ansonsten ist mir Alles klar und ich werde mich selbstverständlich wieder ordentlich damit auseinander setzen, bevor ich weitere Fragen stelle (Ich hoffe natürlich, dass ich das nicht mehr tun muss :wink: ).

Vielen Dank,
Andreas

marabu 28. Apr 2006 10:35

Re: Objekte in XML speichern
 
Hallo Andreas,

Zitat:

Zitat von EConvertError
Oder kann ich Output auf meinen FileStream umleiten?

eine clevere Frage. Ich habe den entsprechenden Code mal angepasst:

Delphi-Quellcode:
begin
  // ...
  fn := 'c:\daten\dp\sax-demo.xml';
  fs := TFileStream.Create(fn, fmCreate);
  wrt := CoMXXMLWriter.Create;
  cnth := wrt as ISAXContentHandler;
  wrt.output := TStreamAdapter.Create(fs, soReference) as IStream;
  cnth.startDocument;
  dc.Serialize(cnth);
  cnth.endDocument;
  wrt.flush;
  fs.Free;
  // ...
end;
Die wichtige Zeile ist die, in der eine IStream-Schnittstelle an wrt.output übergeben wird.

Zitat:

Zitat von EConvertError
Könntest du mir erklären, was das für eine Art von String-Paramemter-Übergabe ist: cnth.endElement(Word(sEmpty[1]), 0, ...
Ich bin es eher gewöhnt, einen String als PChar an eine API-Funktion zu übergeben...

Genau das passiert hier, allerdings nicht für einen Single-Byte-Character String, sondern für einen Double-Byte-Character String.

Grüße vom marabu

EConvertError 28. Apr 2006 18:39

Re: Objekte in XML speichern
 
Danke!

Zitat:

eine clevere Frage
Ich gebe zu, dass ich schon in der Dokumentation über IStream gelesen habe. Ich wusste nur noch nicht genau wo ich einen IStream herbekomme und wie ich diesen dem MXXMLWriter übergebe.

Ansonsten ist jetzt Alles klar, danke! :thumb:

Bei Bedarf melde ich mich wieder, wenn das OK ist.

Vielen Dank,
Andreas

PS: Ich habe mich jetzt für SAX entschieden.

EConvertError 29. Apr 2006 14:08

Re: Objekte in XML speichern
 
Hallo noch einmal!

Ich habe noch eine Frage bzgl. Lesen mit SAX.

In der Demo gibt es ja die Funktion:
Delphi-Quellcode:
procedure TDemoClass.Deserialize(cnth: ISAXContentHandler);
Ich habe mir einige Delphi-SAX Beispiele angesehen und da wurde immer das Interface ISAXContentHandler selbst implementiert. Mit den Funktionen des Interfaces wird man praktisch wie bei ganz normalen Delphi-Events informiert, was sich in der XML-Datei befindet.

Wäre es in diesem Fall nicht sinnvoller, wenn die Funktion einen ISAXXMLReader als Parameter nimmt und die zu deserialisierende Klasse ISAXContentHandler selbst implementiert?

Noch praktischer wäre es für mich, wenn man mit MSXML so etwas Ähnliches machen könnte wie mit dem XmlReader in .net:
Dort kann ich nämlich das Pull-Modell verwenden, sodass ich nicht auf Events reagieren muss, sondern ähnlich wie aus einem FileStream lesen kann:
Code:
while (MyXmlReader.Read())
{
  string mystring = MyXmlReader.ReadElementString();
}
Oder noch allgemeiner gefragt: Wie würdest du/würdet ihr das Herauslesen mit SAX organisieren?

Vielen Dank,
Andreas

EConvertError 30. Apr 2006 12:28

Re: Objekte in XML speichern
 
Hallo!

Ich habe jetzt etwas bzgl. Pull-Modell nachgeforscht und leider Hinweise gefunden, dass es so etwas in MSXML nicht gibt, sondern eben erst seit .net. :?

Jetzt frage ich mich natürlich, wie ich das Herauslesen mit SAX managen soll. Muss wirklich jede zu deserialisierende Klasse ISAXContentHandler implementieren?
Das würde aber auch ganz andere Probleme nach sich ziehen:
Denn mit der Rückkehr der Methode Deserialize() wäre noch nicht sichergestellt, dass ich mit dem Deserialisieren fertig bin (da ja über Callback-Methoden/Events gearbeitet) wird. :gruebel:

Wie würdet ihr/würdest du also das Herauslesen organisieren?

Vielen Dank,
Andreas

marabu 30. Apr 2006 22:07

Re: Objekte in XML speichern
 
Hallo Andreas,

mit dem Hinweis auf das in MS SAX2 implementierte push model legst du den Finger in eine Wunde. In meiner Demo arbeite ich mit EINEM root object - nur so macht die gezeigte Methode Serialize() überhaupt Sinn. Die Signatur der Methode Deserialize() in meinem Beispiel ist übrigens durch Copy & Paste entstanden und sollte kein versteckter Hinweis auf eine Machbarkeit sein. Selbst wenn wir eine einzige Objekt-Verwaltungsinstanz als gegeben annehmen, würde ich angesichts der MS SAX2 Implementierung wohl eher auf zwei externe Funktionen setzen:

Delphi-Quellcode:
type
  TObjectManager = class; // to be coded

var
  root: TObjectManager;
  s: TStream;
  fn: TFileName;

begin
  fn := ChangeFileExt(ParamStr(0), '.xml');
  s := TFileStream.Create(fn, fmCreate or fmShareDenyWrite);
  root := TObjectManager.Create;
  // ... fill me up
  Serialize(root, s);
  root.Free;
  s.Free;
  s := TFileStream.Create(fn, fmOpenRead or fmShareDenyWrite);
  root := Deserialize(s);
  // ... dump root
  root.Free;
  s.Free;
end;
Gute Nacht

marabu

EConvertError 1. Mai 2006 13:25

Re: Objekte in XML speichern
 
Danke für die Antwort!

Dann bin ich also genau richtig gelegen mit der Vermutung, dass es keinen SAX-Parser mit Pull-Modell gibt. :?

Ganz habe ich deinen Code noch nicht verstanden. Ist ObjectManager die zu serialisierende Klasse, die die Unterobjekte enthält?

Wie soll das Serialize() als externe Funktion funktionieren? Normalerweise weiß doch das Objekt am Besten, wie es gespeichert werden soll. Das Selbe frage ich mich was Deserialize() betrifft. Oder meinst du, dass ich mit published Elementen & Typinformationen arbeiten soll?

Könntest du mir da ein ganz kurzes Beispiel schreiben (nur kurz um den Grundgedanken etwas ausführlicher zu erkären; muss nicht funktionsfähig sein)?


Sonst fällt mir nur diese Möglichkeit ein, dass die zu deserialisierenden Klassen selbst die Interfaces implementieren (oder irgendwie anders mittels Events Daten erhalten) und dann über ein OnDeserialized-Event sagen, wenn sie fertig sind. Was meinst du?

Noch besser wäre es, wenn man irgendwie erreichen könnte, dass Deserialize() erst zurückkehrt, wenn alles fertig ist.

Vielen Dank,
Andreas

PS: Im ärgsten Notfall muss ich doch auf DOM zurückgreifen, was ich aber verhindern möchte.

EConvertError 3. Mai 2006 17:54

Re: Objekte in XML speichern
 
Hallo!

Ich habe mich weiterhin mit diesem Problem beschäftigt.
So wie ich das sehe, bekomme ich die Events von SAX an eine zentrale Stelle, weshalb sich die einzelnen Objekte nicht wirklich selbst deserialisieren können (wie sollen sich sonst untergeordnete Objekte die Daten holen können?).

D.h., dass ich die Objekte "von außen" (also erzeugen und dann die Eigenschaften von außen zuweisen) zusammenbauen muss. Das scheint mir reichlich "unelegant" und unsauber zu sein, wenn man bedenkt, dass ich einfach nur ein paar Objekte in XML speichern (und wieder von dort laden will).

Womöglich ist es klüger, wenn ich doch auf DOM setze.

Wobei sich hierbei die Frage stellt, ob es nicht besser wäre, die Properties direkt auf ein XML-Dokument zu mappen. Zumindest dort, wo es um primär um die Speicherung von Daten geht (z.B. Anwendungseinstellungen).

Was meinst du/meint ihr dazu?

Vielen Dank,
Andreas

mschaefer 3. Mai 2006 18:12

Re: Objekte in XML speichern
 
Moin zusammen,

Auch wenn wenn es nicht hart am aktuellen Problem liegt: Eigentlich geht es doch meist nicht darum alle Eigenschaften in XML zu giesen, sondern nur solche, die auch im Programm änderungen erfahren und damit Nutzereinstellungen speichern. Folglich müßte man an einem Object auch eine Namensliste mit den zu speichernden Properties haben. Jedenfalls scheint mir da noch ein Zwischenschritt sinnvoll.

Grüße // Martin

EConvertError 3. Mai 2006 18:25

Re: Objekte in XML speichern
 
Vielen Dank für diese Idee!

Das ist eine interessante Anregung, die ich mir gründlich durch den Kopf gehen lassen muss - auch wenn es nicht, wie du schon geschrieben hast, mein direktes Problem ist.
Allerdings möchte ich anmerken, dass ich nicht nur Anwendungsdaten speichern möchte, sondern auch alle möglichen anderen Objekte. Wenn ich diesbezüglich mehr Informationen geben soll, bitte nur Bescheid geben - meine Vorhaben sind nicht geheim. :wink:

Mein Problem ist sozusagen: Bei DOM werden die gesamten Daten nochmal in den Speicher geladen, wodurch sie dann dort doppelt vorhanden sind: 1) in dem Objekten selbst und 2) in dem DOM-Objekt.
Freilich wäre bei den allermeisten Objekten diese Ineffektivität verkraftbar, aber wenns besser geht...

Mit SAX habe ich das oben beschriebene Problem, dass das Herauslesen (Schreiben ginge ja bereits pefekt) sehr schwierig wird.

Wenn ich also bei DOM bleibe wäre es durchaus denkbar, dass ich die Daten gleich auf ein XML-Objekt mappe, da dann die Daten nur 1-mal vorhanden sind. Bei Objekten, bei denen es hauptsächlich um die Daten geht (deshalb habe ich die Anwendungsdaten angesprochen), wäre dies vielleicht eine Möglichkeit. Bei anderen, normalen Objekten, ist das wahrscheinlich wieder Ressourcenverschwendung.

*bereits vollkommen verzweifelt bin*

Hoffentlich könnt ihr mir helfen,
Andreas

marabu 3. Mai 2006 21:17

Re: Objekte in XML speichern
 
Hallo Andreas,

ich habe noch ein wenig über deinem Problem meditiert und bin für mich zu dem Schluß gekommen, dass eigentlich alle wichtigen Aspekte in deinem thread schon einmal angesprochen worden sind.

Dass dir die Serialisierung via SAX gefällt kann ich nachvollziehen. Dass du die Deserialisierung gerne auf die gleiche Weise realisieren möchtest auch. Wenn du weiterhin mit SAX die Persistenz über Methoden der persistenten Klassen bzw. Objekte realisieren willst, dann wird die TDemoClass so oder ähnlich aussehen müssen:

Delphi-Quellcode:
type
  TDemoClass = class(TInterfacedObject, IDispatch, IVBSAXContentHandler)
  private
    // IVBSAXContentHandler
    procedure _Set_documentLocator(const Param1: IVBSAXLocator); safecall;
    procedure startDocument; safecall;
    procedure endDocument; safecall;
    procedure startPrefixMapping(var strPrefix: WideString; var strURI: WideString); safecall;
    procedure endPrefixMapping(var strPrefix: WideString); safecall;
    procedure startElement(var strNamespaceURI: WideString; var strLocalName: WideString;
                           var strQName: WideString; const oAttributes: IVBSAXAttributes); safecall;
    procedure endElement(var strNamespaceURI: WideString; var strLocalName: WideString;
                         var strQName: WideString); safecall;
    procedure characters(var strChars: WideString); safecall;
    procedure ignorableWhitespace(var strChars: WideString); safecall;
    procedure processingInstruction(var strTarget: WideString; var strData: WideString); safecall;
    procedure skippedEntity(var strName: WideString); safecall;
    // IDispatch
    function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
    function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
    function GetIDsOfNames(const IID: TGUID; Names: Pointer;
      NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
      Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
    // other
    // ...
  public
    SomeInteger: Integer;
    SomeString: String;
    DemoClass: TDemoClass;
    procedure Serialize(writer: IMXWriter);
    procedure Deserialize(reader: IVBSAXXMLReader);
    // class function Deserialize(reader: IVBSAXXMLReader): TDemoClass; // 
    destructor Destroy; override;
    procedure Show; // for debugging purposes
  end;
Eventuell brauchst du dann noch eine ähnlich aufgebaute HelperClass um das Henne-Ei-Problem zu umgehen oder die Methode Deserialize() muss als class function implementiert werden. Außerdem wird ein Stack für die Umschaltung des ContentHandler in der Methode Deserialize() benötigt.

Ob eine Implementierung auf Basis von DOM insgesamt weniger Lines-Of-Code aufweist, dass kann ich im Augenblick noch garnicht erkennen. Implementieren würde ich beides. Hinterher weiß man mehr.

Gute Nacht

marabu

mschaefer 3. Mai 2006 22:46

Re: Objekte in XML speichern
 
Very Spätmoin,

Bin immer wieder beeindruckt, was Marabu hier zu Tage zaubert. Mag aber trotzdem mal eine vielleicht etwas naive Frage stellen. Wieso geht für sowas nicht eine von den sagen wir noch schlanken kleinen XML-Komponenten. Kenne mich aktuell weder mit SAX noch DOM sonderlich gut aus, deshalb würde ich dies zunächst mal mit der TGmXML-Komponente angehen (was vielleicht auch viel zu trivial ist).

TgmXML bei Torry

Beispielanwendung


Tja was spricht dagegen?


// Viele Grüße in die Runde // Martin

EConvertError 4. Mai 2006 11:57

Re: Objekte in XML speichern
 
Danke für Alles!

@mschaefer:
In der Tat habe ich schon einmal daran gedacht mir selbst so einen kleinen SAX-Parser (nach dem Muster des XMLReader in .net) zu schreiben. Da hätte ich mir solche schlanken XML-Komponenten angesehen.
Kann leicht sein, dass ich das noch tun werde, wobei diese Aufgabe sicher nicht trivial ist. Selbst schreiben deshalb, weil ich entweder einen "richtigen" Parser, wie MSXML verwenden will, oder ganz auf Fremdkomponenten verzichten will. Auf jeden Fall reizt mich das sehr...mal sehen ob mal was draus wird... :mrgreen:

@marabu:
Ich glaube, dass ich jetzt genug Informationen habe, um selbst eine Entscheidung zu fällen. Dass ich Deserialisierung und Serialisierung auf die gleiche Weise mache, ist meiner Meinung nach logisch. Um das Henne-Ei-Problem zu lösen, überlade ich einfach den Konstruktor.

Mir kommt es nicht unbedingt auf weniger Lines-Of-Code an, sondern auf die eleganteste Lösung. :mrgreen:

Ein letztes Problem bleibt allerdings noch für mich:
Ist es eine gute Idee in einem Projekt sowohl SAX aus MSXML als auch IXMLDocument (DOM) aus der Unit XMLDoc zu verwenden (jeweils für verschiedene Zwecke natürlich)?
Delphi-Quellcode:
var doc: IXMLDocument
begin
  doc := NewXMLDocument;
end;
Oder habe ich dann sozusagen doppelten Code und ich sollte besser direkt die MSXML-DOM Implementation verwenden?
Weil das TXMLDocument ja auch MSXML unterstützt, aber ich bei IXMLDocument nicht sicher bin, welche Implementation verwendet wird. Und für nicht visuelle Komponenten empfiehlt Borland ja IXMLDocument statt TXMLDocument (gab mal so einen Artikel auf CodeCentral).

Ansonsten betrachte ich das Problem als erledigt. :thumb:

Vielen Dank,
Andreas

marabu 4. Mai 2006 12:18

Re: Objekte in XML speichern
 
Hallo Andreas,

ich würde versuchen in einem Projekt entweder mit MSXML oder mit MSXML2 zu arbeiten. Den von dir erwähnten Artikel kenne ich jetzt nicht, aber der wesentliche Vorteil der Borland XML Implementierung ist die Unabhängigkeit vom DOM Vendor MS.

Wenn du dich an der Implementierung eines XML-Parsers versuchen willst, dann wäre eine passive Komponente das richtige für dich. Der Vorteil, den ich auch in einem Kundenprojekt genutzt habe, ist die Stop-And-Go Fähigkeit - ein SAX-Parser kennt keine Bremse.

marabu

EConvertError 4. Mai 2006 18:11

Re: Objekte in XML speichern
 
Vielen Dank!

Ok, dann werde ich versuchen, die XML-Implementationen in einem Projekt nicht zu mischen. Ich finde den Artikel auf CodeCentral nicht mehr, aber es geht darin darum, dass ein während der Laufzeit dynamisch erzeugtes TXMLDocument zu AccessViolations führt. Laut Borland liegt die Lösung darin, das IXMLDocument Interface zu verwenden, was eigentlich auch super funktioniert.

Ja, ich denke, dass ich mich an einem XML-Parser versuchen will. Er soll so ähnlich wie SAX den Streaming-Ansatz verwenden, aber nicht über Events arbeiten, sondern über das Pull-Modell. D.h. ähnlich wie in einem TFileStream möchte ich von einem XML-Element zu nächsten navivigieren. Damit wäre auch die Stop-And-Go Fähigkeit dabei.
Hoffentlich wird was draus...

Somit betrachte ich meine Fragen als beantwortet und versuche mich an dem Parser. Bei Fragen eröffne ich einen neuen Thread, da das den Rahmen dieses Threads wohl sprengen würde.

Ich bedanke mich hiermit noch einmal herzlich,
Andreas


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