XML Datenbindung und Substitution Groups
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich habe mit der XML-Datenbindung von Delphi einem XML-Schema entsprechende Klassen erzeugt. Allerdings gelingt es mir nicht, damit dann dem Schema entsprechende XML-Dateien so einzulesen, dass auch die entsprechenden Delphi-Objekte erzeugt werden. Genausowenig kann ich diese Delphi-Objekte aus dem Programm heraus erzeugen. Das Problem liegt dabei darin, dass im Schema sogenannte Substitution Groups verwendet werden. Ich habe mal ein stark vereinfachtes Beispielschema und die mit der Datenbindung generierte Source-Datei (Beispielschema.pas) angehängt, sowie eine Beispieldatei, die mit dem Schema validiert werden kann. Als Beispiel: Ich habe im Programm ein Objekt vom Typ IXMLBasis erzeugt (mit NewBasis) und will jetzt ein neues Element vom Typ IXMLElement1 erzeugen. Die einzige Funktion in Beispiel.pas, mit der ich ein neues Listenelement erzeugen kann, ist die Funktion Add, die aber ein IXMLListenElement zurück liefert und kein IXMLElement1. Ich habe dann versucht, eine weitere Add-Funktion zu schreiben, die ein IXMLElement1 zurückgibt:
Delphi-Quellcode:
Aber die Ausführung scheitert dann immer mit der Fehlermeldung EIntfCastError 'Interface nicht unterstützt' (ich nehme an, weil das AddItem(-1) ein IXMLListenElement zurück liefert, aber ich weiß nicht, wo ich beeinflussen kann, wass AddItem liefert).
function TXMLBasis.Add: IXMLElement1;
begin Result := AddItem(-1) as IXMLElement1; end; Umgekehrt funktioniert das Einlesen der Beispieldatei auch nicht. Das XML kann zwar ohne Fehler gelesen werden, aber IXMLBasis.Count ist Null, obwohl ja fünf Listenelemente vorhanden sein sollten. Es wird also nicht erkannt, dass Element1, Element2 und Element3 Untertypen von Listenelement sind und deshalb auch in der Liste der Listenelemente auftauchen sollten. Geht man direkt die Childnodes des XML-Dokuments durch (also an der von der Datenbindung erzeugten Struktur vorbei), dann findet man auch die entsprechenden Einträge für die Elemente. Hat jemand eine Idee, wie sich die Probleme lösen lassen? Oder gibt es vielleicht andere Delphi-Komponenten für die XML-Datenbindung, die solche Konstruktionen unterstützen? |
AW: XML Datenbindung und Substitution Groups
Woher soll das XML-DOM denn deine Klassen kennen, wenn du sie him niemals mitteilst?
Schau die mal alles mit TXMLNodeCollectionClass und TXMLNodeClass in XMLDoc an.
Delphi-Quellcode:
var X: IXMLElement1;
X := TXMLElement1.Create; // oder X := {irgendwas mit XMLNodeCollectionClass}.Create; |
AW: XML Datenbindung und Substitution Groups
Aber die Klassen stehen doch in der Datei Beispiel.pas (so wie sie von der Datenbindung erzeugt wurden)?
Und wenn ich ein Element vom Typ Listenelement hinzufügen will, klappt das ja auch mit den erzeugten Klassen. Nur bei den abgeleiteten Klassen wie Element1 klappt das nicht. Oder wie teilt man dem XML-DOM die Klassen explizit mit? Ich habe mir TXMLNodeCollectionClass und TXMLNodeClass angeschaut, aber ich werde daraus nicht so recht schlau. Aber wenn ich das richtig verstehe, dann erlaubt TXMLNodeCollectionClass nur Elemente von genau dem Typ, für den sie definiert wurde (also ListenElement), aber keine Elemente von abgeleiteten Typen (wie Element1). Wenn ich (händisch beim Debuggen) dem AddChild den richtigen Knotentyp (Element1) gebe, dann wird dieser Knoten zwar erzeugt, aber beim Einfügen in die NodeCollection (in InsertInColletion) wird dann versucht, eine neue Collection zu erzeugen, da nicht erkannt wird, dass der Typ Element1 ein von Listenelement abgeleiteter Typ ist (deshalb liefert IsCollectionItem(Node) false). Ich will aber ja erreichen, dass alle Elemente (egal ob vom Typ Element1, Element2 oder Element3) in die gleiche NodeCollection eingefügt werden (also in IXMLBasis). |
AW: XML Datenbindung und Substitution Groups
Das Databinding ist im allgemeinen leider eher Schrott und zudem veraltet (siehste ja an den generierten Implementierungen :>).
Wenn Du Dir auf Basis deines XML-Schemas die Klassen vom XML-Databinding erzeugen lässt, dann musst Du diese auch verwenden - da leitest Du also nichts mehr ab oder sonst irgendwas - Du bist an die generierte Implementierung gebunden. Und über die bereitgestellten, losen Methoden arbeitest Du dann damit: - LoadBasis Datenobjekte aus einer schemakonformen XML-Datei deserialisieren - GetBasis Datenobjekte aus einem bestehenden IXMLDocument deserialisieren (hier könnte Dein schemakonformes XML theoretisch auch Bestandteil einer anderen XML-Datei sein, aus der Du dann nur den generierten Teil herausserialisieren lässt. - NewBasis Eine neue Instanz deiner Datenobjektstruktur erzeugen lassen, um diese zu einem späteren Zeitpunkt (nach dem Arbeiten/Befüllen) wieder in ein XML-Format zu serialisieren (String/File) Sobald Du eigene Funktionalität benötigst würde ich vom XML-Databinding weggehen und mit komplett eigenen Klassen arbeiten und mich entsprechend selbst um das Serialisieren kümmern. Sofern Du nicht mit Interfaces arbeitest, kannst Du Dir diesbezüglich mal den SvSerializer anschauen: Klick mich . |
AW: XML Datenbindung und Substitution Groups
Danke für den Tip, den SvSerializer werde ich mir mal anschauen.
Ich hatte halt gehofft, dass sich die vom Databinding generierten Schnittstellen mit vertretbarem Aufwand so modifizieren lassen, dass ich doch damit arbeiten kann. Das Schema, mit dem ich arbeiten muss, ist sehr umfangreich und deshalb ist der Aufbau einer eigenen Klassenhierarchie sehr aufwendig. Zudem erzeugt das Databinding ja großteils sinnvolle Schnittstellen, nur mit der NodeCollection mit unterschiedlichen von einer Basisklasse abgeleiteten Objekten klappt es leider nicht. Unter Umständen würde es für meine Zwecke auch schon reichen, wenn ich aus einem Knoten im XML-Dokument (den ich mit Childnode selektiere) z.B ein Objekt vom Typ TXMLElement1 erzeugen könnte, aber leider ist mir das bisher auch nicht gelungen. |
AW: XML Datenbindung und Substitution Groups
Dein Problem mit einer eigenen Implementierung sind hier halt die Interfaces - sobald Du eigene Funktionalität bereitstellen möchtest, musst Du bei der Verwendung dieser immer hin und her Casten. (Da das generierte Interface vom Databinding ja nur die aus dem Schema definierten Informationen enthält).
Zitat:
Du hast also viele verschiedene Möglichkeiten: - eine Übersetzung/Kapselung von Deinen Objekten in die XML-Databinding Objekte bereitstellen. Somit trennst Du "Deine" Objektstruktur von der des XML-Databindings und kannst auf der einen Seite komfortabel mit "Deinen" Objekten arbeiten und auf der anderen Seite immer Schemakonform speichern - eine Übersetzung von Deinen Objekten in das XML-Format manuell vornehmen - eine Übersetzung von Deinen Objekten in das XML-Format von einer anderen Bibliothek übernehmen lassen, bei der das z.B. über Attribute und RTTI läuft (z.B. den SvSerializer) |
AW: XML Datenbindung und Substitution Groups
Zitat:
Den Sv-Serializer habe ich mal ausprobiert, leider habe ich da das Problem, dass bei der Serialisierung die Properties alle in Elemente des XML-Knotens umgewandelt werden, das Schema erwartet aber Attribute. Gibt es da vielleicht eine Möglichkeit, um für eine Property zu bestimmen, ob sie als Element oder als Attribut interpretiert werden soll? Ansonsten bleibt mir wohl wirklich nur, die Übersetzung manuell vorzunehmen. |
AW: XML Datenbindung und Substitution Groups
Zitat:
Zitat:
Ansonsten gibt es noch eine Implementierung in DSharp, die allerdings auch nicht komplett ist (auf der basiert auch meine eigene). Da blickt man, im vergleich zum SvSerializer auch wenigstens durch und kann manuell recht schnell etwas ändern: Klick mich (DSharp.Core.XmlSerialization.*) |
AW: XML Datenbindung und Substitution Groups
Zitat:
Ich habe die XML-Datenbindung auch früher schon mit anderen (einfacheren) Schemata benutzt und hatte da nie Probleme, aber da wurden eben keine Substitution Groups verwendet. Wenn ich bei dem Beispiel, das ich gepostet habe, mit
Delphi-Quellcode:
die XML-Datei einlese, dann sollte ja iBasis Listenelemente vom Typ IXMLListenElement enthalten (bzw. eben von den von IXMLListenElement abgeleiteten Typen IXMLElement1, ...). Diese Liste ist aber leer, iBasis.Count ist Null. Die Datenbindung schafft es leider nicht, ein IXMLElement1 einzulesen und in die Liste einzuhängen.
procedure Einlesen;
var iBasis: IXMLBasis; begin iBasis := LoadBasis('Beispieldatei.xml'); end; Umgekehrt funktioniert es eben auch nicht (bzw. ich habe es nicht hinbekommen), ein neues Element vom Typ IXMLElement1 zu erzeugen und unter iBasis einzufügen. Ich habe auch versucht, XMLDocument so zu modifizieren, dass eine Funktion Add: IXMLElement1, die ich in IXMLBasis eingefügt habe, auch ein IXMLElement1 erzeugt, aber dabei bin ich immer an einer Fehlermeldung "...Interface wird nicht unterstützt" gescheitert. |
AW: XML Datenbindung und Substitution Groups
Das hab ich in der Tat überlesen, danke für den Hinweis ;-) Hätte nicht gedacht, dass er das (die SubstitutionGroups) überhaupt in den generierten Klassen abbilden kann, aber ich werd das morgen gleich mal bei mir testen, das interessiert mich jetzt :P
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:56 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