Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   XML (https://www.delphipraxis.net/46-xml/)
-   -   XML Datenbindung und Substitution Groups (https://www.delphipraxis.net/184192-xml-datenbindung-und-substitution-groups.html)

Gor1 6. Mär 2015 08:35

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:
function TXMLBasis.Add: IXMLElement1;
begin
  Result := AddItem(-1) as IXMLElement1;
end;
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).

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?

himitsu 6. Mär 2015 09:04

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;

Gor1 9. Mär 2015 10:44

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).

alda 9. Mär 2015 22:11

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 .

Gor1 10. Mär 2015 09:03

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.

alda 10. Mär 2015 13:17

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:

Zitat von Gor1 (Beitrag 1292894)
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.

Deine Objektstruktur muss und sollte wahrscheinlich auch nicht der Schemastruktur gleichen - die Objektstruktur sollte so aussehen, dass Sie für Deinen Anwendungszweck (im Code) am besten passt und man komfortabel damit arbeiten kann. Das Serialisieren in ein entsprechendes Format ist wiederum etwas völlige anderes und kann von der Objektstruktur wie Du Sie als Entwickler beim Coden verwendest ja durchaus abweichen.

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)

Gor1 11. Mär 2015 08:41

AW: XML Datenbindung und Substitution Groups
 
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)
Das Problem ist ja, dass die von der Datenbindung generierten Objekte beim einlesen einer zum Schema passenenden Datei schon gar nicht gefüllt werden, deshalb kann ich diese auch nicht verwenden (unabhängig davon, wie meine interne Struktur dann aussieht).

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.

alda 11. Mär 2015 19:52

AW: XML Datenbindung und Substitution Groups
 
Zitat:

Zitat von Gor1 (Beitrag 1292991)
Das Problem ist ja, dass die von der Datenbindung generierten Objekte beim einlesen einer zum Schema passenenden Datei schon gar nicht gefüllt werden, deshalb kann ich diese auch nicht verwenden (unabhängig davon, wie meine interne Struktur dann aussieht).

Dann hast Du was falsche gemacht. Wie liest Du die XML-Datei denn ein? Poste mal bitte einen Snippet. Out of the Box (also mit den generierten Implementierungen) sollte erstmal alles reibungslos laufen - vorausgesetzt Du liest es über die bereitgestellten Methoden des Databindings ein ;D


Zitat:

Zitat von Gor1 (Beitrag 1292991)
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?

Ja ich glaube er kann das nicht, bin mir aber nicht sicher. Konnte zumindest auf die schnelle kein vorhandenes Attribut finden, mit dem das zu steuern wäre. Ich arbeite selbst auch an einer eigenen Implementierungen da mir die bestehenden Bibliotheken nicht gefallen und zu unflexibel sind, allerdings aufgrund zu wenig Zeit leider noch under construction ;-)

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.*)

Gor1 12. Mär 2015 08:22

AW: XML Datenbindung und Substitution Groups
 
Zitat:

Dann hast Du was falsche gemacht. Wie liest Du die XML-Datei denn ein? Poste mal bitte einen Snippet. Out of the Box (also mit den generierten Implementierungen) sollte erstmal alles reibungslos laufen - vorausgesetzt Du liest es über die bereitgestellten Methoden des Databindings ein ;D
Ich glaube, es gab da ein Mißverständnis. Mein Problem ist gerade, dass aufgrund der Verwendung von Substitution Groups im Schema der von der Datenbindung erzeugte Code nicht funktioniert, also sich damit Schema-konforme Dateien weder sinnvoll einlesen noch neu erzeugen und dann schreiben lassen.
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:
procedure Einlesen;
var iBasis: IXMLBasis;
begin
  iBasis := LoadBasis('Beispieldatei.xml');
end;
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.
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.

alda 12. Mär 2015 21:55

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