XML Schema und Objektorientierung
XML Schema und Objektorientierung Einführung.NET Java
Einführung: Einsatzbereiche In folgenden Situationen kann eine sehr enge und ähnliche Abbildung von Daten Sinn machen: Die gleichen Daten sollen in mehreren Anwendungen genutzt werden und werden über XML-/Text-Nachrichten (typischerweise Web Services) ausgetauscht und nicht durch Zugriff auf die gleiche Datenbank. Eine Software soll fähig sein, offline und online arbeiten zu können, sodass online zu speichernde Daten möglichst leicht zu serialisieren sein sollen, um sie dann wieder in Objekte einzulesen und dann oder direkt aus der serialisierten Darstellung an die zentrale Datenbank zu senden. Eine Software soll ein eigenes Dateiformat besitzen, welches man möglichst einfach aus Objektzuständen erstellen möchte.
Einführung: Prinzip Klasse Collection Klasse Klasse Klasse Collection / Array Collection-Element Eigenschaften einer Klasse
Einführung: Prinzip In der Abbildung hat man über eine XML Schema-Darstellung eine weitere Ebene eingefügt, welche eine Hierarchie in XML in Klassen mit Eigenschaften zerlegt. Das Vorgehen ist hierbei recht simpel: Jede Hierarchie-Ebene bzw. jeder Teilbaum steht für eine Klasse. Ein Element, das einen Textknoten enthält, und ein Attribut betrachtet man als Eigenschaften einer Klasse. Es ist lediglich bei der Übertragung von Daten festzuhalten, welche Eigenschaften nun Elemente und welche Attribute sind. Ein Element, das selbst wieder Kind-Elemente hat, stellt eine Eigenschaft einer Klasse dar, die ein Objekt enthält. Eine Gruppe von Geschwister-Elementen stellt die Eigenschaften einer Klasse dar. Dabei unterscheidet man zwischen primitiv typisierten und über eine Klasse typisierte Eigenschaften. Kann ein Element mehrfach im Instanzdokument erscheinen, ist es als Collection oder Array zu betrachten.
Einführung: Gemeinsamkeiten Als Zusammenfassung dieses Abschnitts kann man nun noch beide Welten die objektorientierte und die XML Schema-Welt zusammen in eine Abbildung bringen. Sie zeigt die folgenden Aspekte: Das Datenmodell und damit die Strukturdefinitionen sind in XML Schema und in der Klassendefinition hinterlegt. Es ist nicht immer notwendig, eine 1:1-Zuordnung herzustellen, denn oft wird nur ein Teil der Daten in XML oder der Software benötigt. Die Instanzen sind dann entweder die XML-Instanzdokumente, da sie gültige Entsprechungen des XML Schema sind, oder die Objekte, da sie auf Basis der Klassen instanziiert wurden. Die Erzeugung von XML Schema-Dateien aus den Klassendefinitionen oder umgekehrt, lässt sich durch schon vorhandene Generator-Software durchführen. Ebenfalls vorhandene weitere Software nutzt Anmerkungen in den Klassen oder auch der XML Schema-Datei, um die Instanzen ebenfalls bei Bedarf zu überführen.
Generator - Software Instanz(daten) Modell Einführung: Gemeinsamkeiten <> schema { class XM- Daten Objekte XML Schema -> Klasse Automatisch oder benutzerdefinierte Anmerkungen in Schema Klasse -> XML Schema Automatisch oder benutzerdefinierte Anmerkungen in Klasse
Einführung: Generierung und (Un)Marshalling <> schema + Erweiterungen für Anpassung der Bindung XML Schema- Generator Klassen-Generator { class + Annotationen für Anpassung der Bindung <> XML data Marshaller Unmarshaller
Einführung: <> XML Schema- Generator Generierung schema und (Un)Marshalling Klassen-Generator { class + Erweiterungen für Anpassung der Bindung + Annotationen für Anpassung der Bindung Marshaller <> XML data Unmarshaller
Einführung: Generierung und (Un)Marshalling <> schema + Erweiterungen für Anpassung der Bindung XML Schema- Generator Klassen-Generator { class + Annotationen für Anpassung der Bindung <> XML data Marshaller Unmarshaller
Einführung: Zusammenfassung Die nächste Abbildung fasst die verschiedenen Konzepte noch einmal zusammen. Die Klassen werden an das XML Schema gebunden und umgekehrt. Dafür gibt es Kommandozeilentools zur Generierung der fehlenden Dateien. Die XML-Instanzdaten folgen ihrem XML Schema. Die Objekte folgenden ihren Klassendefinitionen. Zwischen den Instanzdaten in Objekten und XML findet eine Umwandlung statt Marshalling und Unmarshalling genannt. Dafür gibt es Framework-Klassen zur Umwandlung der Instanzdaten unter Rückgriff auf die Bindungsinformationen.
Einführung: Zusammenfassung XML Schema <> schema definiert folgt Bindung { class definiert folgt <> XML data xml Unmarshalling (Deserialisierung) Marshalling (Serialisierung) Objekte
Einführung: Ausblick Datenbanken Datenbank (De)Serialisierung XML data <> Sicht XML- Schnittstelle (Un)Marshalling Tabelle 1 Tabelle 2 SQL- Schnittstelle Ergebnismenge (Objekte) Umwandlung SQL-Befehle und Daten Objekte Relationale Modellierung XML- Modellierung Objektorientierte Modellierung Gemeinsame Daten-Elemente
Einführung: Ausblick Datenbanken Die Abbildung stellt zwei verschiedene Vorgehensweisen dar: Setzt man den traditionellen Weg über SQL und Ergebnismengen ein, so ruft man Daten in einem nicht weiter typisierten Format ab und formt aus diesen dann die benötigten Objektstrukturen. Sollen Daten wieder zur Datenbank geschickt werden, muss man sie in einzelne SQL-Anweisungen umwandeln, die dann die relationalen Strukturen referenzieren und die entsprechenden Daten einhalten. Setzt man auf die XML Schema-Bindung, dann erhält man direkt von der Datenbank das benötigte XML, welches dann in die benötigten Objekte umgewandelt wird. Der umgekehrte Weg ist genauso einfach, denn hier wandelt man die Objektstruktur in XML um und übergibt dieses an die Datenbank, die dann die XML- Daten relational zerlegen muss.
Fragen...
XML Schema und Objektorientierung Einführung.NET Java
.NET: Prinzip der Klassengenerierung { class ErfolguebersichtErfolg ErfolguebersichtErfolgGesamt Erfolguebersicht <> schema ErfolguebersichtErfolgProKopf Generierte Klassen aus Matrjoschka-Design
.NET: Prinzip der Klassengenerierung public partial class Erfolguebersicht { private ErfolguebersichtErfolg[] erfolgfield; public ErfolguebersichtErfolg[] Erfolg { get { return this.erfolgfield; set { this.erfolgfield = value; public partial class ErfolguebersichtErfolg { private ErfolguebersichtErfolgGesamt gesamtfield; private ErfolguebersichtErfolgProKopf prokopffield; private string stadtfield; private string monatfield; public ErfolguebersichtErfolgGesamt Gesamt { get { return this.gesamtfield; set { this.gesamtfield = value; public ErfolguebersichtErfolgProKopf ProKopf { get { return this.prokopffield; set { this.prokopffield = value; public string Stadt { get { return this.stadtfield; set { this.stadtfield = value; public string Monat { get { return this.monatfield; set { this.monatfield = value; public partial class ErfolguebersichtErfolgGesamt { public partial class ErfolguebersichtErfolgProKopf { private decimal umsatzfield; private decimal anrufefield; private short kundenfield; public decimal Umsatz { get { return this.umsatzfield; set { this.umsatzfield = value; public decimal Anrufe { get { return this.anrufefield; set { this.anrufefield = value; public short Kunden { get { return this.kundenfield; set { this.kundenfield = value; private decimal umsatzfield; private decimal anrufefield; public decimal Umsatz { get { return this.umsatzfield; set { this.umsatzfield = value; public decimal Anrufe { get { return this.anrufefield; set { this.anrufefield = value;
.NET: Schema-Bindung { class { { { <> schema Generierte Klassen aus globalen komplexen Typen {
.NET: Schema-Bindung public partial class Erfolguebersicht { private ErfolgTyp[] erfolgfield; public ErfolgTyp[] Erfolg { get { return this.erfolgfield; set { this.erfolgfield = value; public partial class ErfolgTyp { private GesamtType gesamtfield; private UmsatzTyp prokopffield; private string stadtfield; private string monatfield; public GesamtType Gesamt { get { return this.gesamtfield; set { this.gesamtfield = value; public UmsatzTyp ProKopf { get { return this.prokopffield; set { this.prokopffield = value; public string Stadt { get { return this.stadtfield; set { this.stadtfield = value; public string Monat { get { return this.monatfield; set { this.monatfield = value; public partial class GesamtType : UmsatzTyp { public partial class UmsatzTyp { private int kundenfield; public int Kunden { get { return this.kundenfield; set { this.kundenfield = value; private decimal umsatzfield; private decimal anrufefield; public decimal Umsatz { get { return this.umsatzfield; set { this.umsatzfield = value; public decimal Anrufe { get { return this.anrufefield; set { this.anrufefield = value;
.NET: Generierung und Mapping beeinflussen using System.Xml.Serialization; [XmlRoot(Namespace = "http://www.ruhrfon.biz", ElementName = "Uebersicht")] // Alternative: anonymer Typ //[XmlType(AnonymousType=true)] [XmlType("UebersichtTyp")] public partial class Erfolguebersicht { private ErfolgTyp[] erfolg; [XmlElement(ElementName = "Erfolg", IsNullable = false)] public ErfolgTyp[] Erfolg { get; set;
.NET: Generierung und Mapping beeinflussen public partial class ErfolgTyp { private GesamtTyp gesamt; private UmsatzTyp prokopf; private string stadt; private string monat; private string region; // Berücksichtigung als Element mit Umbenennung [XmlElement(ElementName = "Total", IsNullable = true)] public GesamtTyp Gesamt { get; set; // Berücksichtigung als Element gleichen Namens [XmlElement(IsNullable = true)] public UmsatzTyp ProKopf { get; set; // Unberücksichtigt lassen [XmlIgnore] public string Region { get; set; // Berücksichtigung als Attribut und Namensänderung //[XmlAttribute("Ort")] [XmlAttribute(AttributeName = "Ort", DataType="string")] public string Stadt { get; set; // Berücksichtigung als Attribut gleichen Namens [XmlAttribute()] public string Monat { get; set;
.NET: Generierung und Mapping beeinflussen
.NET: Marshalling und Unmarshalling // Erstellung einer Erfolgsübersicht Erfolguebersicht uebersicht = new Erfolguebersicht(); ErfolgTyp erfolg = new ErfolgTyp(); erfolg.monat = "10.04"; erfolg.stadt = "Essen, Ruhr"; // Serialisierung XmlSerializer serializer = new XmlSerializer(typeof(Erfolguebersicht)); TextWriter writer = new StreamWriter(filename); serializer.serialize(writer, uebersicht); writer.close();
.NET: Marshalling und Unmarshalling // Deserialisierung XmlSerializer serializer = new XmlSerializer(typeof(Erfolguebersicht)); FileStream fs = new FileStream(filename, FileMode.Open); Erfolguebersicht uebersicht; uebersicht = (Erfolguebersicht)serializer.Deserialize(fs); // Ausgabe und Weiterverwendung Console.WriteLine("Anrufe gesamt: " + uebersicht.erfolg[0].gesamt.anrufe); Console.WriteLine("Anrufe pro Kopf: " + uebersicht.erfolg[0].prokopf.anrufe);
Fragen...
XML Schema und Objektorientierung Einführung.NET Java
Java : Prinzip der Klassengenerierung { class ErfolguebersichtErfolg ErfolguebersichtErfolgGesamt Erfolguebersicht <> schema ErfolguebersichtErfolgProKopf Generierte Klassen aus Matrjoschka-Design
Java : Prinzip der Klassengenerierung public class Erfolguebersicht { protected List<Erfolguebersicht.Erfolg> erfolg; public List<Erfolguebersicht.Erfolg> geterfolg() { if (erfolg == null) { erfolg = new ArrayList<Erfolguebersicht.Erfolg>(); return this.erfolg; public static class Erfolg { protected Erfolguebersicht.Erfolg.Gesamt gesamt; protected Erfolguebersicht.Erfolg.ProKopf prokopf; protected String stadt; protected String monat; public Erfolguebersicht.Erfolg.Gesamt getgesamt() { return gesamt; public void setgesamt(erfolguebersicht.erfolg.gesamt value) { this.gesamt = value; public Erfolguebersicht.Erfolg.ProKopf getprokopf() { return prokopf; public void setprokopf(erfolguebersicht.erfolg.prokopf value) { this.prokopf = value; public String getstadt() { return stadt; public void setstadt(string value) { this.stadt = value; public String getmonat() { return monat; public void setmonat(string value) { this.monat = value; public static class Gesamt { protected BigDecimal umsatz; protected BigDecimal anrufe; protected short kunden; public BigDecimal getumsatz() { return umsatz; public void setumsatz(bigdecimal value) { this.umsatz = value; public BigDecimal getanrufe() { return anrufe; public void setanrufe(bigdecimal value) { this.anrufe = value; public short getkunden() { return kunden; public void setkunden(short value) { this.kunden = value; public static class ProKopf { protected BigDecimal umsatz; protected BigDecimal anrufe; public BigDecimal getumsatz() { return umsatz; public void setumsatz(bigdecimal value) { this.umsatz = value; public BigDecimal getanrufe() { return anrufe; public void setanrufe(bigdecimal value) { this.anrufe = value;
Java: Schema-Bindung { class { { { <> schema { Generierte Klassen aus globalen komplexen Typen
Java: Schema-Bindung public class Erfolguebersicht { protected List<Erfolg> erfolg; public List<Erfolg> geterfolg() { if (erfolg == null) { erfolg = new ArrayList<Erfolg>(); return this.erfolg; public class Erfolg { protected Gesamt gesamt; protected UmsatzTyp prokopf; protected String stadt; protected String monat; public Gesamt getgesamt() { return gesamt; public void setgesamt(gesamt value) { this.gesamt = value; public UmsatzTyp getprokopf() { return prokopf; public void setprokopf(umsatztyp value) { this.prokopf = value; public String getstadt() { return stadt; public void setstadt(string value) { this.stadt = value; public String getmonat() { return monat; public void setmonat(string value) { this.monat = value; public class GesamtTyp extends UmsatzTyp { public class UmsatzTyp { protected int kunden; public int getkunden() { return kunden; public void setkunden(int value) { this.kunden = value; protected BigDecimal umsatz; protected BigDecimal anrufe; public BigDecimal getumsatz() { return umsatz; public void setumsatz(bigdecimal value) { this.umsatz = value; public BigDecimal getanrufe() { return anrufe; public void setanrufe(bigdecimal value) { this.anrufe = value;
Java: Generierung und Mapping beeinflussen import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) @XmlType( name = "", proporder = {"erfolg", namespace = "http://www.ruhrfon.biz" ) @XmlRootElement(name = "Erfolguebersicht") public class Erfolguebersicht { @XmlElement(name = "Erfolg", required = true) protected List<ErfolgTyp> erfolg;...
Java: Generierung und Mapping beeinflussen @XmlAccessorType(XmlAccessType.FIELD) @XmlType( name = "ErfolgTyp", proporder = { "gesamt", "prokopf" ) public class ErfolgTyp { @XmlElement(name = "Gesamt", required = true) protected GesamtTyp gesamt; @XmlElement(name = "ProKopf", required = true) protected UmsatzTyp prokopf; // Berücksichtigung mit anderem Namen @XmlAttribute(name = "Ort", required = true) protected String stadt; @XmlAttribute(name = "Monat", required = true) protected String monat; // Nicht berücksichtigen @XmlTransient private String region;...
Java: Generierung und Mapping beeinflussen <xs:element name="kunden" type="xs:int"> <xs:annotation> <xs:appinfo> <jaxb:property name="klienten"/> </xs:appinfo> </xs:annotation> </xs:element>... <xs:element name="erfolg" type="erfolgtyp" maxoccurs="unbounded"> <xs:annotation> <xs:appinfo> <jaxb:property name="erfolgliste" collectiontype="java.util.list"/> </xs:appinfo> </xs:annotation> </xs:element> <xs:complextype name="umsatztyp"> <xs:annotation> <xs:appinfo> <jaxb:javadoc><![cdata[<h2>klasse <i>umsatz</i></h2>]]></jaxb:javadoc> <jaxb:class name="umsatz"/> </xs:appinfo> </xs:annotation> <xs:sequence> <xs:element ref="umsatz"/>...
Java: Marshalling und Unmarshalling // Erstellung einer Erfolgsübersicht ObjectFactory of = new ObjectFactory(); Erfolguebersicht uebersicht = of.createerfolguebersicht(); GesamtTyp gesamt = of.creategesamttyp(); gesamt.setanrufe(bigdecimal.valueof(18869));... // Serialisierung try { JAXBContext jc = JAXBContext.newInstance("generated"); Marshaller m = jc.createmarshaller(); m.setproperty(marshaller.jaxb_formatted_output, Boolean.TRUE); m.marshal(uebersicht, new File("erfolguebersicht.xml")); catch (JAXBException e){ e.printstacktrace();
Java: Marshalling und Unmarshalling try { // Deserialisierung JAXBContext jc = JAXBContext.newInstance("generated"); Unmarshaller u = jc.createunmarshaller(); Erfolguebersicht uebersicht = (Erfolguebersicht)u. unmarshal( new FileInputStream("erfolguebersicht.xml")); // Ausgabe und Weiterverwendung Iterator<ErfolgTyp> iter = uebersicht.geterfolg().iterator(); while (iter.hasnext()){ ErfolgTyp erfolg = iter.next(); System.out.println("Anrufe gesamt: " + erfolg.getgesamt().getanrufe()); System.out.println("Anrufe pro Kopf: " + erfolg.getprokopf().getanrufe());
Fragen...