Die Neuerungen im .NET Framework 2.0 fur XML

Veröffentlicht: 19. Okt 2005
Von Martin Szugat

... denkste! Zwar bietet die zweite Version des .NET Framework auch im Hinblick auf XML einige Verbesserungen und Erweiterungen an, doch der große Wurf blieb aus. Das Schlagwort lautet stattdessen "Refactoring". So wurde beispielsweise die Architektur der XmlReader- und XmlWriter-Klassen überarbeitet und an der Performanz gefeilt - die Änderungen liegen also im Detail.

dot.net magazin


Diesen Artikel können Sie dank freundlicher Unterstützung von dot.net magazin auf MSDN Online lesen. dot.net magazin ist ein Partner von MSDN Online. Ausgabe: 7/8.05


Zur Partnerübersichtsseite von MSDN Online

Die schlechte Nachricht gleich vorweg: Weder XQuery 1.0, noch dessen integraler Bestandteil XPath 2.0, XSLT 2.0 oder XInclude 1.0 haben Eingang in Whidbey gefunden. Auf die Problematik hinsichtlich XQuery sowie auf die Verwendung von XInclude im .NET Framework 1.x wurde bereits in [1] hingewiesen und in [2] bereits Alternativen für XQuery in .NET vorgestellt.

Die Ankündigung, XQuery in der nun kommenden Version 2.0 nicht zu unterstützen, hat sogar dazu geführt, dass die Firma Stylus Studio (Hersteller des gleichnamigen XML-Editors) eine Online-Petition für eine Aufnahme von XQuery in das .NET Framework 2.0 ins Leben gerufen hat [3]. Ob sich Microsoft davon allerdings beeindrucken lässt, ist fraglich (zumal derartige Petitionen fast schon zur Gewohnheit werden). Vielleicht hoffen die Redmonder ja auch, dass die Open-Source- Gemeinde die noch fehlende Funktionalität nachliefert und Microsoft sie dann nur noch zu lizenzieren braucht - wie zuletzt im Falle der Mvp.Xml-Bibliothek und XInclude .NET geschehen [4]. Doch nicht nur XQuery wurde gestrichen [5], auch an anderen Stellen wurden angekündigte Funktionen [6] wieder zurückgezogen [7]. In dieser Ausgabe stehen daher die Neuerungen von .NET 2.0 im Vordergrund, die es tatsächlich in die zweite Beta von Whidbey geschafft haben [8] - allen voran die Änderungen, die die Klassen XmlReader und XmlWriter betreffen.

Auf dieser Seite

 Das unzertrennliche Paar
 Harte Typen
 Helfershelfer
 Auf die einfache Tour
 360° Drehung
 Schneckenrennen
 Käfersuche
 Links & Literatur
 Über den Author

Das unzertrennliche Paar

Das (Klassen-)Duo stellt die Grundlage der XML-Verarbeitung in .NET dar. Daran hat sich auch in der zweiten Version nichts geändert. Doch die Erzeugung von XmlReader- beziehungsweise XmlWriter-Objekten hat sich dafür grundlegend verändert. Bisher wurden Nachfahren der beiden Klassen, beispielsweise XmlTextReader und XmlTextWriter, direkt instantiiert. Um einen validierenden Parser zu erhalten, wurde zusätzlich ein XmlValidatingReader-Objekt angelegt und mit einem XmlTextReader-Objekt initialisiert. Auf diese Weise konnten verschiedene Parser mit unterschiedlichen Fähigkeiten kombiniert werden - es entstand eine Pipeline. Das so genannte "Pipelining" bietet zwar die größtmögliche Flexibilität (und wird deshalb auch weiterhin unterstützt), doch wirkt es auf Grund der Komplexität für viele Entwickler abschreckend. Erschwerend kommt hinzu, dass die Effizienz leidet, da Aufrufe von einem zum nächsten Objekt weitergeleitet werden. In Whidbey wurden die beiden abstrakten Basisklassen XmlReader und XmlWriter deshalb um eine statische Create-Methode erweitert. Diese Methode akzeptiert zusätzlich zum Pfad des XML-Dokuments ein Objekt der Klasse XmlReaderSettings beziehungsweise XmlWriterSettings. Über ein solches Objekt kann gesteuert werden, welche Formatierung für die XMLAusgabe verwendet wird oder ob ein Parser die Eingabe gegen ein Schema oder eine DTD validieren soll. Die Create- Methode verwendet diese Informationen, um das passende XmlReader- (Listing 1) beziehungsweise XmlWriter-Objekt (Listing 2) zu erzeugen und zurückzugeben. Dieses Objekt ist somit genau auf die notwendigen Funktionalitäten optimiert, wodurch die Performanz verbessert wird.

Dim xrs As New XmlReaderSettings
With xrs
    .CloseInput = True
    .IgnoreWhitespace = True
    .ValidationType = ValidationType.None
    .Schemas.Add("urn:data", "..\..\Data.xsd")
End With


Dim xr As XmlReader =
XmlReader.Create("..\..\Data.xml", xrs)
With xr
    .MoveToContent()
    Dim version As Decimal = xr("version")
    Dim source As String = xr("source")
    .ReadStartElement("data", "urn:data")
    Dim dbl As Double = .ReadElementContentAsDouble()
    Dim dte As Date = .ReadElementContentAs(GetType
                                         (Date), Nothing)
Dim int As Integer = .ReadElementContentAsObject()
.ReadEndElement()
.Close()
End With

Listing 1: XmlReader in .NET 2.0

Dim xws As New XmlWriterSettings()
With xws
    .CloseOutput = True
    .Encoding = Encoding.UTF8
    .Indent = True
    .NewLineOnAttributes = True
End With


Dim xw As XmlWriter =
XmlWriter.Create("..\..\Data.xml", xws)
With xw
    .WriteStartDocument()
    .WriteStartElement("data", "urn:data")
    .WriteAttributeString("version", "1.0")
    .WriteAttributeString("source", "XmlWriter")
    .WriteStartElement("double", "urn:data")
    .WriteValue(Math.PI)
    .WriteEndElement()
    .WriteStartElement("date", "urn:data")
    .WriteValue(Date.Now)
    .WriteEndElement()
    .WriteStartElement("integer", "urn:data")
    .WriteValue(Integer.MaxValue)
    .WriteEndElement()
    .WriteEndElement()
    .WriteEndDocument()
    .Close()
End With

Listing 2: XmlWriter in .NET 2.0

Harte Typen

Eine weitere Innovation betrifft die Typbehandlung beim Lesen und Schreiben von XML-Dokumenten. Bisher lieferten die Read-Methoden der XmlReader-Klasse nur Zeichenfolgen, die dann mithilfe der XmlConvert-Klasse in die jeweiligen CLR-Typen konvertiert werden konnten. Auch mit dieser umständlichen Vorgehensweise ist nun Schluss: Die neue XmlReader-Klasse hält spezielle Read-Methoden wie ReadElementContentAsDouble für Werte vom Typ Double oder ReadElementContentAs für beliebige Typen bereit. Im Falle der letzt genannten Methode wird der gewünschte Typ als Type-Objekt im ersten Parameter übergeben.

Die Methode ReadElementContentAsObject entscheidet hingegen selbstständig, welchen Typ der zurückgegebene Wert erhält. Liegt einem XML-Dokument ein Schema zu Grunde, wird der Typ anhand des Schemas ermittelt. Andernfalls wird versucht, den Typen anhand der vorliegenden Daten zu bestimmen. In umgekehrter Weise geschieht selbiges beim Schreiben von Daten in ein XML-Dokument mittels der WriteValue-Methode eines XmlWriter-Objekts. Auf Grund des Typs der übergebenen Daten wird entschieden, wie die Ausgabezeichenfolge formatiert werden muss.

Helfershelfer

Weitere sehr nützliche Methoden, die in der zweiten Version der XmlReader- Klasse spendiert wurden, sind beispielsweise ReadSubtree, ReadToDescendant und ReadToNextSibling. Die Methode ReadSubtree liest - wie der Name bereits andeutet - einen kompletten (XML-)Baum ein, also ein Element samt seinen Unterelementen, und liefert diesen als weiteres XmlReader-Objekt zurück. Die beiden anderen Methoden, ReadToDescendant und ReadToNextSibling, helfen beim Auffinden bestimmter Elemente. Bisher war es überaus mühsam, nur bestimmte Elemente aus einem XML- Dokument einzulesen. Mit den beiden Methoden, die bis zu einem bestimmten untergeordneten beziehungsweise benachbarten Element lesen, vereinfacht sich der Code erheblich.

Auf die einfache Tour

In einem früheren Artikel [9] wurde auf die Problematik von Namensräumen in XPath-Ausdrücken hingewiesen. Um mit XPath Elemente und Attribute abzufragen, die einem bestimmten Namensraum zugeordnet sind, muss dieser erst dem XPathNavigator-Objekt bekannt gegeben und mit einem Präfix versehen werden. Hierfür war es erforderlich, einen XPath-Ausdruck in ein XPathExpression-Objekt zu kompilieren und ein XmlNamespaceManager-Objekt an dessen SetContext-Methode zu übergeben, bevor der XPath-Ausdruck mittels Evaluate oder Select ausgewertet wurde. Microsoft hat das Flehen der Programmierer erhört und bietet mit .NET 2.0 eine einfachere Lösung an - zu sehen in Listing 3.

Dim xd As New XmlDocument()
xd.Load("..\..\Data.xml")
Dim xpn As XPathNavigator = xd.CreateNavigator()
xpn.MoveToChild("data", "urn:data")


With xpn.AppendChild()
    .WriteStartElement("d", "date", "urn:data")
    .WriteValue(Date.Now)
    .WriteEndElement()
    .Close()
End With


Dim xpi As XPathNodeIterator = xpn.Select("d:date", xpn)
While (xpi.MoveNext)
    Console.WriteLine(xpi.Current.ValueAsDateTime)
End While


xd.Save("..\..\Data.xml")

Listing 3: XPathNavigator-Klasse in .NET 2.0

In .NET 2.0 kann der Evaluate- beziehungsweise Select-Methode im zweiten Parameter ein Objekt, welches die Schnittstelle IXmlNamespaceResolver implementiert, übergeben werden. Diese Schnittstelle ist für die Abbildung von Präfixen auf Namensraum-URIs zuständig und wird unter anderem von der XPathNavigator- Klasse implementiert. Diese XPathNavigator- Klasse stellt hierüber die Namensraumdeklarationen aus dem XML-Dokument zur Verfügung, sodass die dort deklarierten Präfixe in einem XPath-Ausdruck auch (wieder-) verwendet werden können. Allerdings muss der XPathNavigator zuerst auf einem Knoten im Gültigkeitsbereich der Namensraumdeklaration positioniert werden. Dies erfolgt in Listing 3 dadurch, dass der XPathNavigator zum Wurzelelement des XML-Dokuments bewegt wird. Dort befindet sich die Namensraumdeklaration für das Präfix "d".

360° Drehung

Ohnehin bekommt XPath mit Whidbey einen höheren Stellenwert, allerdings keinen so hohen wie angekündigt. Ursprünglich sollte XPath zu dem Zugriffsmodell Nr. 1 für .NET 2.0 werden und damit die Lücke zwischen dem komfortablen, aber schwerfälligen DOM und dem umständlichen, aber leichtgewichtigem Gespann aus XmlReader und XmlWriter werden - doch daraus wurde nichts. Wie die Entwickler bei Microsoft selbst einsahen, programmieren viele ihrer Kollegen gerne und oft mit DOM und vermeiden das zwar schnellere, aber erstmal ungewohnte Cursor- basierte Modell der XPathNavigator- Klasse. Immerhin wurden auch die Anhänger dieser Zugriffsmethode für XML reichlich beschenkt: Die XPathNavigator- Klasse ist nun editierbar, sofern sie durch ein XmlDocument-Objekt erzeugt wurde. So können mittels der Methode AppendChild unterhalb des aktuellen Knotens und im Anschluss an vorhandene Unterknoten neue Daten eingefügt werden. Die AppendChild-Methode liefert hierfür ein XmlWriter-Objekt, welches anschließend nach Belieben gefüllt werden kann. Zum Schluss ist noch die Close-Methode auf dem XmlWriter-Objekt aufzurufen, sodass die Änderungen auch in das darunter liegende Speichermodell des XPathNavigator-Objekts geschrieben werden. Die Änderungen sind unmittelbar danach sichtbar und können mittels XPath abgefragt werden. Um sie dauerhaft in einer XML-Datei zu speichern, muss das XmlDocument-Objekt bemüht werden, dessen CreateNavigator- Methode für die Erzeugung des XPathNavigator-Objekts verwendet wurde. Ein Aufruf der Methode Save speichert die geänderten Daten in einem XML-Dokument.

Schneckenrennen

XSLT war das Stiefkind des System.Xml- Namensraumes in .NET 1.x, zumindest in Hinblick auf Performanz und Unterstützung durch Visual Studio .NET. Beides soll sich mit .NET 2.0 ändern: Zum einen wurde die XslTransform-Klasse durch die Klasse XslCompiledTransform ersetzt, welche ein Stylesheet beim Laden in MSILCode übersetzt und so eine höhere Verarbeitungsgeschwindigkeit erreicht - zum anderen bietet Visual Studio 2005 einen XSLT-Debugger an [10]. Die Migration von XslTransform zu XslCompiledTransform soll ohne Probleme möglich sein [11], denn immerhin gleichen sich die Schnittstellen beider Klassen weitgehend, doch zumindest ein Feature der XslTransform- Klasse fehlt im Falle der XslCompiledTransform- Klasse: Das so genannte "Pulling" [12]. Hierbei wurde die Ausgabe einer Transformierung direkt in ein Xml- Reader-Objekt geleitet und die Transformierung erst dann durchgeführt, wenn über das XmlReader-Objekt gelesen wurde. Dies erlaubte auf eine sehr effiziente Weise die Implementierung von Verarbeitungs- Pipelines. Mit der XslCompiledTransform-Klasse ist dies leider nicht möglich. Ein kleiner Trost ist jedoch, dass die XslTransform-Klasse weiterhin zur Verfügung stehen wird.

Die XslCompiledTransform-Klasse hat allerdings auf einem weiteren, wichtigen Gebiet eine Verbesserung erfahren: Sicherheit. Dank der XsltSettings-Klasse kann bereits beim Laden des Stylesheet festgelegt werden, welche sicherheitskritischen Aktionen erlaubt oder verboten sein sollen. So sind das Scripting und die Anwendung der document-Funktion als Standardeinstellung deaktiviert und können über entsprechende Eigenschaften der XsltSettings-Klasse aktiviert werden. In diesem Fall muss zusätzlich zu den XsltSettings ein Objekt der Klasse XmlResolver übergeben werden. Zur Auswahl stehen die Klassen XmlUrlResolver und XmlSecureResolver. Letztere bietet die Möglichkeit, genau festzulegen, auf welche Ressourcen das Stylesheet wie zugreifen darf.

Käfersuche

Der erwähnte XSLT-Debugger unterstützt das Setzen von Haltepunkten, das schrittweise Ausführen von XSLT-Anweisungen sowie die Inspektion von Variablen. Um das Debugging überhaupt zuzulassen, muss jedoch bei der Instantiierung der XslCompiledTransform- Klasse im Konstruktor der Wert True übergeben werden - wie in Listing 4 gezeigt. Beim Aufruf der Transform-Methode wechselt der Debugger von Visual Studio in den XSLT-Editor, sofern in diesem zuvor ein Haltepunkt gesetzt wurde. Abbildung 1 zeigt einen solchen Haltepunkt und den XSLT-Debugger in Aktion. Selbst in das Stylesheet eingebetteter Code, in Listing 5 in Visual Basic .NET verfasst, lässt sich so einfach und bequem nach Fehlern durchforsten. Einzig und allein die Anzeige von XSLT-Variablen, wie in diesem Beispiel $date, ist etwas umständlich realisiert. Anstatt den jeweiligen Wert direkt anzugeben, findet sich hier der Eintrag System.Xml.Xsl.Runtime.XmlQuery-Sequence. Unterhalb dieses Eintrags, genauer unter Non-Public members/cache- Items/ [0] findet sich endlich der eigentliche Wert - in diesem Fall das Datum.

Die Neuerungen im .NET Framework 2.0 für XML
Abb. 1: Der XSLT-Debugger von Visual Studio .NET 2005

Ebenso wurde das Erstellen und Editieren von XML-Dokumenten vereinfacht, indem IntelliSense-Unterstützung und Validierung verbessert wurden. Schemas lassen sich über den Eigenschaften-Dialog laden und einem XML-Dokument zuordnen. Einziges Manko: Für die Entwicklung von Stylesheets steht kein passendes Schema und somit keine automatische Vervollständigungsfunktion bereit.

Links & Literatur

[1] Martin Szugat, XInclude .NET, in: dot.net magazine 4.2005

[2] Martin Szugat, XQuery: SQL für XML, in: dot.net magazin 5.2005

[3] XQuery-Petition: www.stylusstudio.com/xquery/xquery_for_all.html

[4] Microsoft licensed Mvp.Xml library: www.tkachenko.com/blog/archives/000429.html

[5] Status of XQuery in the .NET Framework 2.0: msdn.microsoft.com/XML/XQueryStatus/default.aspx

[6] What's New in System.Xml for Visual Studio2005 and the .NET Framework 2.0 Release: msdn.microsoft.com/XML/BuildingXML/XMLinNETFramework/default.aspx?pull=/library/en-us/dnxml/html/sysxmlvs05.asp

[7] Upcoming Changes to System.Xml in .NET Framework 2.0 Beta 2: blogs.msdn.com/dareobasanjo/archive/2004/10/13/241591.aspx

[8] What's New in System.Xml: msdn2.microsoft.com/library/1k76xshy(en-us,vs.80).aspx

[9] Martin Szugat, Ärger mit XPath, in: dot.net magazin 3.2005

[10] An Introduction to the XML Tools in Visual Studio 2005: msdn.microsoft.com/XML/BuildingXML/XMLinNETFramework/default.aspx?pull=/library/en-us/dnxmlnet/html/xmltools.asp

[11] Migrating From the XslTransform Class: msdn2.microsoft.com/library/66f54faw(en-us,vs.80).aspx

[12] XslCompiledTransform - no more pull-mode XSLT: www.tkachenko.com/blog/archives/000421.html

Über den Author

Martin Szugat ist seit vielen, vielen Jahren als freischaffender Fachautor im Bereich der Softwareentwicklung tätig und Sprecher auf der Basta! 2005 zum Thema XML. Bei Fragen erreichen Sie ihn unter Martin.Szugat@GMX.net. Aktuelle Neuigkeiten rund um XML erfahren Sie unter www.aboutxml.de.


Anzeigen: