30.04.2009, 23:25 Uhr

Moderne XML-Programmierung mit C# 3.0 und Visual Basic 9.0

Mit .NET 3.5 ist der Umgang mit XML-Daten deutlich einfacher geworden. Die funktional reichhaltigen, aber insgesamt nicht gerade entwicklerfreundlichen Klassen im Namespace System.Xml wurden durch Klassen im Namespace System.Xml.Linq erweitert, die eine Art "moderne XML-API" darstellen. Insbesondere der Umgang mit Namespaces und XPath wurde deutlich vereinfacht. Auch wenn die neue "XML-API" in erster Linie für LINQ-Abfragen konzipiert wurde, eignet sie sich auch für die meisten jener Szenarien, in denen bislang die Klassen aus System.Xml zum Einsatz kamen.
Im Mittelpunkt von System.Xml.Linq steht die XElement-Klasse, die ein (beliebiges) XML-Element, also ein Wert>, repräsentiert. Während sich Entwickler bei System.Xml bei einem XmlNode-Objekt zwischen einer InnerText- und einer InnerXml-Eigenschaft entscheiden müssen und die Value-Eigenschaft keinen Wert liefert, steht die Value-Eigenschaft der XElement-Klasse für den Wert zwischen den XML-Elementen, was den Zugriff auf den Inhalt, um den es in der Regel geht, angenehm vereinfacht. In einem kleinen XML-Fragment, das wie folgt definiert ist:string xml = @" C#3.0 Visual Basic9.0 ";liefert ein IEnumerable AlleSprachen = XElement.Parse(xml).Elements("Sprache").Elements("Name") alle -Elemente, so dass ein foreach (var sp in AlleSprachen) Console.WriteLine(sp.Value); die Werte aller -Elemente ausgibt. Ein wenig einfacher wird die Abfrage, wenn über die Descendants-Property alle "Abkömmlinge" des Stammelements geholt werden unabhängig davon, auf welcher Ebene sie sich befinden:IEnumerable AlleSprachen = XElement.Parse(xml).Descendants("Name"); Diese Methode entspricht der SelectNodes-Methode aus System.Xml, ohne dass sich der Entwickler mit der etwas sperrigen XPath-Syntax beschäftigen muss. Es ist interessant, dass das vermeintliche Pendant zu XmlDocument, die XDocument-Klasse, in vielen Situationen gar nicht benötigt wird. Sie kommt immer dann ins Spiel, wenn ein "vollständiges" XML-Dokument benötigt wird, bei dem z.B. die Processing Instruction variiert werden soll. Ein XElement lässt sich auch direkt abspeichern: XElement Sprachen = XElement.Parse(xml); Sprachen.Save("Sprachen.xml"); Besonders attraktiv ist, wie einfach sich Knoten hinzufügen oder entfernen lassen. Der folgende Befehl fügt ein -Element mit zwei Unterelementen (Name und Version) hinzu:Sprachen.Add(new XElement("Sprache", new XElement("Name", "F#"), new XElement("Version", "0.9"))); Der folgende Befehl entfernt alle Version-Elemente: Sprachen.Descendants("Version").Remove(); XName repräsentiert einen NamenDer Umstand, dass im Konstruktor der XElement-Klasse ein Name angegeben werden darf mag zunächst ein wenig verwundern, denn laut Syntaxbeschreibung ist für den Konstruktor kein string-Argument vorgesehen. Der Hintergrund ist, dass der Compiler daraus ein XName-Objekt macht (ein Blick in den IL-Code verrät weitere Details), das dadurch nicht direkt angelegt werden muss. Sind Namespaces im Spiel, wird diese durch ein XName repräsentiert: string xml = @" C#3.0 Visual Basic9.0 "; XName XnSp = XName.Get("Name", "http://tempuri.org"); Bei einer Abfrage muss jetzt das XName-Objekt explizit angegeben werden: IEnumerable AlleSprachen = XElement.Parse(xml).Descendants(XnSp); Besonderer Komfort bei Visual Basic 9.0Visual Basic besitzt ab der Version 2008 eine besondere Fähigkeit: Es erlaubt die direkte Eingabe von XML in den Quelltext des Programms: Dim xml = C#3.0 Visual Basic9.0 Der folgende Befehl gibt die Werte aller -Element zurück: Dim AlleSprachen = xml.Descendants(XName.Get("Name", "http://tempuri.org")) Sind keine Namespaces im Spiel, wird es noch ein wenig einfacher, da in diesem Fall eine spezielle Abkürzung zur Verfügung steht: Dim AlleSprachen = xml... Auch ad hoc generiertes XML muss nicht auf ein XML Schema verzichtet. Seit VS 2008 SP1 steht ein kleiner Assistent über die unscheinbare Vorlage "XML zu Schema" zur Verfügung (für VS 2008 gibt es den Assistenten auch als separaten Download). Wird diese Vorlage zu einem Projekt hinzugefügt, kann das XML, von dem ein XML Schema abgeleitet werden soll, über eine Datei, direkt über eine Webseite oder durch Eingabe des XML-Textes abgeleitet werden (Abbildung1). Abbildung 1: Über die Xml zu Schema-Vorlage kann aus XML ein XML Schema abgeleitet werden Der Vorteil eines XML Schema ist, dass die entsprechenden Elemente bei der Eingabe einer (LINQ-) Abfrage über Intellisense angeboten werden kann (Abbildung 2).Sind Namespaces im Spiel, kommen Visual Basic-Entwickler in den Genuss einer weiteren Vereinfachung. Die AbfrageDim AlleSprachen = xml... funktioniert nicht, da der Namespacepräfix "sp" nicht bekannt ist. Über eine Erweiterung des Imports-Befehl kann er im Modul bekannt gemacht werden:Imports Dass der Namespace System.Xml.Linq seinen Namen nicht ganz umsonst trägt, macht die folgende kleine LINQ-Abfrage deutlich, die den Durchschnittswert der Versionsnummer über die Average-Erweiterungsmethode bildet:Dim DurchschnittsVersion = (From v In xml... Select CType(v.Value, Single)).Average() So komfortabel ließen sich XML-Daten mit .NET 2.0 noch nicht verarbeiten. FazitXML-Daten, die heutzutage als "Zwischendaten" bei vielen Gelegenheiten im Internet anzutreffen sind, müssen schnell und entwicklerfreundlich verarbeitet werden können. Die etwas "sperrige" API aus System.Xml ist dafür nicht besonders gut geeignet. Mit den Klassen in System.Xml.Linq steht ab .NET 3.5 eine deutlich entwicklerfreundliche API zur Verfügung, die nicht nur in Silverlight-Anwendungen oder im Zusammenspiel mit LINQ ihre Vorteile ausspielt. Über Erweiterungsmethoden wird die Brücke zu XPath, XSLT&Co gebaut. Visual Basic-Entwickler genießen einen besonderen Komfort, in dem XML-Code direkt in den Quellcode eingegeben werden kann und sich XML-Schema aus ad hoc eingefügtem XML ableiten lässt. Man darf gespannt sein, was in diesem Bereich mit .NET 4.0 kommen wird. Abbildung 2: Dank einem XML Schema steht beim Zugriff auf die XML-Elemente Intellisense zur Verfügung Peter Monadiemi


Das könnte Sie auch interessieren