C#: XML-Serialisierung

In diesem Artikel wird die Serialisierung von XML-Strukturen beschrieben. Allgemein versteht man unter Serialisierung die Persistierung von Objekten in Dateien (dabei wird der Zustand eines Objekts in einen Datenstrom umgewandelt und auf ein Speichermedium geschrieben), um diese z.B. über das Netzwerk zu übertragen. Die Umkehrung der Serialisierung, also die Umwandlung eines Datenstroms in Objekte, wird als Deserialisierung bezeichnet. Ein typisches Anwendungsbeispiele wäre die Serialisierung auf Clientseite, die Übertragung via HTTP zum Server und der Server wiederum deserialisert den enthaltenden Datenstrom wieder in ein entsprechendes Objekt. Im Artikel wird nun auf Basis eines kleinen Beispielprogramms beschrieben wie man einen XML-Datenstrom in ein Objekt deserialisieren kann. Als „Backend“, welches den XML-Datenstrom liefert kommt ein Linux-Satellitenreceiver zum Einsatz.

Grundlagen

Um ein Objekt zu serialisieren stellt das .NET-Framework schon fertigen Klassen zu Verfügung, darunter auch die XmlSerializer-Klasse. Mit dieser Klasse ist es möglich Objekte in und aus XML-Dokumenten zu serialisieren bzw. zu deserialisieren. Darüber hinaus bietet diese Klasse einige Steuerungsfunktionen, um festzulegen wie Objekte in XML codiert werden sollen (dazu später mehr).

Wie weiter oben schon geschrieben versteht man unter XML-Serialisierung die Konvertierung der öffentlichen Eigenschaften und Felder eines Objekts in ein serielles Format (in diesem Fall XML) zum Zweck der Speicherung und Übermittlung. Die Deserialisierung überführt das Objekt aus der XML-Ausgabe in seinem ursprünglichen Zustand. Die Serialisierung kann daher als eine Möglichkeit zum Speichern des Zustands eines Objekts in einen Stream oder Puffer aufgefasst werden. Die Daten in den Objekten werden durch Konstrukte der Programmiersprache beschrieben, z. B. Klassen, Felder, Eigenschaften, primitive Typen, Arrays oder auch eingebettetes XML in Form von XmlElement-Objekten oder XmlAttribute-Objekten. Schauen wir uns dazu mal das folgende Beispiel an. Angenommen wir haben die folgende Klasse:

Die Klasse lässt sich jetzt ganz einfach mit der XmlSerializer-Klasse auf die lokale Festplatte lokalisieren. Dazu mal das folgende Beispielprogramm:

In Zeile 12 wird zunächst ein neues Objekt erzeugt. In Zeile 19 wird ein XmlSerializer erzeugt und dieser bekommt im Konstruktor den Typ des zu serialisierenden Objekts mitgegeben. Da der XmlSerializer mit Streams arbeitet und das Objekt in eine Datei serialisiert werden soll wird in Zeile 22 ein neuer FileStream erzeugt. In Zeile 24 wird dann die Serialize-Methode aufgerufen, welche als Parameter den vorher erzeugten Stream und das entsprechende Objekt übergeben bekommt. Als Output erhalten wir dann folgendes:

Steuerung von generiertem XML-Code mit Attributen

Zum Steuern des generierten XML können spezielle Attribute auf Klassen und Member angewendet werden. Um z. B. einen anderen XML-Elementnamen anzugeben, weisen Sie XmlElementAttribute einem öffentlichen Feld oder einer Eigenschaft zu und legen die ElementName-Eigenschaft fest. Hier mal eine Übersicht über die im Beispiel verwendeten XML-Attribute:

AttributAnwendbar aufBeschreibung
XmlRootAttributeDeklarationen öffentlicher KlassenSteuert die XML-Serialisierung des Attributziels als XML-Stammelement. Mit diesem Attribut können Sie Namespace und Elementnamen genauer angeben
XmlElementAttributeÖffentliches Feld, Eigenschaft, Parameter oder RückgabewertDas Feld oder die Eigenschaft wird als XML-Element serialisiert
XmlAttributeAttributeÖffentliches Feld, Eigenschaft, Parameter oder RückgabewertDer Member wird als XML-Attribut serialisiert
XmlArrayAttributeÖffentliches Feld, Eigenschaft, Parameter oder Rückgabewert, wodurch ein Array von komplexen Objekten zurückgegeben wirdDie Member des Arrays werden als Member eines XML-Arrays generiert

Eine vollständige Liste mit den verfügbaren Attributen ist hier zu finden: https://msdn.microsoft.com/de-de/library/83y7df3e(v=vs.110).aspx

Mit dem XmlSerializer kann man also die Vorteile der Arbeit mit stark typisierten Klassen nutzen, ohne auf die Flexibilität von XML verzichten zu müssen. In Verbindung mit den oben gezeigten Attributen kann man die Serialisierung darüber hinaus noch flexibel gestalten, so ist es beispielsweise möglich nur bestimmte Eigenschaften zu serialisieren oder geschachtelte Strukturen (z.B. Listen oder Arrays) zu verarbeiten.

Praktische Anwendung

So dann kommen wir mal zu einem praktischen Anwendungsfall des Ganzen. Es gibt diverse Satellitenreceiver deren Betriebssystem auf Linux basiert. Auf den meisten dieser Receiver ist ein Webinterface installiert, welches es erlaubt den Receiver über den Browser zu steuern. Dabei arbeitet dieses Webinterface nach dem Client-Server-Prinzip und stellt die folgende Funktionalität bereit:

  • Eine Client-API, die mit einer beliebigen Programmiersprache angesprochen werden kann (C#, JAVA, usw.). Dies läuft dann wie folgt ab:
    • Senden eines Requests an den Receiver, z.B. Abrufen der Kanalliste oder Timer, EPG-Informationen oder Steuerungsinformationen (Lautstärke, Umschalten, usw.)
    • Ergebnis wird als XML zurückgeliefert
  • http-Client zur Nutzung in einem beliebigen Browser

In folgendem Beispiel wollen wir den Receiver jetzt über die Client-API aus einem C#-Programm heraus ansprechen (z.B. um Informationen zum aktuellen Zustand des Receivers abzufragen) und das Ergebnis (XML-Datenstrom) in ein Objekt deserialisieren. Dieses Objekt kann dann genutzt werden um die Daten innerhalb eines Dialogs anzuzeigen. Der Ablauf ist dann also der folgende:

ClientServerEnigmaWebInterface

Eine typische Anwendung wäre hier z.B. eine Fernbedienung. Für diese Receiver existieren diverse Apps (auf den verschiedenen Plattformen), die dieses Prinzip nutzen um den Receiver fernzusteuern (Lautstärke, Timer anlegen/löschen, EPG, …). Gerade für die Home-Automatisierung ist das eine schöne Sache. Neben den Satellitenreceivern gibt es noch diverse andere Programme, die sich auf ähnliche Art und Weise steuern lassen, z.B. der Kodi MediaPlayer. Hat man jetzt einen Enigma2-Receiver ist auf diesem, in den meisten Fällen, ein Webinterface installiert. Sollen jetzt Informationen zum Receiver ermittelt werden sieht der Aufruf wie folgt aus:

http://IP_of_your_box/web/about

Das Ergebnis des Aufrufs sieht dann, je nach verwendetem Receiver, in etwa so aus:

XML_Result

Um diese Daten in der Anwendung verarbeiten zu können wird noch eine entsprechende Klasse benötigt. Diese Klassen wird mit entsprechenden XML-Attributen (wie weiter oben beschrieben) ausgestattet. Das oben gezeigte Ergebnis enthält darüber hinaus noch verschachtelte Strukturen, die ebenfalls mit XML-Attributen abgebildet werden können, dazu aber später mehr. Zunächst einmal die Klasse:

In Zeile 1 wird der Klasse DeviceInfo mit dem Attribut XmlRoot das Einstiegselement zugewiesen. Um den Eigenschaften der Klasse Werte zuzuweisen wird das Attribut XmlElement verwendet, z.B. in Zeile 6 zum Ermitteln der installierten Version. Hier ist auch schön zu sehen, dass die Eigenschaft der Klasse nicht zwingend den gleichen Namen wie das XML-Element haben muss. Um die verschachtelten Strukturen zu lesen kommen die Attribute XmlArray und XmlArrayItem zum Einsatz, z.B. in Zeile 51 und 52. Hier ist zu beachten, dass eine Liste eines bestimmten Typs zurückgegeben wird. Die hier verwendete Klasse Tuner besitzt lediglich die Eigenschaften Name und Model. Diese Eigenschaften werden wiederum mit entsprechenden XML-Attributen ausgestattet (analog zur oben gezeigten Klasse). Um die XML-Struktur zu deserialisieren geht man jetzt wie folgt vor:

Zunächst wird die XML-Struktur mit einem HttpWebRequest ermittelt und in Zeile 16 deserialisiert.
XML_Deserialized
Wie zu sehen wurden die ermittelten Informationen in ein entsprechendes Objekt deserialisiert und können jetzt beliebig innerhalb der Anwendung verwendet werden. Und das Beste: Die komplette Arbeit wurde von derXmlSerializer-Klasse übernommen und man muss sich nicht selbst um das XML-Parsing kümmern.

Literaturverzeichnis und Weblinks

Abk.Quelle
[1]XmlSerializer-Klasse
[2]Attribute zur Steuerung der XML-Serialisierung
[3]Enigma2 - Webinterface
Fork me on GitHub