Ingeborg Puppe-Strafrecht Allgemeiner Teil

download Ingeborg Puppe-Strafrecht Allgemeiner Teil

of 141

Transcript of Ingeborg Puppe-Strafrecht Allgemeiner Teil

  • Sandini Bib

    XML mit .NET

  • Sandini Bib

    Grafikprogrammierung mit System.Drawing Vektorgrafiken, Bildbearbeitung, Texteffekte inkl. Farbteil

    Web Forms Holger Schwichtenberg144 SeitenEUR 16,95 [D]/sFr 27,50ISBN 3-8273-2010-0

    ADO.NETRalf Westphal144 Seiten 16,95 [D]/sFr 27,50ISBN 3-8273-1997-8

    GDI+Ellen Diehl, Thomas Ehrenberg192 Seiten 16,95 [D]/sFr 27,50ISBN 3-8273-1993-5

    Windows FormsMichael Kofler176 Seiten 16,95 [D]/sFr 27,50ISBN 3-8273-1994-3

    Web Forms ASP.NET-Programmierung mit System.Web.UI:Webcontrols, Ereignisse, State Management, Datenbindung,User Controls, Debugging

    Unser Online-Tippfr noch mehr Wissen

    ... aktuelles Fachwissen rund um die Uhr zum Probelesen,

    Downloaden oder auch auf Papier.

    www.InformIT.de

    Datenbankprogrammierung mit System.Data: relationaleDatenbanken fr ADO.NET, komplexe hierarchische Daten,Fehlerbehandlung

    Die .NET Essentials greifen die wichtigsten Themen des .NET Frameworks auf und behandeln auf knappemRaum, was Sie wissen mssen, um sofort eigene .NET Anwendungen auf hchstem Niveau zu schreiben.Ohne umstndliche Einfhrung kommen Sie umgehend zum Kern des jeweiligen Themas und findenAntworten auf Fragen, mit denen Sie sich beim Codieren immer wieder konfrontiert sehen. Die Autoren zei-gen Lsungen auf, die Sie bernehmen oder variieren und in eigene Projekte integrieren knnen:

    Grafische Benutzerschnittstellen mit System.Windows.Forms Formularinterna, mehrere Fenster, Multithreading, Zwischen-ablage, Drag&Drop

    Weitere Informationen finden Sie unter www.dotnet-essentials.de.

    .NETEssentials

  • Sandini Bib

    Armin Hanisch

    XML mit .NETProgrammierung und Basisklassen

    An imprint of Pearson Education

    Mnchen Boston San Francisco Harlow, EnglandDon Mills, Ontario Sydney Mexico CityMadrid Amsterdam

    .NETEssentials

    praktit01NotizCompleted festgelegt von praktit01

    praktit01NotizMigrationConfirmed festgelegt von praktit01

  • Sandini Bib

    Die Deutsche Bibliothek CIP-Einheitsaufnahme

    Ein Titeldatensatz fr diese Publikation ist bei Der Deutschen Bibliothek erhltlich.

    Die Informationen in diesem Produkt werden ohne Rcksicht auf einen eventuellen Patentschutz verffentlicht. Warennamen werden ohne Gewhrleistung der freien Verwendbarkeit benutzt.Bei der Zusammenstellung von Abbildungen und Texten wurde mit grter Sorgfalt vorgegangen. Trotzdem knnen Fehler nicht vollstndig ausgeschlossen werden. Verlag, Herausgeber und Autoren knnen fr fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung bernehmen. Fr Verbesserungsvorschlge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar.

    Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulssig.

    Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwhnt werden, sind gleichzeitig eingetragene Warenzeichen oder sollten als solche betrachtet werden.

    Umwelthinweis:Dieses Produkt wurde auf chlorfrei gebleichtem Papier gedruckt. Die Einschrumpffolie zum Schutz vor Verschmutzung ist aus umweltvertrglichem und recyclingfhigem PE-Material.

    5 4 3 2 1

    05 04 03 02

    ISBN 3-8273-1998-6

    2002 by Addison-Wesley Verlag,ein Imprint der Pearson Education Deutschland GmbH,Martin-Kollar-Strae 1012, D-81829 Mnchen/GermanyAlle Rechte vorbehaltenEinbandgestaltung: Barbara Thoben, KlnLektorat: Christine Auf, [email protected], Tobias Draxler, [email protected]: Katja Treu, MnchenHerstellung: Monika Weiher, [email protected]: reemers publishing services gmbh, Krefeld, www.reemers.deDruck und Verarbeitung: Media-Print, PaderbornPrinted in Germany

  • Sandini Bib

    .NETEssentials

    5

    Inhalt

    Einfhrung 7Vorwort 7Voraussetzungen 7Typografie 8Beispielcodes, Errata, Hinweise 8

    1 XML-Basics 91.1 XML-Terminologie 91.2 Namensrume 111.3 Die .NET-Namensrume 131.4 Untersttzte Standards 13

    2 XmlReader und XmlWriter 152.1 Lesen von XML-Daten 152.2 Schreiben von XML-Dateien 212.3 Zusammenfassung 26

    3 Serialisierung und XML 273.1 XML-Serialisierung im Detail 323.2 Zusammenfassung 37

    4 Document Object Model 394.1 Streaming oder DOM? 394.2 XML-Dokumente laden und lesen 394.3 ndern von XML-Dokumenten per DOM 444.4 Ereignisbehandlung 484.5 Zusammenfassung 52

    5 XPath-Abfragen 535.1 Warum XPath? 535.2 Grundlagen 535.3 SelectNodes und SelectSingleNode 595.4 Nutzung des XPathNavigators 615.5 Zusammenfassung 65

    6 XML-Namensrume 676.1 Einfhrung 676.2 Zusammenfassung 77

  • Sandini Bib

    .NETEssentials

    6

    Inhalt

    7 XSL-Transformationen 797.1 Grundlagen 797.2 Stylesheets laden 817.3 Transformation durchfhren 827.4 Transformationen verketten und optimieren 867.5 Zusammenfassung 87

    8 Validieren von XML 898.1 Warum ein Schema? 898.2 XSD der Standard 968.3 Zusammenfassung 112

    9 XML und Daten 1139.1 Einfhrung 1139.2 DataSet und Co. 1139.3 XmlDataDocument 1219.4 Zusammenfassung 125

    10 XML-Dokumentation 12710.1 XML-Kommentare 12710.2 Zusammenfassung 134

    11 Ausblick 135

    Stichwortverzeichnis 137

  • Sandini Bib

    .NETEssentials

    7

    Einfhrung

    Vorwort

    Thema dieses Bandes sind die XML-Basisklassen des .NET-Frame-works und ihre Verwendung sowie die Rolle von XML als Basisinfra-struktur innerhalb der .NET-Umgebung. XML ist bereits seit einigenJahren dabei, sich zur neuen lingua franca innerhalb der IT-Welt zuentwickeln und auch Microsoft setzt im Rahmen der .NET Initiative aufXML. Es gibt wohl kaum einen Bereich innerhalb des .NET-Frame-works, in dem XML keine Rolle spielt. Als universelles Austausch- undSpeicherformat wird es fr Konfigurationsdateien, ADO.NET, dieObjektserialisierung, Schemas und XSLT bis hin zu SOAP und Web Ser-vices als sprachneutrales Format benutzt. Als Entwickler haben Siekompletten Zugriff auf eine Reihe von hochoptimierten und vollstndi-gen Klassen, die nahezu jede Anforderung abdecken und ber denFunktionsumfang der alten XML Core Services der COM-Welt(MSXML) weit hinausgehen. Mit nur wenigen Zeilen an Code sind Siein der Lage, Daten zu transformieren, XML-Strukturen aufzubauenoder zu validieren und mit ADO.NET sogar beliebige XML-Dateienentweder als relationales DataSet oder als XML-Baumstruktur zubehandeln.

    Voraussetzungen

    Bentigte Software

    Zum Nachvollziehen der Beispiele in diesem Buch bentigen Sie einenRechner mit Windows 2000 oder Windows XP, Visual Studio .NET oderdas .NET-Framework SDK. Die Beispiele zu diesem Buch finden Siezum Download auf der Website fr diese Buchreihe, die unter demURL http://www.dotnet-essentials.de erreichbar ist. Dieses Buch gehtdavon aus, dass Sie zumindest das .NET-Framework und die Komman-dozeilen-Tools installiert haben. Sie bentigen nicht unbedingt VisualStudio .NET, obwohl Sie im Kapitel ber XML-Validierung und XML-Dokumentation sicher davon profitieren, da die grafische Oberflchedoch einige Aufgaben erleichtert. Aber auch diese Kapitel enthaltenHinweise, wie Sie ohne das Visual Studio .NET zurechtkommen.

  • Sandini Bib

    .NETEssentials

    8

    Einfhrung

    Vorkenntnisse

    Die Zielgruppe dieser Buchreihe sind Entwickler mit Programmier-erfahrung, die sich bereits erfolgreich mit den Grundlagen von .NETund Visual Studio vertraut gemacht haben. Sie finden in diesen Bndenpraktische Beispiele und kompakte Informationen ohne die endloseWiederholung von Grundlagen. Der Autor geht davon aus, dass Sie C#beherrschen bzw. Code, der in C# geschrieben wurde, lesen knnenund mit der objektorientierten Programmierung vertraut sind. AusPlatzgrnden sind viele Listings nicht komplett abgedruckt, sondernzeigen lediglich den Code einer (meist statischen) Methode ohne dieKlassendefinition und die using-Anweisungen drumherum, da Siesicher in der Lage sind, diese zu ergnzen. Wo es sinnvoll erschien oderbestimmte zustzliche Namespaces eingebunden wurden, wurdenkomplette Listings abgedruckt. Die Quellcodes der Downloads sindnatrlich alle vollstndig.

    Typografie

    Normaler Flietext wird mit dieser Schriftart dargestellt. Falls inner-halb eines Textabsatzes einzelne Schlsselwrter oder Klassen- bzw.Variablennamen vorkommen, werden diese als Klassenname hervorgeho-ben.

    Listings im Text besitzen diese Schriftartund wurden nach Mglichkeit so umbrochen,dass die Struktur trotz der geringen Spaltenbreite erhalten bleibt.

    Einzelne Listingszeilen erhalten diese Formatierung

    Auswahlen in einem MENNAMEN oder als DIALOGOPTION werdenebenfalls besonders gekennzeichnet.

    Alle Dateinamen, URLs oder Pfadangaben sind wie hier gezeigt hervorge-hoben.

    Beispielcodes, Errata, Hinweise

    Die Beispielcodes zu diesem Band der Reihe .NET-Essentials finden Sieim Internet unter dem URL http://www.DotNet-Essentials.de. Hier findenSie auch zustzliche Hinweise, Ergnzungen und Korrekturen zu die-sem und den anderen Bnden der Reihe. Alle Listings, Codeangabenund Verweise in diesem Buch wurden nach bestem Wissen und Gewis-sen auf Fehlerfreiheit geprft. Sollten Sie dennoch einen Fehler findenoder Anregungen und Kommentare zu diesem Buch haben, freut sichder Autor auf Ihr Feedback.

  • Sandini Bib

    .NETEssentials

    9

    1 XML-Basics

    1.1 XML-Terminologie

    Knoten, Elemente, Tags und Attribute

    Eine XML-Struktur (Struktur deshalb, da XML nicht notwendigerweiseimmer in einer Datei vorliegen muss, beispielsweise als MemoryStream) isteine baumfrmige Struktur. Dieser Baum besteht aus einzelnen Knotenoder Elementen, die in textueller Form durch entsprechende Tags dar-gestellt werden. Ein Element kann einen reinen Textinhalt oder Unter-elemente (oder Kindknoten) besitzen, auch ein gemischter Inhalt ausText und Unterelementen ist mglich.

    XML als Baum oder als Stream

    Je nach Programmiermodell (Streamingzugriff ber XmlReader oderDOM-Zugriff ber ein XmlDocument) wird diese XML-Struktur seriellgelesen und Element fr Element an die Anwendung weitergegebenoder die komplette Datei wird gelesen und die Baumstruktur im Spei-cher aufgebaut (wobei hier der Ressourcenbedarf dementsprechendgro werden kann). Ein Element kann entweder ein XML-Element, einKommentar, eine Verarbeitungsanweisung an den XML-Parser oderLeerraum sein.

    Elemente knnen Attribute enthalten, die allerdings in keiner bestimm-ten Reihenfolge vorliegen mssen (der XML-Standard erlaubt aus-drcklich eine wechselnde Attributreihenfolge bei gleichen Elementen)und die daher in den XML-Klassen in einer ungeordneten Auflistungmitgefhrt werden. Attribute besitzen einen Namen und einen Wert.

    XML-Zeichen und XML-Einheiten

    Eine XML-Datei besteht aus verschiedenen Einheiten: Kommentaren,Leerraum, Verarbeitungsanweisungen oder Elementen. Auch hier gel-ten einige Regeln, ebenso wie fr die Angabe von bestimmten Zeicheninnerhalb einer XML-Datei.

    LeerraumLeerraum wird innerhalb einer XML-Datei ignoriert oder beim Parsingmit beachtet, abhngig von der Einstellung der entsprechenden Klasse.Im .NET-Framework geschieht dies ber eine Eigenschaft mit demNamen PreserveWhitespace. Ist Leeraum innerhalb eines Elements vonBedeutung, beispielsweise fr die Einrckung in einem Listing, dannsollten Sie das Attribut xml:space verwenden und einen Wert von"preserve" setzen. Der Defaultwert "default" legt fest, dass die Einstel-lungen des Parsers verwendet werden.

  • Sandini Bib

    .NETEssentials

    10

    1 XML-Basics

    Kommentare Ein Kommentar beginnt auch in XML mit der Zeichenfolge . Innerhalb eines Kommentars drfenkeine doppelten Bindestriche vorkommen. Kommentare sind nichtinnerhalb eines Element-Tags erlaubt und drfen auch nicht vor derersten Verarbeitungsanweisung vorkommen, die eine XML-Datei alssolche kennzeichnet (, Details s.u.).

    PIs Eine Verarbeitungsanweisung (processing instruction) ist kein Element,sondern eine Anweisung an den XML-Parser bzw. die Anwendung,eine bestimmte Aktion auszufhren oder eine Kennzeichnung frbestimmte Eigenschaften des Dokumentes. Diese beginnen immer mitder Zeichenkette .

    CDATA Soll ein Abschnitt oder Elementinhalt als regulrer Text aufgefasst wer-den, ohne dass der XML-Parser versucht, darin Markup zu erkennen,kann dieser Abschnitt als CDATA-Sektion (CDATA steht fr characterdata) geschrieben werden. Dazu wird folgendes Konstrukt verwendet:

    ,ohne dass der Parser ber diese Zeichen stolpert ]]>

    Listing 1.1: Ein CDATA-Abschnitt

    Entities Sonderzeichen bzw. Entitten beginnen in XML immer mit einem kauf-mnnischen Und-Zeichen (&) und enden mit einem Semikolon (;). Fol-gende Entities sind bereits vordefiniert:

    Elemente Elemente sind der ganze Rest, also ein ffnendes und ein schlieendesTag, dazwischen entweder weitere Elemente oder ein Textinhalt. Auchein gemischter Inhalt aus Textzeichen, Unterelementen oder z.B.CDATA ist mglich. Alternativ zu der Konstruktion kann ein Element ohne Inhalt auch als abgekrzt werden.

    t Entity Bedeutung& Das &-Zeichen< Das -Zeichen

    " Das "-Zeichen

    ' Das '-Zeichen

    Das Zeichen mit dem Code 00

    Das Zeichen mit dem hexadezimalen Code 00

    Tabelle 1.1: Vordefinierte Entittszeichen in XML

  • Sandini Bib

    .NETEssentials

    11

    Namensrume

    Gltig oder wohlgeformt

    Im Gegensatz zum butterweichen HTML-Standard mssen XML-Strukturen wesentlich strikteren Regeln folgen. Dabei wird zwischeneinem gltigen und einem wohlgeformten Dokument unterschieden.Wir kommen gleich auf diesen Unterschied zurck. Generell gelten frXML-Strukturen die folgenden Regeln:

    Es wird strikt zwischen Gro- und Kleinschreibung unterschieden,d.h. ein Tag ist ein anderes Tag als .

    Jedes geffnete Tag muss auch wieder geschlossen werden.

    Attributwerte mssen grundstzlich in Anfhrungszeichen einge-schlossen werden, die Reihenfolge der Attribute in einem Elementist nicht definiert. Ohne ein Schema sind nur CDATA-Attributwerteerlaubt.

    Es sind keine isolierten Auszeichnungszeichen (wie ) erlaubt,diese mssen als Entitten angegeben werden, z.B. > als >.

    Tags mssen korrekt geschachtelt werden, d.h. es sind keine ver-schrnkten Schachtelungen erlaubt.

    Zu Beginn einer XML-Datei steht die Verarbeitungsanweisung mit einer Versionsangabe (obligatorisch) und einer Zeichen-codierung (optional), z.B. .

    Eine XML-Struktur oder -datei, die diese Bedingungen erfllt, wird alswohlgeformte XML-Datei bezeichnet.

    Eine gltige XML-Datei liegt dann vor, wenn der Inhalt dieser Dateianhand einer Grammatik validiert werden kann (beispielsweise bereine DTD oder ein XSD-Schema).

    1.2 Namensrume

    Das Problem der Namenskonflikte ist so alt wie die Softwareentwick-lung selbst. Stellen Sie sich vor, Sie entwickeln ein Kalenderprogrammmit Datumsberechnungen. Natrlich nennen Sie diese Klasse Datum. Ineinem Nachbarteam arbeitet ein Kollege ebenfalls an einer Klasse frDatumsberechnung, allerdings fr den Kalender der Inkas. Auch ernennt seine Klasse Datum. In einem System ohne Namespaces htten Sienun ein Problem. Mit dem .NET-Framework und den Namensrumenerhalten Sie zwei Vorteile: Zum einen besitzen Sie damit eine weitereMglichkeit, logisch zusammengehrige Klassen in einem Namens-raum zu sammeln. Zum anderen vermeiden Sie damit die Konflikte beider Namensgebung von Klassen und mssen sich nicht irgendwelcheobskuren Prfixe aus Vorname und Blutgruppe des Entwicklers fr die

    t

  • Sandini Bib

    .NETEssentials

    12

    1 XML-Basics

    Benennung von Klassen ausdenken. Wenn Sie sich jetzt fragen, wodenn dabei das Problem liegt, arbeiten Sie einfach mal ein Jahr lang ineinem Programmierteam mit 20 Entwicklern.

    Namensrume gibt esauch woanders

    Ein anderes Beispiel sind Internet-Domains. Ein Domainname wieTollesProdukt ist nur einmal vorhanden. Glcklicherweise existiert frdas Domain Name System eine auf Namensrumen basierende Lsung,die sogenannten Toplevel-Domains. Unterhalb von z.B. .com kann es dieDomain geben, genauso aber unterhalb von .net und beispielsweise .de,damit haben dann immerhin drei Firmen die Mglichkeit, sich um die-sen Namen zu streiten. Bei DNS wird der Namensraumkennzeichnerals Postfix an den Domainnamen angehngt, da Domainnamen vonrechts nach links gelesen werden, um in der Hierarchie abzusteigen.

    XML-Namensrume

    Auch bei XML-Namensrumen existiert ein Prfix-Kennzeichner, dervor dem eigentlich Elementnamen geschrieben wird und durch einenDoppelpunkt vom Elementnamen getrennt wird. Der eigentlicheNamensraum selbst wird durch einen URI angegeben und bei der Defi-nition mit diesem Prfix verknft.

    URI/URN: siehe RFC2396

    Die obige Zeile zeigt die Definition eines Namensraumes und die Ver-wendung des entsprechenden Prfix fr das Element. Weitere Details,auch die Verwendung von XML-Namensrumen im Programmcode,finden Sie im Kapitel ber die Untersttzung von Namensrumen.

    .NET-Namensrume

    Auch ein komplexes Produkt wie das .NET-Framework kommt nichtohne einen Mechanismus zur Vermeidung von Namenskonflikten aus.So ist es ohne weiteres mglich, zwei Klassen mit dem Name Error zudefinieren, solange sich diese beiden Klassen in verschiedenenNamensrumen befinden. Auch in .NET wird der Namensraum (imGegensatz beispielsweise zum Internet Domain Name System) vor demNamen der Klasse angegeben, die einzelnen Elemente werden hierdurch einen Dezimalpunkt getrennt und Namensrume sind imGegensatz zu XML hierarchisch ber mehrere Ebenen schachtelbar.

    Achten Sie also darauf, XML-Namensrume und .NET-Namensrumefr Klassen nicht zu verwechseln.

  • Sandini Bib

    .NETEssentials

    13

    Die .NET-Namensrume

    1.3 Die .NET-Namensrume

    Die gesamte Funktionalitt der XML-Basisklassen ist in dem ffentli-chen Assembly System.Xml.dll enthalten, das im globalen Assembly-cache liegt. Aus Grnden der bersichtlichkeit wurden die einzelnenFunktionsblcke in verschiedene Namenspaces unterteilt.

    System.XmlHier finden sich die allgemeinen Klassen und Typen wie XmlReaderund XmlWriter.

    System.Xml.XPathDieser Namensraum beinhaltet alle Typen, die fr die Abfrage vonXml-Strukturen mit Hilfe der XPath-Sprache bentigt werden.

    System.Xml.XslDie Transformation von Xml-Strukturen in andere Formate odereinen anderen Aufbau der Xml-Struktur wird durch die Datentypenin diesem Namensraum ermglicht. In der Literatur (und auch im.NET-Framework) finden Sie manchmal anstelle der AbkrzungXSL auch die Ablrzung XSLT.

    System.Xml.SchemaIn diesen Namensraum befinden sich die Datentypen zur Validie-rung von Xml-Strukturen auf Gltigkeit und die Klassen fr dasSchema Object Model, das, hnlich wie das Document Object Modelfr Dokumente, fr die Baumdarstellung von Schemas vorhandenist.

    System.Xml.SerializationHier finden Sie die Klassen fr die Serialisierung von Instanzen ineine XML-Datei.

    Auf eine Auflistung aller in den jeweiligen Namensrumen enthaltenenKlassen wird hier aus Platzgrnden verzichtet. Erstens macht es keinenSinn, hier einfach Informationen zu wiederholen, die Sie genauso gut inder Online-Hilfe zum .NET-Framework finden, zum anderen ist aufGrund der Konzeption dieses Buches auch gar kein Platz fr ellenlangeTabellen.

    1.4 Untersttzte Standards

    Microsoft hat sich bei der Planung der .NET-Initiative bemht, beste-hende und in Planung befindliche offene Standards so gut als mglicheinzuhalten. Fr den Bereich XML finden Sie hier eine Liste der unter-sttzten Standards mit dem URL fr weitere Informationen:

  • Sandini Bib

    .NETEssentials

    14

    1 XML-Basics

    Die wichtigstenStandards

    XML 1.0http://www.w3.org/TR/1998/REC-xml-19980210 (einschlielich DTD-Untersttzung)

    XML-Namespaceshttp://www.w3.org/TR/REC-xml-names/ (sowohl Streamebene als auch DOM)

    XSD-Schemashttp://www.w3.org/2001/XMLSchema

    XPath-Ausdrckehttp://www.w3.org/TR/xpath

    XSLT-Transformationenhttp://www.w3.org/TR/xslt

    DOM Level 1 Corehttp://www.w3.org/TR/REC-DOM-Level-1/

    DOM Level 2 Corehttp://www.w3.org/TR/DOM-Level-2/

  • Sandini Bib

    .NETEssentials

    15

    2 XmlReader und XmlWriter

    Die Basis fr die XML-Infrastruktur in .NET bilden unter anderem diebeiden abstrakten Klassen XmlReader und XmlWriter. Diese beiden Klas-sen definieren den grundlegenden Leistungsumfang fr alle abgeleite-ten Klassen.

    2.1 Lesen von XML-Daten

    Die .NET-Laufzeitumgebung untersttzt fr den Zugriff auf XML-Dateien sowohl den DOM-Ansatz als auch einen Streaming-Zugriffhnlich SAX.

    Mssen Sie innerhalb des Dokumentes navigieren oder wahlfrei schrei-ben, bleibt nur das Document Object Model, welches eine Baumstruk-tur aller Knoten im Speicher aufbaut. Sicherlich nicht geraderessourcenschonend, aber mit allen Mglichkeiten der Manipulationder einzelnen XML-Elemente und ihrer Inhalte.

    Die Arbeitsweise des XmlReaders

    Firehose = Feuerwehr-schlauch, Fachausdruck fr schnellsten Zugriff

    Der andere Ansatz ist eine Art Streaming der XML-Dokumente, eineMethode, die bereits seit lngerem von beipielsweise dem SAX-Proto-koll verfolgt wird. Hier sind die Anforderungen an die Ressourcenwesentlich geringer. Im Gegensatz zu SAX implementiert XmlReaderaber ein Pull-Modell, bei dem die Applikation die Daten abholt unddaher auch uninteressante Teile der Datei berlesen lassen kann. DieseArt von Zugriff wird (beipielsweise in der Datenbankwelt) auch oft alsFirehose Cursor bezeichnet, da nur vorwrts lesend durch die Dateigegangen wird und dies (analog dem Feuerwehrschlauch) die Methodemit dem besten Durchsatz darstellt.

    Von der abstrakten Klasse XmlReader abgeleitet existieren im .NET-Framework drei Klassen: XmlTextReader, XmlNodeReader und die KlasseXmlValidatingReader, die eine Mglichkeit der berprfung auf Gltig-keit des Dokumentes erlaubt.

    Die Klasse XmlReader und die davon abgeleiteten Klassen arbeiten miteinem depth first-Ansatz, d.h. es wird zuerst innerhalb eines Knotensin die Tiefe gesucht und danach werden die Geschwisterknoten desaktuellen Knotens abgearbeitet.

  • Sandini Bib

    .NETEssentials

    16

    2 XmlReader und XmlWriter

    XmlReader / XmlTextReader

    Der einfachste Ansatz ist das Einlesen eines XML-Dokuments voneinem URL oder einem Dateinamen .

    // einlesen einer XML-Dateipublic void ReadXmlDoc(string docurl){ XmlTextReader rdr = new XmlTextReader(docurl); while (rdr.Read()) { // behandlung des aktuellen knotens } rdr.Close();}

    Listing 2.1: Die einfachste Art, eine XML-Datei zu lesen

    Innerhalb der while-Schleife kann nun der aktuell gelesene Knoten derDatei untersucht und entsprechend verarbeitet werden.

    Das Konzept des aktuellen Knotens

    Die .NET-Laufzeitumgebung implementiert das Konzept eines aktuel-len Knotens. Beim Lesen mit einer XmlReader-Instanz wird dieser aktu-elle Knoten ber die verschiedenen Methoden immer weiter nachvorne bewegt, bis das Ende einer Datei erreicht wird. Dieser aktuelleKnoten ist nicht notwendigerweise immer ein XML-Element. DieEigenschaft NodeType des XmlReaders enthlt einen der folgendenWerte, die im Namensraum System.XML in der Aufzhlung XmlNodeTypedefiniert werden:

    t Name BeschreibungAttribute Ein Attribut, z.B. units="Celsius" CDATA Ein CDATA-Bereich, der Text enthlt, der sonst als XML-Aus-

    zeichnung erkannt wrde, z.B. ]]>

    Comment Ein Kommentar, z.B.

    Document Das Dokumentenobjekt, welches die Wurzel des XML-Baums darstellt.

    DocumentFrag-ment

    Ein XML-Fragement beinhaltet einen Knoten oder einen Teil-baum, nicht notwendigerweise in einem eigenen Dokument.

    DocumentType Der Dokument-Typ, z.B.

    Element Ein einzelnes XML-Element, z.B.

    EndElement Ein schlieendes Tag fr ein Element, z.B.

    Tabelle 2.1: Die von XmlReader gelieferten Knotentypen

  • Sandini Bib

    .NETEssentials

    17

    Lesen von XML-Daten

    Knotentypen unterscheiden

    Fr die nachfolgende kleine XML-Datei, die in den nchsten Beispielenbenutzt wird, soll nun jeweils der Knotentyp sowie der Name des Ele-ments ausgegeben werden.

    Algeirs overcast 11 93% E 5 1028 rising Athens mostly cloudy 16 77% SW 2 1024

    EndEntity Wird als Ergebnis einer Entity-Auflsung mit ResolveEntity zurckgeliefert und markiert das Ende eines Entity.

    Entity Die Deklaration eines XML-Entity, z.B.

    EntityReference Die Referenz auf ein Entity, z.B.

    None Wird geliefert, wenn noch nie die Methode Read aufgerufen wurde.

    Notation Ein Notationseintrag in der DTD, z.B.

    ProcessingInstruc-tion

    Eine Verarbeitungsanweisung, z.B.

    Significant-Whitespace

    Leerraum, der beachtet werden soll, wenn z.B. die Option xml:space="preserve" verwendet wurde.

    Text Der Textinhalt eines XML-Knotens

    Whitespace Leerraum zwischen Auszeichnungsknoten

    XmlDeclaration Die XML-Deklaration selbst, z.B. ; diese Anweisung muss der erste Knoten im Dokument sein.

    Name Beschreibung

    Tabelle 2.1: Die von XmlReader gelieferten Knotentypen (Fortsetzung)

  • Sandini Bib

    .NETEssentials

    18

    2 XmlReader und XmlWriter

    rising

    Listing 2.2: Die Beispieldatei mit XML-Inhalt

    Da sich der Leerraum (white space) schlecht anzeigen lsst, erfolgt dieAusgabe hier ber die Klasse Convert als Hexdump der Zeichencodes.

    // neue methode ReadXmlDoc mit Knotenbehandlungusing System;using System.XML;using System.Text;

    namespace XmlReader{

    class clsReaderClass{ XmlTextReader rdr;

    public clsReaderClass(string docurl){ rdr = new XmlTextReader(docurl);}

    public void ReadXmlDoc(){ while (rdr.Read()) { // den typ des knotens als string ausgeben Console.Write(rdr.NodeType); // abhngig vom typ ausgabe bauen switch(rdr.NodeType) { // ein element: name ausgeben case XmlNodeType.Element: Console.Write(" "); break;

    // schliessendes tag: / + name case XmlNodeType.EndElement: Console.Write(" "); break;

    // textinhalt: achtung! value statt name! case XmlNodeType.Text: Console.Write(" " + rdr.Value); break;

  • Sandini Bib

    .NETEssentials

    19

    Lesen von XML-Daten

    // whitespace: zeichen als hexdump ausgeben case XmlNodeType.SignificantWhitespace: case XmlNodeType.Whitespace: for(int i = 0; i < rdr.Value.Length; i++) { int cv = Convert.ToUInt16(rdr.Value[i]); Console.Write(" {0:X2}", cv); } break; } Console.WriteLine(); } rdr.Close();}

    //// Die Testklasse fr clsReaderClass//class TestClass{

    static void Main(string[] args) { clsReaderClass rc; rc = new clsReaderClass("miniwetter.xml"); rc.ReadXmlDoc(); }}}

    Listing 2.3: Unterscheidung der einzelnen Knotentypen

    Hier die Ausgabe des Programms bis zum Ende des ersten station-Knotens:

    XmlDeclarationWhitespace 0D 0AElement Whitespace 0D 0A 09Element Whitespace 0D 0A 09 09Element Text AlgeirsEndElement Whitespace 0D 0A 09 09Element Text overcastEndElement Whitespace 0D 0A 09 09Element

  • Sandini Bib

    .NETEssentials

    20

    2 XmlReader und XmlWriter

    Text 11EndElement Whitespace 0D 0A 09 09Element Text 93%EndElement Whitespace 0D 0A 09 09Element Text EEndElement Whitespace 0D 0A 09 09Element Text 5EndElement Whitespace 0D 0A 09 09Element Text 1028EndElement Whitespace 0D 0A 09 09Element Text risingEndElement Whitespace 0D 0A 09EndElement

    Listing 2.4: Die Ausgabe der einzelnen Knoten

    Fehlerbehandlung beim Lesen

    Wird die Wohlgeformtheit des Dokuments durch eine ungltige XML-Konstruktion verletzt, wird eine XmlException ausgelst und der Lese-vorgang abgebrochen.

    Lesen bestimmer Elemente und Datentypen

    Leere Elemente finden Fr viele Anwendungszwecke muss sichergestellt werden, dass deraktuelle Knoten ein bestimmtes Element enthlt. Hierzu exisitierenweitere Methoden der XmlReader-Klasse, die ein bestimmtes Elementerwarten. So kann mit der Methode IsStartElement festgestellt werden,ob der aktuelle Knoten ein Starttag ist, whrend beispielsweise IsEmpty-Element dann true liefert, wenn es sich um ein leeres Element in derForm handelt.

    Die Methode ReadStartElement erlaubt das Lesen ganz bestimmter Ele-mente und ein manuelles Parsing der Datei, so dass eine Exception aus-gelst wird, wenn das Element nicht den erwarteten Namen besitzt.

  • Sandini Bib

    .NETEssentials

    21

    Schreiben von XML-Dateien

    2.2 Schreiben von XML-Dateien

    Das Schreiben von XML-Daten als Strom erfolgt mit Hilfe einer von derabstrakten Klasse XmlWriter abgeleiteten Klasse. In der aktuellen Versiondes .NET-Frameworks existiert eine Implementierung in der KlasseXmlTextWriter, die auch fr die folgenden Beispiele benutzt wird.

    Instantiierung der Klasse

    Der Konstruktor der Klasse XmlTextWriter ist dreifach berladen. Sieakzeptiert entweder einen vorhandenen TextWriter, einen Stream odereinen Dateinamen als Parameter, wobei fr den Dateinamen und denIO-Stream als zweiter Parameter noch die Codierung der Zeichen ange-geben werden kann (wird dieser auf null gesetzt, erfolgt die Ausgabemit der Standardcodierung UTF-8).

    // instanz per dateinamen erzeugen// die datei wird bei existenz neu berschrieben

    XmlTextWriter xtw = new XmlTextWriter(@"c:\tmp\ausgabe.xml", null);

    Listing 2.5: Beispiel-Instantiierung per Dateinamen fr XmlTextWriter

    Schreiben von Elementen und Attributen

    Die Methoden zum Erstellen des Inhaltes sind leicht zu finden undanzuwenden, deren Namen sind ebenfalls weitestgehend selbsterkl-rend. Das folgende Beispiel zeigt eine Methode zum Schreiben einereinfachen XML-Datei.

    public static void DemoXmlTextWriter(){ // instanz erzeugen XmlTextWriter xtw = new XmlTextWriter(@"c:\tmp\ausgabe.xml", null);

    // inhalte schreiben xtw.WriteStartElement("buecher"); xtw.WriteElementString("titel", "Von Windows verweht ..."); xtw.WriteStartElement("preis"); xtw.WriteAttributeString("waehrung","EUR"); xtw.WriteString("14.55"); xtw.WriteEndElement(); xtw.WriteEndElement();

    // writer schliessen

  • Sandini Bib

    .NETEssentials

    22

    2 XmlReader und XmlWriter

    xtw.Close();

    Console.WriteLine("Datei geschrieben.");}

    Listing 2.6: Schreiben von XML, die erste Version

    WriteStartElement vs.WriteElement String

    Wie Sie aus dem Listing erkennen, existiert zum Schreiben von Elemen-ten eine Methode WriteElementString, die Starttag, Inhalt und Endtag ineinem Aufruf schreibt. Soll das Element jedoch Unterelemente oderAttribute enthalten, dann benutzen Sie besser die Methoden WriteStart-Element und WriteEndElement, mit denen Sie die einzelnen Elementegezielt beginnen und beenden knnen. Die Ausgabe des Programms inder Datei c:\tmp\ausgabe.xml sieht dann so aus:

    Von Windows verweht ...14.55

    Listing 2.7: Inhalt der erzeugten Datei

    Hier sind noch einige Sachen zu verbessern. Zuerst ist dies keine gltigeXML-Datei, noch nicht mal eine wohlgeformte, da die Verarbeitungsan-weisung fehlt. Auerdem wre eine fr den (menschlichen)Entwickler etwas bessere Lesbarkeit recht schn. Diese beiden Punkteerreichen Sie durch ein paar nderungen im Code. Zuerst werden diebeiden Methoden WriteStartDocument und WriteEndDocument integriert, diefr einen sauberen Rahmen um die XML-Struktur sorgen. Danachwird die Formatierung noch umgestellt. Hier die nderungen im Code:

    public static void DemoXmlTextWriter(){ // instanz erzeugen XmlTextWriter xtw = new XmlTextWriter(@"c:\tmp\ausgabe.xml", null);

    // formatierung einstellen

    // pro ebene 1 tab eingerckt

    xtw.Indentation = 1;

    xtw.IndentChar = '\t';

    xtw.Formatting = Formatting.Indented;

    // inhalte schreiben xtw.WriteStartDocument();

    xtw.WriteStartElement("buecher"); xtw.WriteElementString("titel", "Von Windows verweht ..."); xtw.WriteStartElement("preis"); xtw.WriteAttributeString("waehrung","EUR");

  • Sandini Bib

    .NETEssentials

    23

    Schreiben von XML-Dateien

    xtw.WriteString("14.55"); xtw.WriteEndElement(); xtw.WriteEndElement(); xtw.WriteEndDocument();

    // writer schliessen xtw.Close();

    Console.WriteLine("Datei geschrieben.");}

    Listing 2.8: Ausgabe mit XML-PI und Formatierung

    Jetzt findet sich in der Ausgabe auch eine wohlgeformte XML-Strukturmit einer lesbaren Formatierung:

    Von Windows verweht ... 14.55

    Listing 2.9: Inhalte der Ausgabedatei

    Nachdem es im Gegensatz zu beispielsweise HTML bei XML immerein schlieendes Tag geben muss, werden Elemente ohne Inhalt in derNotation geschrieben. Viele Programme kommen damitaber nicht zurecht (vor allem ltere Browser), daher kann anstelle derMethode WriteEndElement die Methode WriteFullEndElement benutzt wer-den, die eine Ausgabe in der Form erzeugt.

    Neben der Methode WriteString zum Schreiben von Textinhalten exis-tieren noch Methoden zum Schreiben von Binrdaten in BinHex- oderBase64-Notation, als CDATA-Bereich oder als Entity-Referenz fr Uni-code-Zeichen. Alle diese Methoden folgenden aber dem gleichen Prin-zip, so dass ein eigenstndiges Beispiel fr jede dieser Methoden hiernicht notwendig ist.

    XML mit XmlWriter und XmlReader modifzieren

    Als Abschluss fr dieses Kapitel ein kleines Beispiel, wie mit Hilfe dieserStreamingklassen auch groe Dateien ressourcenschonend verarbeitetwerden knnen. Nehmen wir an, in einer als XML-Datei vorliegendenBcherliste soll die Umstellung von DEM auf EUR vorgenommen wer-den (gut, dass wir das schon alle hinter uns haben!). Mit einem XmlText-Reader werden die einzelnen Knoten gelesen und ber eine XmlTextWriter-Instanz in die Ausgabedatei geschrieben. Wird ein Element mit demNamen Preis angetroffen, wird dessen Textinhalt von Mark nach Euro

  • Sandini Bib

    .NETEssentials

    24

    2 XmlReader und XmlWriter

    umgerechnet und ein evtl. vorhandenes Attribut Whrung ebenfallskorrekt umgestellt.

    // umwandeln von xml-dateien per streaming-zugriff

    public static void DemoModifyXml(string inURL, string outURL){ // die reader und writer XmlTextReader rdr = new XmlTextReader(inURL); XmlTextWriter wrt = new XmlTextWriter(outURL, null);

    // ausgabe einruecken wrt.Formatting = Formatting.Indented; wrt.Indentation = 4; wrt.IndentChar = (char)32;

    // marker fuer preis-element bool bPreistag = false;

    // dokumenten-start-pi schreiben wrt.WriteStartDocument();

    // alle knoten lesen while (rdr.Read()) { // abhngig vom typ ausgabe bauen switch(rdr.NodeType) { // element, auf "preis" testen case XmlNodeType.Element: bPreistag = (rdr.Name == "preis"); if(bPreistag) Console.WriteLine("{0} gefunden!", rdr.Name); wrt.WriteStartElement(rdr.Name); // attribute mit kopieren if(rdr.HasAttributes) { for(int i = 0;i < rdr.AttributeCount;i++) { rdr.MoveToAttribute(i); // waehrung ist jetzt EUR // also eintragen if(rdr.Name == "waehrung") wrt.WriteAttributeString(rdr.Name,"EUR"); else wrt.WriteAttributeString(rdr.Name,rdr.Value); } } break;

  • Sandini Bib

    .NETEssentials

    25

    Schreiben von XML-Dateien

    // schliessendes tag: / + name case XmlNodeType.EndElement: if(rdr.Name == "preis" && bPreistag) { bPreistag = false; Console.WriteLine("/{0} gefunden!", rdr.Name); } wrt.WriteEndElement(); break;

    // textinhalt: achtung! value statt name! case XmlNodeType.Text: if(bPreistag) { decimal betrag = decimal.Parse(rdr.Value); betrag = betrag / 1.955830m; Console.WriteLine("Konvertiert!"); wrt.WriteString(betrag.ToString("F2")); } else wrt.WriteString(rdr.Value); break; } } rdr.Close(); wrt.WriteEndDocument(); wrt.Close();}

    Listing 2.10: XML-Konvertierung manuell

    Hier die beiden Dateien, zuerst die Eingabe-, dann die Ausgabedateinach der Konvertierung:

    Von Windows verweht ... 29,90 Alice im Windowsland 34,80

    Listing 2.11: Die Eingabedatei

  • Sandini Bib

    .NETEssentials

    26

    2 XmlReader und XmlWriter

    Von Windows verweht ... 15,29 Alice im Windowsland 17,79

    Listing 2.12: Die Ausgabedatei

    2.3 Zusammenfassung

    Die Klassen XmlReader und XmlWriter sowie die davon abgeleitetenKlassen bieten einen ressourcenschonenden Zugriff auf XML-Dateienin Streaming-Form. Sie haben erfahren, wie sich feststellen lsst, wel-chen Knoten Sie gerade lesen, wie Elemente und Attribute geschriebenwerden und wie mit Hilfe dieser Klassen auf einfache Art und Weisekleinere nderungen in XML-Dateien durchgefhrt werden knnen.

    Dieser rein lesend bzw. schreibende, nur vorwrtsgerichtete Zugriffreicht aber nicht aus, um alle Szenarien abzudecken. Fr komplexerenderungen oder die Navigation innerhalb der XML-Struktur reichtdieser Ansatz nicht mehr aus. Daher erfahren Sie im nchsten Kapitel,wie Sie den Zugriff ber das Document Object Model realisieren. Mitdieser Schnittstelle knnen Sie jeden Knoten eines Dokuments einzelnnach Ihren Anforderungen anspringen und ndern.

  • Sandini Bib

    .NETEssentials

    27

    3 Serialisierung und XML

    Einfhrung

    TerminologieSerialisierung bedeutet, vereinfacht ausgedrckt, das berleben derObjekte nach einem Programmende oder die Verpackung der Objektefr den Transport ber Prozess- und Maschinengrenzen bei einemRemote-Aufruf. Fr OOP-Systeme, die Mechanismen fr solche Aktio-nen boten, wurde dies dadurch gewhrleistet, dass aktuelle Daten undVariableninhalte in eine Datei geschrieben wurden. Der Code lag in derausfhrbaren Datei vor und nach dem erneuten Start wurde die Daten-datei geffnet und der Entwickler hatte die Aufgabe, alle Daten wiederin die richtigen Strukturen zu laden. Innerhalb des .NET-Frameworksist XML das Rckgrat fr die Serialisierung von Klasseninstanzen. Diefr die Nutzung dieser Funktionalitt bentigten Namensrume des.NET-Frameworks sind System.XML und System.XML.Serialization.

    Serialisierung mit XmlSerializer

    Die Klasse XmlSerializer ist fr die Serialisierung einer Instanz in eineXML-Datei bzw. den umgekehrten Weg zurck zu einer Instanz zustn-dig. In der einfachsten Form erhlt der Konstruktor einen Parametermit dem Typ des Objekts, fr das er zustndig sein soll.

    Hier eine sehr einfache Demoklasse, die in eine XML-Datei serialisiertwerden soll:

    // eine einfache demo-klassepublic class SimpleDemo{ public string Kennzeichen; public int KmStand; public double Verbrauch;}

    Listing 3.1: Die erste Demoklasse

    Als Ziel fr die Serialisierung knnen Sie bei der Methode Serialize desXmlSerializer drei mgliche Ausgabetypen spezifizieren:

    Einen XmlWriter oder einen Nachfahren

    Einen Stream oder einen Nachfahren

    Einen TextWriter oder einen Nachfahren

  • Sandini Bib

    .NETEssentials

    28

    3 Serialisierung und XML

    Nachdem es hier nur um das Herauschreiben der Instanzdaten geht,verwenden wir im Listing einen XmlWriter, da dieser als reine vorwrts-gerichtete Nur-Schreiben-Klasse den geringsten Overhead besitzt.

    Hier der Code, mit dem die Instanz serialisiert wird:

    class TestClass{ static void Main(string[] args) { XmlSerializer ser = new XmlSerializer(typeof(SimpleDemo)); XmlTextWriter tw = new XmlTextWriter("ausgabe.xml", null);

    SimpleDemo d = new SimpleDemo();

    d.Kennzeichen = "LA-DY 2002"; d.KmStand = 45800; d.Verbrauch = 7.85;

    ser.Serialize(tw, d); tw.Close();

    Console.WriteLine("Objekt serialisiert.");

    Console.Write("\nPress a key ...."); Console.ReadLine(); }}

    Listing 3.2: Serialisierung in eine XML-Datei

    Nach dem erfolgreichen Durchlaufen des Codes liegt die Datei auf derPlatte und Sie knnen sich deren Inhalt ansehen:

    Objekte als XML

    LA-DY 2002 45800 7.85

    Listing 3.3: Der Inhalt der XML-Ausgabedatei

    Sie erkennen, dass das Wurzelelement den Namen der Klasse trgt unddie einzelnen Elemente mit ihrer Bezeichnung den Namen der Felderentsprechen. Zustzlich werden die beiden Deklarationen der Namens-

  • Sandini Bib

    .NETEssentials

    29

    rume fr XML-Schemas und XML-Schemainstanzen mit in das Wur-zelelement aufgenommen (mehr zu Namensrumen erfahren Sie imKapitel XML-Namensrume).

    Deserialisierung mit XmlSerializer

    Um aus einer XML-Datei eine Instanz einer Klasse zu laden, gehen sieeinfach den umgekehrten Weg.

    class TestClass{ static void Main(string[] args) { XmlSerializer ser = new XmlSerializer(typeof(SimpleDemo));

    // diesmal einen reader einsetzen XmlTextReader rdr = new XmlTextReader("ausgabe.xml");

    SimpleDemo d;

    // klasseninstanz aus dem serializer d = ser.Deserialize(rdr) as SimpleDemo; rdr.Close();

    // instanzdaten ausgeben Console.WriteLine("Objekt deserialisiert:"); Console.WriteLine(d.Kennzeichen); Console.WriteLine(d.KmStand); Console.WriteLine(d.Verbrauch);

    Console.Write("\nPress a key ...."); Console.ReadLine(); }}

    Listing 3.4: Deserialisierung aus einer XML-Datei

    Abbildung 3.1: Die Ausgabe des Deserialisierungsbeispiels

  • Sandini Bib

    .NETEssentials

    30

    3 Serialisierung und XML

    Dieser Code produziert die in Abbildung 3.1 zu sehende Ausgabe undzeigt damit, dass so sehr leicht aus einer XML-Datei eine Objektinstanzerzeugt werden kann.

    Ungleiche Dokumente und Klassen

    Falls ein Schema vorliegt, knnen Sie mit dem folgenden Aufruf ausdem Schema eine passende Klasse erstellen lassen, um dieses Problemzu vermeiden.

    Das Tool xsd.exe xsd schema0.xsd /classes

    Anschliessend wird eine Datei schema0.cs erzeugt, die eine Klasse mitden aus dem Schema gewonnen Feldern enthlt.

    //-----------------------------------------------------// // This code was generated by a tool.// Runtime Version: 1.0.3705.0//// Changes to this file may cause // incorrect behavior and will be lost if // the code is regenerated.// //-----------------------------------------------------

    // // This source code was auto-generated by xsd, Version=1.0.3705.0.// using System.XML.Serialization;

    /// [System.XML.Serialization.XmlRootAttribute(Namespace="", IsNullable=true)]public class SimpleDemo { /// public string Kennzeichen; /// public int KmStand; /// public System.Double Verbrauch;}

    Listing 3.5: Automatisch aus einem Schema erzeugte Klasse

  • Sandini Bib

    .NETEssentials

    31

    Was aber passiert nun, wenn die Definition der Klasse nicht mit demAufbau der Datei bereinstimmt? Eine Mglichkeit wre es, nurDateien anzunehmen, deren Aufbau genau der Klasse entspricht,indem fr die Klasse ein Schema erstellt und das Dokument damit vali-diert wird. Ein Beispiel dafr finden Sie im Kapitel ber die Validierungvon XML-Dokumenten.

    Zustzlicher Inhalt in der XML-Datei

    Fr den anderen Fall wird die XML-Datei um ein zustzliches Elementergnzt, das in der Klasse nicht vorhanden ist. Ebenso wird die Klasseum ein weiteres Feld ergnzt, das in der XML-Datei nicht vorhandenist.

    LA-DY 2002 45800 108 7.85

    Listing 3.6: Die genderte XML-Datei

    // eine einfache demo-klassepublic class SimpleDemo{ public string Kennzeichen; public int KmStand; public double Verbrauch; public string Hersteller;}

    Listing 3.7: Die genderte Klasse mit dem neuen Feld

    Bei der Ausfhrung des Programms erfolgt keine Fehlermeldung unddie Ausgabe zeigt das Standardverhalten bei der Behandlung unbe-kannter Elemente in der XML-Datei:

    Abbildung 3.2: Deserialisierung mit den genderten Daten

  • Sandini Bib

    .NETEssentials

    32

    3 Serialisierung und XML

    Elemente ignorieren Zustzlich vorhandene Elemente werden also bei der Deserialisierungignoriert, Felder in der Klasse ohne einen Inhalt in der XML-Dateiwerden von der Laufzeitumgebung bei der Erzeugung der Instanz ini-tialisiert, bekommen dann aber keinen Wert aus der XML-Datei zuge-wiesen. Dieses Verhalten lsst sich, wie in den sptereren Abschnittengezeigt, auch steuern und beinflussen.

    3.1 XML-Serialisierung im Detail

    Steuerung der XML-Struktur

    Den Serialisierungsprozess, genauer die Erstellung der XML-Datei,knnen Sie ber den Einsatz verschiedener Attribute steuern. So mch-ten Sie vielleicht einige Felder der Klasse nicht als eigene Unterele-mente, sondern als Attribute des Klassenelementes rendern lassen oderfr einige Elemente den Datentyp ndern.

    Serialisierungs-Attribute Um das Wurzelelement der XML-Datei zu ndern, benutzen Sie vor derKlasse das Attribut [XmlRoot()]. Das Attribut [XmlElement] dient derDefinition eines anderen Elementnamens, der vom Namen des Feldesabweicht. Mit Hilfe des Attributes [XmlAttribute] knnen Sie angeben,dass ein Feld nicht als eigenes Element, sondern als Attribut des umge-benden Elternelements gerendert wird.

    // eine einfache demo-klasse[XmlRoot(ElementName = "root")]public class SimpleDemo{ public string Kennzeichen; public int KmStand; [XmlIgnore] public double Verbrauch; [XmlAttribute(AttributeName = "marke")] public string Hersteller;}

    Listing 3.8: Die Klasse mit XML-Steuerungsattributen

    Wird die genderte Klasse jetzt serialisiert, enthlt die XML-Datei dieneuen Daten, wobei das mit dem Attribut [XmlIgnore] deklarierte Feldaus der Datei ausgelassen wird.

  • Sandini Bib

    .NETEssentials

    33

    XML-Serialisierung im Detail

    LA-DY 2002 45800

    Listing 3.9: Der neue Inhalt der XML-Datei

    Serialisierung komplexerer Datentypen

    Fr die Serialisierung von Datentypen wie Eigenschaften, Arrays,geschachtelten Objekten usw. gilt im Prinzip das bereits weiter obengesagte. Fr die folgenden Beispiele wird eine etwas erweiterte Klas-sendefinition benutzt, die ber eine ffentliche Eigenschaft, ein Arrayund Konstruktoren verfgt. Hier der Teil der Klassendefinition mit denentsprechenden Feldern:

    // demo-klasse fr die serialisierungpublic class DemoClass{ // private felder der klasse private int fID; private int fIndentLevel = 0;

    // ffentliche felder public string StrField = "Nur ein String"; public System.UInt32[] liste = {1,3,5,7,11,13,17,19};

    // konstruktoren public DemoClass() { }

    public DemoClass(int theID) { fID = theID; }

    // eine ffentliche eigenschaft public int IndentLevel { get { return fIndentLevel; } set { fIndentLevel = value; } }

    Listing 3.10: Der erste Teil der erweiterten Klassendefinition

    Diese Klasse soll in der Lage sein, sich selbst zu serialisieren und bereine statische Methode aus einer anzugebenden XML-Datei die Deseri-alisierung durchzufhren. Dies wird in die beiden Methoden SaveToXmlund LoadFromXml eingepackt.

  • Sandini Bib

    .NETEssentials

    34

    3 Serialisierung und XML

    // serialisieren in eine xml-datei public void SaveToXml(string filename) { XmlSerializer ser = new XmlSerializer(typeof(DemoClass));

    // einen xmlwriter einsetzen XmlTextWriter xml = new XmlTextWriter(filename, null); xml.Formatting = Formatting.Indented; xml.Indentation = 4; xml.IndentChar = (char)32;

    // klasseninsanz serialisieren ser.Serialize(xml, this); xml.Close(); }

    // deserialisieren aus einer xml-datei public static object LoadFromXml(string filename) { XmlSerializer ser = new XmlSerializer(typeof(DemoClass));

    XmlTextReader rdr = new XmlTextReader(filename);

    if(ser.CanDeserialize(rdr)) return ser.Deserialize(rdr); else return null; }

    } // ende der klassendefinition

    Listing 3.11: Die beiden Wrapper fr die Serialisierung

    Arrays serialisieren Wird eine Instanz dieser Klasse ber den Aufruf von SaveToXml in eineXML-Datei geschrieben, wird eine ffentliche Eigenschaft als XML-Ele-ment mit dem Namen dieser Eigenschaft geschrieben (also analog zueinem normalen ffentlichen Feld). Das Array wird als XML-Elementmit dem Namen des Arrays erstellt und die einzelnen Elemente diesesArrays werden als Unterelemente, jeweils mit dem Namen des Daten-typs, in die Datei geschrieben. Hier die erstellte XML-Datei:

    Hallo!!

  • Sandini Bib

    .NETEssentials

    35

    XML-Serialisierung im Detail

    1 3 5 7 11 13 17 19 4

    Listing 3.12: Die serialisierte Instanz als XML-Datei

    Fr die Deserialisierung muss ein parameterloser Konstruktor in derKlasse vorhanden sein (Sie haben sich vielleicht schon darber gewun-dert). Da der XmlSerializer aus den Daten der XML-Datei nicht erschlie-en kann, welcher Konstruktor mit welchen Parametern aufzurufen ist,muss ein Konstruktor ohne Parameter vorhanden sein, der dann aufge-rufen wird, um die Instanz zu erstellen. ber das Einlesen der restlichenXML-Elemente werden anschlieend die gleichlautenden ffentlichenFelder und Eigenschaften gesetzt.

    Unbekannten XML-Inhalt behandeln

    Sollte in der XML-Datei zustzlicher Inhalt vorhanden sein (in Formvon Elementen, Attributen oder z.B. CDATA-Knoten), dann knnen Sieber Ereignisbehandlungsroutinen das Standardverhalten der Deseria-lisierung ndern. Sind keine solchen Eventhandler definiert, wirdzustzlicher Inhalt in der XML-Datei einfach ignoriert und fr Felderder Klasse, fr die kein Element in der Datei vorhanden ist, wird keineZuweisung durchgefhrt.

    Unknown-EreignisseFr die Steuerung dieses Verhaltens definiert die Klasse XmlSerializerdrei Ereignisse: UnknownElement, UnknownAttribute und UnknownNode. Erstel-len Sie eine Ereignisbehandlungsroutine fr das gewnschte Ereignis,wird diese Methode dann aufgerufen. Fr eine Demonstration erwei-tern wir die Datei aus Listing 3.3 um zustzliche Elemente.

    LA-DY 2002 Renault 45800 7.85

  • Sandini Bib

    .NETEssentials

    36

    3 Serialisierung und XML

    Listing 3.13: Der neue Inhalt der XML-Datei

    Jetzt wird dafr eine Ereignisbehandlungsroutine definiert:

    public void XmlElementEventHandler(object sender, XmlElementEventArgs args){ Console.Write("Bei der Deserialisierung von {0} ", args.ObjectBeingDeserialized.ToString()); Console.Write("wurde ein Element gefunden.", args.Element.LocalName); Console.WriteLine();}

    Listing 3.14: Der EventHandler fr unbekannte Elemente

    Diese Methode wird dem XmlSerializer nach der Instantiierung einge-tragen.

    static void Main(string[] args){ XmlSerializer ser = new XmlSerializer(typeof(SimpleDemo)); XmlTextReader rdr = new XmlTextReader(@"c:\tmp\ser.xml"); ser.UnknownElement += new XmlElementEventHandler(DoUnknownElement);

    SimpleDemo sd = (SimpleDemo)ser.Deserialize(rdr); rdr.Close();

    Console.WriteLine("KmStand: {0}", sd.KmStand);

    Console.Write("\nPress a key ...."); Console.ReadLine();}

    Listing 3.15: Eintragen der Ereignisbehandlung

  • Sandini Bib

    .NETEssentials

    37

    Zusammenfassung

    Hier das Ergebnis des Programmablaufs:

    3.2 Zusammenfassung

    Serialisierung nach XML ist mit dem .NET-Framework auf einfache Artund Weise mglich, wobei Sie jederzeit in diesen Prozess eingreifenund die Serialisierung der Objektinstanzen genauer steuern knnen.

    Abbildung 3.3: Die unbekannten XML-Elemente werden gemeldet.

  • Sandini Bib

  • Sandini Bib

    .NETEssentials

    39

    4 Document Object Model

    4.1 Streaming oder DOM?

    Whrend sich der Zugriff auf XML-Dateien per Streaming durch einengeringen Verbrauch an Ressourcen auszeichnet, besitzt diese Methodedoch den einen oder anderen Nachteil in bestimmten Situationen. WieSie im Kapitel ber XmlReader und XmlWriter (und den davon abgeleite-ten Klassen) nachlesen knnen, ist nur ein vorwrtsgerichtetes Arbeitenmglich. Dies bedeutet, dass die Informationen in der XML-Datei in derReihenfolge gelesen werden mssen, in der diese im Dokument auftau-chen, whrend beim Schreiben bereits die endgltige Reihenfolge derKnoten feststehen muss.

    IDREFBesonders schwierig wird der Zugriff bei Zeigern (z.B. IDREF) inner-halb der Datei oder dem nachtrglichen Einfgen von Knoten. Aus die-sem Grund ist auch bei .NET die Bearbeitung von XML-Dateien berdas Document Object Model mglich. Hier wird der komplette Doku-mentbaum im Speicher aufgebaut, wobei jeder Knoten einer Instanzeines Nachfahren von XmlNode entspricht.

    Dieses Kapitel befasst sich mit den grundlegenden Mglichkeiten des.NET-Frameworks zur Bearbeitung von DOM-Strukturen. Die Metho-den zur Selektion von Untermengen des Dokumentenbaumes mit Hilfevon XPath-Abfragen werden dann im nchsten Kapitel nach einer kur-zen Einfhrung in das Thema XPath behandelt.

    4.2 XML-Dokumente laden und lesen

    Laden bestehender Dokumente

    XmlDocumentDas Laden bestehender Dokumente geschieht ber eine Instanz derKlasse XmlDocument und deren Methode Load. Nach der Erzeugung derInstanz wird also nur die Methode Load benutzt, um dem Dokumentgleich einen Inhalt zuzuweisen.

    // erzeugen eines neuen XML-DokumentesXmlDocument thedoc = new XmlDocument();

    // laden einer bestehenden dateithedoc.Load(@"h:\wetter.xml");

    // hier erfolgt die bearbeitung der Datei

    Listing 4.1: Das Laden von bestehenden XML-Dokumenten

  • Sandini Bib

    .NETEssentials

    40

    4 Document Object Model

    Diese Methode ist mehrfach berladen. So knnen Sie anstelle desDateinamens auch bei Bedarf einen URL oder eine Instanz eines Xml-Readers angeben.

    LoadXml Falls die XML-Daten bereits in Form eines Strings vorliegen, kann die-ser benutzt werden, um den Inhalt des Dokumentes festzulegen. Dafrexistiert die Methode LoadXml, die als Parameter einen String erwartet:

    // erzeugen eines neuen XML-DokumentesXmlDocument thedoc = new XmlDocument();

    // stringinhalt fr XML, hier direkte zuweisungstring s = "Bob";

    // laden einer bestehenden Dateithedoc.LoadXml(s);

    // hier erfolgt die bearbeitung der datei

    Listing 4.2: Das Laden von bestehenden XML-Dokumenten

    Somit sind wir in der Lage, Daten in XML in einem DOM-Objekt zuladen. In den nchsten Abschnitten dieses Kapitels wird es darumgehen, den Inhalt des Dokumentenbaums zu bearbeiten.

    Knoten und Elemente

    XmlNode Die einzelnen Elemente des Dokumentenbaums bestehen aus Knoten,die hier den einzelnen XML-Elementen entsprechen. ber die Eigen-schaft NodeType eines XmlNode lsst sich feststellen, um welchen Knoten essich handelt (Element, Kommentar, Verarbeitungsanweisung, etc.) undentsprechend kann Ihr Programmcode dann darauf reagieren.

    Zur Verdeutlichung des nchsten Listings hier nochmals ein Ausschnittaus der Beispieldatei mit den Wetterdaten:

    Algeirs overcast 11 93% E 5 1028 rising

    Listing 4.3: Ausschnitt aus der Beispieldatei

  • Sandini Bib

    .NETEssentials

    41

    XML-Dokumente laden und lesen

    Um das -Element aus der ersten Stationsmeldung zu lesen, mussder zweite Kindknoten des Dokumentenknotens gelesen werden (dererste wre die Verarbeitungsanweisung ), davonden ersten Kindknoten (das Element ) und davon wiederumden dritten Knoten. Hier der entsprechende Codeausschnitt dazu:

    static void SampleChildNodes(){ XmlNode node;

    // erzeugen eines neuen XML-Dokumentes XmlDocument thedoc = new XmlDocument();

    // laden einer bestehenden Datei thedoc.Load(@"h:\wetter.xml");

    // das element holen node = thedoc.ChildNodes[1];

    // das element holen node = node.ChildNodes[0].ChildNodes[2];

    // inhalt ausgeben Console.WriteLine("Inhalt: {0}", node.OuterXml);}

    Listing 4.4: Zugriff auf einen bestimmten Elementknoten per DOM

    OuterXmlDie Ausgabe erfolgt dann ber die Eigenschaft OuterXml, so dass das Tagund die Attribute mit ausgegeben werden. Sind Sie nur am reinenInhalt interessiert, knnen Sie statt dessen die Eigenschaft InnerTextverwenden.

    Sollte Ihnen der Programmablauf mehr wie ein Hpfen von Knoten zuKnoten vorkommen, bei dem sich die Reihenfolge der Elemente aufkeinen Fall ndern darf, liegen Sie richtig. Im nchsten Kapitel werdenSie mit XPath-Abfragen eine wesentlich bessere Mglichkeit kennenler-nen, ein Set aus einzelnen Knoten aus einem Dokumentenbaum zuextrahieren.

    Abbildung 4.1: Die Ausgabe des Beispielprogramms

  • Sandini Bib

    .NETEssentials

    42

    4 Document Object Model

    Auswhlen einzelner Elemente

    XmlNodelist Die Auswahl einzelner Knoten oder einer Liste von Knoten geschiehtber verschiedene Methoden, die eine Instanz von XmlNode (bzw. einerAbleitung davon) oder eine Auflistung in einer XmlNodeList liefern.Damit lsst sich die Baumstruktur bequem durchsuchen und filtern.

    Das folgende Beispiel liefert alle location-Elemente der Datei und gibtdiese Auflistung in einer Schleife aus, um aufzulisten, fr welche Stati-onen Wetterdaten vorliegen.

    using System;using System.XML;

    namespace DOMSamples{ class ReadXML { static void Main(string[] args) { // erzeugen eines neuen XML-Dokumentes XmlDocument thedoc = new XmlDocument();

    // laden einer bestehenden Datei thedoc.Load(@"h:\wetter.xml");

    // auslesen aller location-tags XmlNodeList nl = thedoc.GetElementsByTagName("location");

    // auflistung in schleife ausgeben foreach(XmlNode node in nl) { Console.WriteLine("Station location: {0}", node.InnerText); } Console.WriteLine("Total # of stations: {0}", nl.Count); } }}

    Listing 4.5: Auslesen aller benannten Tags eines XML-Dokumentes

    GetElementsByID Zustzlich existiert noch eine Methode GetElementsByID, mit der alle Ele-mente mit einem bestimmten ID-Attribut zurckgeliefert werden.Dafr muss allerdings ein Schema oder eine DTD zur Validierung vor-handen sein, da in .NET im Document Object Model keine ID-Attributevorgesehen sind, wenn diese nicht explizit ber eine DTD oder ein

  • Sandini Bib

    .NETEssentials

    43

    XML-Dokumente laden und lesen

    Schema definiert werden. Mehr dazu im Kapitel ber die Validierungvon XML-Dokumenten.

    Zugriff auf Attribute

    Attributes und XmlAttribute Collection

    Fr den Zugriff auf eventuell vorhandene Attribute eines Elementesbenutzen Sie zuerst die Eigenschaft Count der Auflistung Attributes desKnotens, um zu testen, ob diese einen Wert grer als 0 enthlt.

    Ist dies der Fall, liefert die Auflistung Attributes eine XmlAttributeCollection, deren Elemente aus XmlNodes bestehen. Damit lassen sichdie einzelnen Unterelemente eines Knotens bequem nach vorhandenenAttributen durchsuchen, wie das nchste Beispiel zeigt. Hier wird frdas erste station-Element in der Beispieldatei jeweils ausgegeben, obAttribute vorhanden sind, und deren Namen und Wert. Auch hier wirdaus Platzgrnden wieder nur der Code fr die Klasse aufgelistet, derAufruf in einer Testklasse sollte aber kein Problem darstellen.

    // ausgabe von attributen aus xml-elementen

    static void SampleAttributes(){ XmlNode node;

    // erzeugen eines neuen XML-dokumentes XmlDocument thedoc = new XmlDocument();

    // laden einer bestehenden datei thedoc.Load(@"h:\wetter.xml");

    // das erste element holen node = thedoc.ChildNodes[1].ChildNodes[0];

    // durch alle kindknoten des elementes laufen foreach(XmlNode n in node.ChildNodes) { // haben wir attribute? if(n.Attributes.Count > 0) { // dann durch alle attribute laufen foreach(XmlNode a in n.Attributes) { Console.WriteLine("Element besitzt" + " Attribute:", n.Name); Console.WriteLine(" {0} = {1}", a.Name, a.Value); } } else // keine attribute, elementname ausgeben Console.WriteLine("Element hat keine" +

  • Sandini Bib

    .NETEssentials

    44

    4 Document Object Model

    " Attribute.", n.Name); }}

    Listing 4.6: Ausgabe der Attribute und ihrer Werte

    4.3 ndern von XML-Dokumenten per DOM

    Hinzufgen von neuen Elementen

    Das programmgesteuerte Hinzufgen neuer Elemente (Knoten) in dieDOM-Struktur erlaubt den freien Auf- und Umbau eines XML-Doku-mentes. Fr jeden mglichen Elementtyp existiert in der XmlDocument-Klasse eine eigene Methode, da die Konstruktoren nicht direkt instanti-ierbar sind, da Elemente immer zu einem bestimmten Dokument geh-ren.

    Das Beispiel unten erzeugt zuerst ein neues XML-Dokument und flltdies dann durch die entsprechenden Methoden-Aufrufe mit Inhalten.Zuletzt wird durch das Speichern nach Console.Out der Inhalt im Konso-lenfenster ausgegeben.

    static void SampleNewContent(){ XmlNode node1; XmlNode node2;

    // erzeugen eines neuen XML-Dokumentes XmlDocument thedoc = new XmlDocument();

    // ein kommentarelement erzeugen thedoc.AppendChild(thedoc.CreateComment( "demo fuer .net-essentials"));

    // ein -element erzeugen XmlElement elem = thedoc.CreateElement("weatherdata"); thedoc.AppendChild(elem);

    // ein station-element mit attribut erzeugen node1 = elem.AppendChild(thedoc.CreateElement("station")); (node1 as XmlElement).SetAttribute("id", "Irgendwo");

    // einfuegen von text funktioniert // ueber die Methode "CreateTextNode" node2 = node1.AppendChild(thedoc.CreateElement("weather")); node2.AppendChild(thedoc.CreateTextNode("sunny"));

  • Sandini Bib

    .NETEssentials

    45

    ndern von XML-Dokumenten per DOM

    thedoc.Save(Console.Out);}

    Listing 4.7: Erzeugen von neuen Elementen per DOM

    Hier die Ausgabe der Methode:

    Lschen von Elementen

    RemoveChild, RemoveAllUm ein Element aus der Struktur zu entfernen, existiert die MethodeRemoveChild, die als Parameter den zu entfernenden Unterknoten erwar-tet. Als Erweiterung zum DOM durch Microsoft existiert noch eineMethode RemoveAll, mit der sich in einem Aufruf alle Unterelementeund Attribute eines Knotens entfernen lassen.

    Der Aufruf der Methode SampleDeleteElements aus dem folgenden Bei-spiel entfernt aus allen -Elementen den Unterknoten .

    static void ProcessElementDelete(XmlNode theNode){ foreach(XmlNode n in theNode.ChildNodes) { if(n.HasChildNodes) ProcessElementDelete(n); }

    if(theNode.LocalName == "airtrend") { Console.WriteLine("Deleting a node ...."); theNode.ParentNode.RemoveChild(theNode); }}

    static void SampleDeleteElements(){ // erzeugen eines neuen XML-Dokumentes

    Abbildung 4.2: Die Ausgabe der neu erzeugten XML-Struktur

  • Sandini Bib

    .NETEssentials

    46

    4 Document Object Model

    XmlDocument thedoc = new XmlDocument();

    // laden einer bestehenden Datei thedoc.Load(@"h:\miniwetter.xml");

    // hier erfolgt die bearbeitung ProcessElementDelete(thedoc);

    // genderte datei rausschreiben thedoc.Save("neuwetter.xml");

    }

    Listing 4.8: Entfernen von Elementen aus der DOM-Struktur

    Bearbeiten von Attributen

    CreateAttribute Die Behandlung von Attributen erfolgt auf eine etwas abweichende Artund Weise, da die Methode CreateAttribute ein Mitglied der XmlDocu-ment-Klasse ist. Um also ein neues Attribut zu erzeugen, whrend Sienur auf den aktuellen Knoten Zugriff haben, gehen Sie folgendermaenvor:

    Feststellen des Dokumentes, das diesen Knoten besitzt. Dazu hatjeder Knoten eine Eigenschaft OwnerDocument.

    Aufrufen der Methode CreateAttribute der Dokumentklasse undbergeben von Name und eventuell Namensraumprfixen.

    Setzen des Wertes fr das Attribut.

    Hinzufgen des neuen Attributes an die Attribute-Auflistung desaktuellen Knoten.

    Die beiden nachfolgenden Methoden zeigen einen rekursiven Durch-lauf durch ein XML-Dokument, bei dem fr jeden Stationsknoten derName der Station aus dem Unterknoten gelesen und bei als ID-Attribut eingetragen wird. Danach wird die neueStruktur unter einem anderen Namen gespeichert. Damit die Ausgabeleichter lesbar ist, wird hier eine Datei verwendet, die nur zwei Ein-trge fr Wetterstationen besitzt und die den Namen miniwetter.xmltrgt.

    // diese methode wird fr jeden knoten aufgerufen

    static void ProcessElementChildren(XmlNode theNode) { Console.WriteLine("Processing ....", theNode.Name);

    // id bei station eintragen

  • Sandini Bib

    .NETEssentials

    47

    ndern von XML-Dokumenten per DOM

    if(theNode.LocalName == "location") { // neues attribut ueber dokument erzeugen XmlAttribute attr = theNode.OwnerDocument.CreateAttribute("id"); // attributwert setzen auf den inhalt // des aktuellen knotens (location) attr.Value = theNode.InnerText; // an die auflistung der attribute anhngen theNode.ParentNode.Attributes.Append(attr);

    }

    // alle eventuellen unterknoten abarbeiten foreach(XmlNode n in theNode.ChildNodes) { if(n.HasChildNodes) ProcessElementChildren(n); } }

    // hauptmethode static void SampleRecurseElements() { // erzeugen eines neuen XML-Dokumentes XmlDocument thedoc = new XmlDocument();

    // laden einer bestehenden Datei thedoc.Load(@"h:\miniwetter.xml");

    // hier erfolgt die bearbeitung ProcessElementChildren(thedoc);

    // genderte datei rausschreiben thedoc.Save("neuwetter.xml");

    }

    Listing 4.9: ndern einer DOM-Struktur

    RemoveAttributeSoll ein Attribut eines Elementes gelscht werden, geschieht dies aufsehr einfache Weise durch den Aufruf der Methode RemoveAttribute derKlasse XmlElement, mit der ein benanntes Attribut aus einem XML-Element gelscht werden kann. Da dieser Vorgang nicht sonderlichgeheimnisvoll ist, sei an dieser Stelle auf ein weiteres Listing verzichtet.

    Eine andere Alternative ist die Nutzung der hilfreichen MethodeSetAttribute der Klasse XmlElement. Bitte beachten Sie, dass aus Grnden

  • Sandini Bib

    .NETEssentials

    48

    4 Document Object Model

    des Zeilenumbruchs die beiden Zeilen 05 und 06 getrennt wurden, imCode ist dies eine einzige Zeile.

    01 if(theNode.LocalName == "station")02 {03 XmlElement elem = ((XmlElement)theNode);04 elem.SetAttribute("id", 05 elem.GetElementsByTagName("location") 06 .Item(0).InnerText);07 }

    Listing 4.10: Alternative Erzeugung von Attributen

    Mit dieser Methode lsst sich auch der Inhalt eines bereits bestehendenAttributes wieder ndern.

    4.4 Ereignisbehandlung

    Die Klasse XmlDocument beinhaltet auch eine Reihe von Ereignissen, indie sich Ihr Code mit einer eigenen Ereignisbehandlungsroutine ein-hngen kann. Auf diese Weise kann nicht nur mitverfolgt werden, obein Knoten gendert, eingefgt oder gelscht wurde. ber einen zwei-ten Satz von Ereignissen, der vor der eigentlichen Aktion ausgelstwird, lsst sich die Durchfhrung der nderung sogar bei Bedarfabbrechen.

    Um auf eines dieser Ereignisse zu reagieren, muss in der Klasse einEventHandler programmiert und dem Delegate fr das Ereignis mitge-teilt werden. Das folgende Listing zeigt eine Klasse, die beim Lscheneines Knotens eine entsprechende Meldung ausgibt.

    // klasse zur ereignisbehandlung

    class EventDemo

    t Ereignis BeschreibungNodeChanged Tritt auf, wenn ein Knoten in der DOM-Struktur gendert wurdeNodeChanging Tritt auf, bevor ein Knoten in der DOM-Struktur gendert wird

    (Auslsen einer Exception bricht die Aktion ab)

    NodeInserted Tritt auf, wenn ein Knoten in der DOM-Struktur eingefgt wurde

    NodeInserting Tritt auf, bevor ein Knoten in der DOM-Struktur eingefgt wird (Auslsen einer Exception bricht die Aktion ab)

    NodeRemoved Tritt auf, wenn ein Knoten in der DOM-Struktur gelscht wurde

    NodeRemoving Tritt auf, bevor ein Knoten in der DOM-Struktur gelscht wird (Auslsen einer Exception bricht die Aktion ab)

    Tabelle 4.1: Mgliche Ereignisse der XmlDocument-Klasse

  • Sandini Bib

    .NETEssentials

    49

    Ereignisbehandlung

    { public void DemoActions() { XmlDocument thedoc = new XmlDocument();

    thedoc.NodeRemoved += new XmlNodeChangedEventHandler(this.OnDelete);

    thedoc.Load(@"h:\miniwetter.xml");

    try { thedoc.ChildNodes[1].ChildNodes[0].RemoveAll(); } catch (Exception e) { Console.WriteLine(e.Message); }

    thedoc.Save(Console.Out);

    Console.Write("Press a key ...."); Console.ReadLine(); }

    // knoten wurde gelscht public void OnDelete(Object src, XmlNodeChangedEventArgs args) { Console.Write("Lschereginis: {1}", args.Node.Name, args.Action.ToString());

    if (args.Node.Value != null) Console.WriteLine(" Wert = {0}", args.Node.Value); else Console.WriteLine(""); }

    }

    Listing 4.11: Abfangen von Lschereignissen im Dokument

    NodeChanged, NodeInserted

    Analog dazu funktioniert die Behandlung der NodeChanged- und NodeInserted-Ereignisse. Interessant ist aber die Mglichkeit, in diesen Pro-zess einzugreifen und bei Bedarf durch das Auslsen einer Exceptiondie Aktion abzubrechen. Dazu dienen die Ereignisse, deren Namenjeweils auf ...ing enden und die vielleicht besser als Anforderungbezeichnet werden.

  • Sandini Bib

    .NETEssentials

    50

    4 Document Object Model

    Im folgenden Beispiel soll verhindert werden, dass fr eine Station der-Knoten gelscht wird, alle anderen Unterknoten von sollen gelscht werden knnen.

    Denken Sie daran, beim Lschen von Unterelementen in einer Schleifenicht mit foreach zu arbeiten, da hier das Set der zu durchlaufendenElemente nur einmal berechnet wird und dann nicht mehr gendertwerden darf. Zustzlich muss die Schleife von hinten nach vornedurchlaufen werden, damit nach dem Lschen wegfallende Elementedie Reihenfolge nicht ducheinander bringen. Deshalb die auf den ers-ten Blick etwas merkwrdig aussehende Schleifenkonstruktion. WollenSie in einem Rutsch wirklich alle Unterknoten eines Knotens entfernen,benutzen Sie dazu am besten die Methode RemoveAll der Klasse XmlNode.Diese stellt eine ntzliche Erweiterung des DOM-Standards durchMicrosoft dar.

    // beispiel zum abfangen einer lschaktion im DOM

    class EventDemo{ public void DemoActions() { XmlNode node;

    XmlDocument thedoc = new XmlDocument();

    // eintragen der eventhandler thedoc.NodeRemoved += new XmlNodeChangedEventHandler(this.OnDelete); thedoc.NodeRemoving += new XmlNodeChangedEventHandler(this.OnDeleteReq);

    thedoc.Load(@"h:\miniwetter.xml");

    // die erste station in der wetterdatei node = thedoc.ChildNodes[1].ChildNodes[0];

    // alle unterelemente lschen for(int i = node.ChildNodes.Count-1; i >= 0; i--) { try { node.RemoveChild(node.ChildNodes[i]); } catch (Exception e) { Console.WriteLine(e.Message); } }

  • Sandini Bib

    .NETEssentials

    51

    Ereignisbehandlung

    // den inhalt der XML-Strukur zur // kontrolle ausgeben thedoc.Save(Console.Out);

    Console.Write("Press a key ...."); Console.ReadLine(); }

    // ab hier die ereignisbehandlungsroutinen

    // knoten wurde gelscht public void OnDelete(Object src, XmlNodeChangedEventArgs args) { Console.Write("Lschereignis: {1}", args.Node.Name, args.Action.ToString()); if (args.Node.Value != null) Console.WriteLine(" Wert = {0}", args.Node.Value); else Console.WriteLine(""); }

    // knoten soll gelscht werden, extracheck public void OnDeleteReq(Object src, XmlNodeChangedEventArgs args) { Console.Write("Lschanfrage: {1}", args.Node.Name, args.Action.ToString()); if (args.Node.Value != null) Console.WriteLine(" Wert = {0}", args.Node.Value); else Console.WriteLine("");

    if(args.Node.LocalName == "location") { throw new XmlException("Location darf nicht " + "gelscht werden!", null); } }}

    Listing 4.12: Abbrechen von nderungen im DOM

    Nach der Exception befindet sich die XML-Struktur in der XmlDocument-Instanz in einem stabilen Zustand wie vor der Aktion. Wre im Codestatt der Schleife durch die Unterelemente die Methode RemoveAll aufge-rufen worden, htte die Exception beim Element dafrgesorgt, dass gar keines der Unterelemente gelscht worden wre, da

  • Sandini Bib

    .NETEssentials

    52

    4 Document Object Model

    dann der komplette Aufruf von RemoveAll zurckgerollt worden wre.Dies lsst sich bei Bedarf gezielt dafr einsetzen, komplette Knoten zuschtzen, aber nur ein Unterelement zu prfen.

    4.5 Zusammenfassung

    In diesem Kapitel haben Sie eine bersicht ber die verschiedenenKlassen und Methoden des DOM im .NET-Framework erhalten. Ver-gleicht man die Anforderungen und Mglichkeiten mit denen im Kapi-tel ber die Streaming-Klassen XmlReader und XmlWriter, dann lsst sichauch einordnen, wann am besten welche Methode zum Einsatz kommt.

    Sollten Sie eine groe Anzahl von Dokumenten in einer Art Stapelbe-trieb verarbeiten mssen oder bentigen Sie aus einem umfangreichenXML-Dokument nur eine kleine Anzahl von Elementen (z.B. um auseiner Liste von Teilen die Gewichte fr den Versand zu berechnen),dann ist der Streaming-Ansatz wesentlich ressourcenschonender.

    Sollten Sie aber die volle Kontrolle ber die XML-Struktur bentigenoder beim Aufbau im Speicher noch nicht die endgltige Reihenfolgeder Elemente wissen (weil diese z.B. erst whrend der Laufzeit IhresProgramms erzeugt werden), dann ist es besser, mit dem DOM zuarbeiten, auch wenn dadurch der komplette DOM-Baum im Speicheraufgebaut wird.

  • Sandini Bib

    .NETEssentials

    53

    5 XPath-Abfragen

    5.1 Warum XPath?

    Wie Sie in den vorherigen Kapiteln erfahren haben, bietet das .NET-Framework eine ganze Reihe von Mglichkeiten, um XML-Strukturenzu lesen und zu schreiben. Allerdings ist der Weg zu einem bestimmtenKnoten bzw. Element mehr oder weniger steinig. Das reine Abzhlenvon Unterknoten funktioniert beispielsweise nur dann, wenn Sie sichsicher sind, dass die Reihenfolge der Knoten nicht verndert wurde.Wie Sie dies sicherstellen und auch bestimmte Elemente zwingenderforderlich machen, erfahren Sie im Kapitel ber die Validierung vonXML-Dateien.

    Das Prinzip von XPathHier soll es aber zuerst darum gehen, eine sehr mchtige und flexibleMglichkeit zur Suche nach einem oder mehreren Knoten in einer DOM-Struktur vorzustellen, nmlich den XPath-Standard. XPath ist eine Ent-wicklung des World Wide Web Consortiums (W3C) zur Lokalisierungvon Knoten in XML-Strukturen, die normalerweise nicht allein genutztwird, sondern dazu dient, zusammen mit anderen Standards benutzt zuwerden. So bestehen zum Beispiel die Suchausdrcke der Schablonenfr die Transformation von XML aus XPath-Ausdrcken. XPath operiertauf der abstrakten, logischen Struktur eines XML-Dokuments, nicht aufseiner uerlichen Syntax. Seinen Namen erhlt XPath durch die Ver-wendung einer auch in URLs genutzten Pfad-Notation (path), mit dersich durch die hierarchische Struktur eines XML-Dokuments navigierenlsst. Fr eine erfolgreiche Arbeit mit XML ist daher eine eingehendeBeschftigung mit XPath unabdingbar. Dieses Kapitel kann aus Platz-grnden nur eine kurze Einfhrung bieten, fr die detailliertere Beschf-tigung sei auf die Homepage fr XPath unter http://www.w3.org/TR/xpath.html verwiesen.

    5.2 Grundlagen

    XPath-Ausdrcke

    In der einfachsten Form beschreibt eine XPath-Abfrage den durchSchrgstriche getrennten Weg in der hierarchischen XML-Struktur biszum Zielknoten.

    So liefert der XPath-Ausdruck weatherdata/station/temp alle Knotenunterhalb von , wobei dieses Element ein Unterknoten von sein muss.

  • Sandini Bib

    .NETEssentials

    54

    5 XPath-Abfragen

    Die folgende Abbildung zeigt die Ausgabe, wenn fr jeden Knoten dieEigenschaft OuterXml ausgegeben wird.

    Der |-Operator XPath-Ausdrcke lassen sich mit Hilfe des Operators "|" (in der Bedeu-tung von oder) verbinden. So liefert der Ausdruck /weatherdata/sta-tion/location | /weatherdata/station/temp beispielsweise einen Match frentweder das - oder das -Element. Da der XPath-Parserzuerst die Geschwisterknoten der gleichen Ebene durchsucht, erhaltenSie so auf einfachste Art eine Auflistung der Standorte mit der jeweili-gen Temperatur. Hier das Listing und die Ausgabe des Programmsdazu:

    // kombinieren von XPath-Abfragen

    static void SampleSelectOr(){ // erzeugen eines neuen XML-Dokumentes XmlDocument thedoc = new XmlDocument();

    // laden der xml-datei thedoc.Load(@"h:\miniwetter.xml");

    // abfragen per XPath XmlNodeList nl = thedoc.SelectNodes( "/weatherdata/station/location | " + /weatherdata/station/temp");

    foreach(XmlNode n in nl) { Console.WriteLine(n.OuterXml); }

    }

    Listing 5.1: Kombination zweiter XPath-Ausdrcke

    Abbildung 5.1: Ausgabe aller -Knoten im XML-Baum

  • Sandini Bib

    .NETEssentials

    55

    Grundlagen

    Der Kontextknoten

    Die Abkrzung frden Kontextknoten istder . (punkt)

    Wird eine XPath-Abfrage beispielsweise nach dem Knoten durchgefhrt (name), hngt es davon ab, von wo die Suche gestartetwird. Ein Beginn an der Wurzel des Dokumentes liefert unter Umstn-den ein komplett anderes Ergebnis als der Beginn an einem Unterkno-ten innerhalb der XML-Struktur. Daher verwendet XPath das Konzepteines sogenannten Kontextknotens. Dieser Kontextknoten ist deraktuelle Knoten, an dem die Suche gestartet wird (bei der Verwendungder Methode SelectNodes beispielsweise der XmlNode, fr den dieMethode aufgerufen wird).

    Achsen

    Fr die Durchfhrung einer XPath-Abfrage kann eine bestimmte Rich-tung definiert werden, die sog. Achse. Auch in einem hierarchischenDateisystem beispielsweise kann ber die Notation .. eine Ebene hhergewechselt werden, um nach oben zu suchen.

    Bei der normalen Angabe wie /weatherdata/station/location ist die Achseimmer child, also jeweils ein Unterknoten. Dies ist die Default-Achse,muss daher auch nicht angegeben werden. Wird hingegen eine Achseangegen, trennt man diese vom Rest der Abfrage durch einen doppel-ten Doppelpunkt (::). Einige Achsen werden (wie child) sehr hufigbentigt und besitzen eine eigene Abkrzung. Die wichtigsten Achsenzeigt die nachfolgende Tabelle. Startpunkt ist immer der Kontextkno-ten.

    Abbildung 5.2: Ausgabe der kombinierten XPath-Abfrage

    tAchse Bedeutungchild Default, ein Nachkomme des Kontextknotensself Der Kontextknoten (Abkrzung .)

    descendant Irgendein Nachkomme des Kontextknotens, also z.B. auch ein Nachkomme ber zwei oder drei Ebenen

    descedant-or-self Wie oben, allerdings unter Einbeziehung des Kontextkno-tens (Abkrzung //)

    parent Elternknoten des Kontextknotens (Abkrzung ..)

    Tabelle 5.1: Die wichtigsten Achsen fr XPath-Ausdrcke

  • Sandini Bib

    .NETEssentials

    56

    5 XPath-Abfragen

    Eine vollstndige Liste der mglichen Achsen finden Sie auf der XPath-Homepage im Web unter dem URL www.w3.org/TR/xpath.html .

    Verweis aufElternknoten mit ..

    Um beispielsweise alle -Elemente zu selektieren, egal zu welchemElternknoten diese gehren, kann der Ausdruck //temp benutzt werden.Der Ausdruck //location/.. liefert alle Elternknoten (in diesem Falle), die ein -Element als Kindknoten besitzen.

    Somit sind sehr leicht Abfragen in verschiedenen Richtungen mg-lich, die durch die Auswahl des Kontextknotens noch zustzlich beein-flusst werden knnen. Fr eine noch leichtere Abfrage fehlen jetzt nurnoch Mglichkeiten, einen Vergleich durchzufhren, um nur einbestimmtes Subset von passenden Knoten auszuwhlen. Dies geschiehtbei XPath mit Hilfe von so genannten Prdikaten.

    Prdikate

    Prdikate entsprechen in etwa der WHERE-Klausel bei einer SQL-Abfrage,da sie das zurckgelieferte Set von Knoten durch Bedingungen nochweiter filtern knnen. Diese Prdikate werden an der gewnschtenStelle hinter das jeweilige Hierarchieelement in eckigen Klammernangefgt. Klingt kompliziert, ist es aber nicht. Hier ein Beispiel:

    //station[location = "Athens"]

    liefert das -Element, welches ein Unterlement besitzt, das den Inhalt Athens besitzt.

    Prfung aufvorhandene Attribute

    Der Prdikatwert muss nicht unbedingt einen Vergleich enthalten. Wirdnur ein Unterelement oder ein Attribut angegeben, dann wird auf dasVorhandensein dieses Elementes geprft. Der nachfolgende Ausdruckliefert in der XmlNodeList alle -Knoten, die als Elternknoten ein-Element besitzen, das wiederum ein Attribut "status" enthlt.

    /weatherdata/station[@status]/location

    Wird mehr als ein Prdikat angegeben, was durchaus zulssig ist,besitzt die Reihenfolge dieser Prdikate eine entscheidende Bedeutung.Betrachten wir dazu die beiden folgenden XPath-Ausdrcke:

    1. /weatherdata/station[2][@status]

    2. /weatherdata/station[@status][2]

    following Alle nach dem Kontextknoten folgenden Knoten

    preceding Alle vor dem Kontextknoten vorhandenen Knoten

    attribute Attribut des angegebenen Knotens (Abkrzung @)

    Achse Bedeutung

    Tabelle 5.1: Die wichtigsten Achsen fr XPath-Ausdrcke (Fortsetzung)

  • Sandini Bib

    .NETEssentials

    57

    Grundlagen

    Fr den Ausdruck Nr. 1 ist das Ergebnis der zweite -Knotenunterhalb von , falls dieser ber ein Attribut (wie Sie ander Abkrzung @ fr die Attribut-Achse sehen) mit dem Namen statusverfgt. Die Knotenliste wre hier leer, da der zweite Knoten in unsererBeispieldatei wetter.xml (fr die Station in Amsterdam) nicht ber dasentsprechende Attribut verfgt.

    Der Ausdruck Nr. 2 liefert dagegen zuerst die Liste der Stationen miteinem Attribut status und whlt anschlieend davon den zweiten Kno-ten aus. Im Falle der Beispieldatei enthlt die Ergebnismenge eine Aus-gabe:

    Bukarest light rain 10 49% W 3 1013 raising

    Listing 5.2: Die Ergebnismenge der zweiten Abfrage

    Prdikat-OperatorenZur Kombination von Ausdrcken innerhalb der Prdikate knnen Siemit den drei booleschen Operatoren and, or und not arbeiten (case-sensi-tive) bzw. Teilausdrcke in Klammern gruppieren. Denken Sie bei denrelationalen Operatoren daran, das Zeichen "" ent-sprechend durch ein ">" zu quoten, schlielich befinden wir unsinnerhalb der XML-Grenzen. Mehr dazu und zu den weiteren Mglich-keiten der Prdikate finden Sie in der Online-Dokumentation von .NEToder auf den Webseiten des W3C.

    Als letzten Bestandteil der Einfhrung in die XPath-Sprache fehlen nunnur noch die Funktionen, mit deren Hilfe noch flexiblere Abfragenmglich sind.

    Funktionen

    FunktionstypenFunktionen innerhalb von XPath-Ausdrcken knnen einen der vierfolgenden Datentypen zurckliefern: Boolsche Werte (true oder false),Zahlenwerte, Zeichenketten oder eine Knotenmenge. Wenn eine Funk-tion einen anderen Datentyp als eine Knotenmenge liefert, knnennatrlich die nachfolgend besprochenen Methoden SelectNodes undSelectSingleNode nicht benutzt werden. Verwenden Sie dafr die Metho-den des XPathNavigators, der weiter unten vorgestellt wird.

  • Sandini Bib

    .NETEssentials

    58

    5 XPath-Abfragen

    Mit Hilfe dieser Funktionen ist es sehr einfach mglich, Code zu ver-meiden und die Arbeit einfach in einen XPath-Ausdruck auszulagern.Damit Sie die folgenden Beispiele nachvollziehen knnen, sollten Siezuerst die Abschnitte ber SelectNodes und den XPathNavigator lesenund dann hierher zurckblttern. Aus der Sicht des Autors erschien esan dieser Stelle sinnvoller, die XPath-Einfhrung nicht zu zerreien,sondern linear aufzubauen.

    Sobald eine Funktion kein Set von Knoten mehr liefert, sind die bli-chen Selektierungsmethoden (wie SelectNodes oder Select) nicht mehranwendbar. Benutzen Sie statt dessen die Methode Evaluate der KlasseXPathNavigator, welche als Rckgabetyp object besitzt und dementspre-chend per Unboxing oder Konvertierung gewandelt werden kann.

    Evaluate-Funktion Eine der einfachsten Funktionen ist count(), die einfach dieAnzahl der auf den Ausdruck passenden Knoten liefert.Damit lsst sich die Anzahl der in der Beispieldatei enthaltenenen Sta-tionsmeldungen mit einer einzigen Zeile Code bestimmen.

    int nCount = (int)xnav.Evaluate("count(//station)");

    Listing 5.3: Zhlen von Knoten mit XPath-Funktionen

    Es existiert eine recht beachtliche Liste von ntzlichen Funktionen,wobei sich Microsoft hier an den XPath-Standard hlt. Anstatt dieseListe einfach zu wiederholen, sei auf die Online-Hilfe von Visual Stu-dio.NET verwiesen, in der Sie unter dem Indexbegriff XPath, Funktio-nen die entsprechende Liste finden. Nachfolgend noch einige Beispiele,die ein paar der untersttzten Funktionen demonstrieren:

    Ausgabe aller Temperaturknoten, aber nur der Textinhalt des Elements:

    /weatherdata/station/temp/text()

    Ausgabe aller Stationen mit "P":

    /weatherdata/station[ starts-with(location,"P")]/location

    Ausgabe der Luftfeuchtigkeit fr alle Stationen, die eine Temperaturvon mehr als 10 melden:

    /weatherdata/station/temp[text() > 10]/../humidity

    Alle Stationsdaten mit steigendem Luftdruck und mehr als 10:

    /weatherdata/station[(temp > 10) and (airtrend = "rising")]

    t

  • Sandini Bib

    .NETEssentials

    59

    SelectNodes und SelectSingleNode

    5.3 SelectNodes und SelectSingleNode

    SelectNodesMit der Methode SelectNodes lsst sich eine geladene DOM-Struktur mitHilfe einer XPath-Abfrage durchsuchen und als XmlNodelist-Auflistungzurckgeben.

    Das folgende Beispiel liefert alle -Elemente unterhalb von/weatherdata/station und berechnet anschlieend die Durchschnittstem-peratur der Wettermeldungen.

    static void SampleSelectNodes(){ double sum = 0.0; int count = 0;

    // erzeugen eines neuen XML-Dokumentes XmlDocument thedoc = new XmlDocument();

    // laden der xml-datei thedoc.Load(@"h:\wetter.xml");

    // abfragen per XPath XmlNodeList nl = thedoc.SelectNodes("/weatherdata/station/temp");

    // durchlaufen der nodelist foreach(XmlNode n in nl) { sum += double.Parse(n.InnerText); count++; }

    Console.WriteLine("{0} Werte. Schnitt = {1:F2} Grad", count, sum / count); }

    Listing 5.4: Auslesen von Knoten mit XPath-Abfragen

    Damit ist auf einfache Art und Weise nahezu ohne Programmierauf-wand das Durchsuchen von XML-Strukturen nach bestimmten Kritie-rien mglich.

    SelectSingleNodeSoll ein ganz bestimmter Knoten (z.B. anhand einer ID) gefunden wer-den, kann dazu die Methode SelectSingleNode benutzt werden. So las-sen sich mit der folgende Klasse die kompletten XML-Elemente freinen Standort (also das -Element) abrufen, in dem der Namedes Standortes eingegeben wird. Wird kein passender Knoten gefun-den, liefert die Methode eine Null-Referenz, auf die gestestet werdenkann.

  • Sandini Bib

    .NETEssentials

    60

    5 XPath-Abfragen

    Im Beispiel wird ber ein XPath-Prdikat (s.o. bei den Grundlagen) derName des Standortes gesucht, aber das -Element zurckgelie-fert.

    // suchen eines einzelnen xml-nodes // per SelectSingleNode

    static void SampleSelectSingleNode(){ string location; // der gesuchte name string xpath; // der XPath-Ausdruck

    // erzeugen eines neuen XML-Dokumentes XmlDocument thedoc = new XmlDocument();

    // laden der x