Programmieren von XML mit Visual Basic .NET

Werbung
677.book Page 451 Thursday, December 5, 2002 2:26 PM
Programmieren von XML
mit Visual Basic .NET
452
459
462
471
479
495
Web-Releases von SQL Server
Überblick über XML-Technologien
Generieren von XML-Dokumenten mit dem .NET Framework
Dynamische Angabe von XML-Resultsets
Das Zusammenspiel von XML und DataSets
Erstellen von HTML-Seiten mit XSLT
Das Hauptziel dieses Kapitel ist es, ein Verständnis für die Verwendung von XML-Dokumenten in
Visual Basic .NET zu vermitteln. Dieses Kapitel setzt grundlegende Kenntnisse zu den XML-Datenformaten, -Schemas und den dazugehörigen Technologien, wie XPath (XML Path Language) und
XSLT (Extensible Stylesheet Language Transformation), voraus. Wenn Sie grundlegende Fragen zu
diesen Themen haben, wäre nun die Zeit, zu Kapitel 6 zurückzukehren. Dieses Kapitel umfasst
Abhandlungen zur Formatierung von XML-Dokumenten, sowie Beispiele, die die Verwendung von
XML-Dokumenten in Webanwendungen verdeutlichen, als auch Referenzen für das weiterführende
Studium.
Der erste Schwerpunkt in diesem Kapitel dreht sich um Erläuterungen zu XML. Der zweite Hauptschwerpunkt liegt insbesondere auf der Betonung der Verwendung von XML mit SQL Server 2000Datenbanken. Zwar werden einige Techniken in diesem Kapitel demonstriert, die auch in Verbindung mit anderen Datenbankquellen verwendet werden können, insbesondere solchen, die sich auf
ADO.NET-Datasets stützen, doch wurden die Beispiele nur für den Einsatz mit SQL Server 2000
getestet und evaluiert. Der dritte, dieses Kapitel charakterisierende Schwerpunkt dreht sich um die
Web-Releases von SQL Server 2000. Das Kapitel 6 behandelt die Web-Releases 1 und 2. Dieses
Kapitel rückt nun das Web-Release 3 (SQLXML 3.0) relativ zu den beiden früheren Versionen ins
richtige Licht. Darüber hinaus werde ich auf zwei Innovationen näher eingehen (SQLXML-verwaltete Klassen und Diffgramme), die mit Web-Release 2 vorgestellt wurden und die für .NET-Entwickler
von besonderer Bedeutung sind. Es ist Microsofts erklärte Zielstellung, SQL Server 2000 durch eine
Reihe von Web-Releases auf dem Stand der neuesten XML-Entwicklungen zu halten. Die mit den
Web-Releases vorgestellten Innovationen beeinflussen wesentlich Ihre Fähigkeiten, um Visual Basic
.NET zur Verarbeitung von SQL Server-Datenquellen mit XML zu verwenden.
Nach einer Einführung zu den Web-Releases und den XML-Technologien aus dem .NET Framework
präsentiert dieses Kapitel eine Reihe von Beispielen in vier Abschnitten. Die erste Gruppe von Beispielen dreht sich um die Erstellung von XML-Dokumenten mit SQL-Abfragen und kommentierten
XML-Schemata. Der zweite Satz von Beispielen erweitert die verfügbare Funktionalität, um Eingaben zur Laufzeit zu unterstützen. Darüber hinaus demonstriert dieser zweite Abschnitt den Einsatz
451
677.book Page 452 Thursday, December 5, 2002 2:26 PM
von XPath-Abfragen, um XML-Dokumente zurückzugeben, und vermittelt alternative Möglichkeiten, um äquivalente Ergebnisse mit SQL-Abfragen zurückzugeben. Der dritte Abschnitt untersucht
insbesondere das Zusammenspiel zwischen ADO.NET-Datasets und XML-Dokumenten. Dieser
Abschnitt untersucht außerdem Möglichkeiten zur Ausführung erweiterter XPath-Abfragen. Zwei
Beispiele aus diesem Abschnitt demonstrieren, wie XML-Dokumente mit hierarchischen DataSets
verarbeitet und wie Änderungen an einer Remotedatenbank von SQL Server vorgenommen werden.
Der abschließende Abschnitt dieses Kapitels behandelt dann die Verwendung von XSLT, um Webseiten mit HTML-Tabellen auf der Grundlage von XML-Dokumenten vorzubereiten, die Sie mit Visual
Basic .NET für eine SQL Server-Datenquelle erstellen können.
Sämtliche Beispiele aus diesem Kapitel, mit Ausnahme eines einzigen Beispiels, sind in Module1 aus
dem XMLSamples-Projekt zu finden. Diese Beispiele demonstrieren Visual Basic .NET-Code für die
Verwaltung von XML-Dokumenten bei der Arbeit mit SQL Server-Datenquellen. Lesen Sie weitere
Kapitel für eine allgemeinere Abhandlung der Programmierung mit Visual Basic .NET (beispielsweise
werden Windows Forms und Steuerelemente in Kapitel 9 behandelt). Sie können die Beispiele zu
diesem Kapitel ausführen, wenn Sie die Kommentarzeichen von den Zeilen aus der Prozedur main
entfernen, die die jeweiligen Prozeduren aufrufen. In einigen Fällen müssen Sie das Kommentarzeichen von mehr als einer Zeile entfernen. In den Beschreibungen der Beispiele werden die Zeilen
explizit angegeben, deren Kommentarzeichen entfernt werden müssen. Das einzige Beispiel, das sich
nicht im XMLSamples-Projektordner befindet, trägt den Namen XMLWebSample. Dieses ASP.NETProjekt umfasst zwei Ordner. Der eine Ordner ist für das Verzeichnis \WWWRoot unter \Inetpub auf
Ihrem Webserver bestimmt, das andere Verzeichnis gehört in das Verzeichnis, in dem Sie Ihre Visual
Basic .NET-Projektordner ablegen. Beide Ordner dieses ASP.NET-Projektes tragen den Namen
XMLWebSample.
Web-Releases von SQL Server
Wenn Sie XML mit SQL Server 2000 verwenden wollen, sollten Sie definitiv das aktuellste WebRelease in Erwägung ziehen. Zum Zeitpunkt der Erstellung dieses Kapitels handelte es sich dabei um
das Web-Release 3. Microsoft unterstützt weiterhin alle Web-Releases in vollem Umfang. Dieser
Abschnitt baut auf den früheren Abhandlungen zu den Web-Releases und den allgemeinen XMLFähigkeiten von SQL Server 2000 auf (siehe Kapitel 6). Darüber hinaus stellt dieser Abschnitt
Web-Release 3 vor, welches in Kapitel 6 nicht behandelt wurde. In diesem Abschnitt werde ich
außerdem zwei wichtige XML-Technologien für die .NET-Entwicklung (SQLXML-verwaltete Klassen
und Diffgramme) präsentieren, die im Lieferumfang von Web-Release 2 enthalten sind, aber bisher in
diesem Buch noch nicht behandelt wurden.
Überblick über das erste und zweite Web-Release
Lesen Sie Kapitel 6 für eine genaue Abhandlung zum ersten und zweiten Web-Release für SQL
Server 2000. Das erste Web-Release für SQL Server 2000, welches am 15. Februar 2001 freigegeben
wurde, stellte zum ersten Mal Updategramme vor. Diese XML-basierte Technologie gibt Entwicklern
die Möglichkeit, SQL Server-Datenbanken mittels HTTP über Webverbindungen programmatisch zu
verarbeiten. Die Datenverarbeitung ist zwar über Webverbindungen möglich, diese Fähigkeit ist allerdings von Standardsicherheitsregeln abhängig. Darüber hinaus stellte Web-Release 1 eine Möglichkeit für die Übernahme von XML-Dokumenten in eine SQL Server-Datenbank en gros vor.
Web-Release 2 (SQLXML 2.0) wurde am 15. Oktober 2001 vorgestellt. Dieses Update für SQL Server
2000 brachte weitere allgemeine XML-Features, wie die clientseitige Formatierung, sowie eine Reihe
452
Kapitel 12
677.book Page 453 Thursday, December 5, 2002 2:26 PM
von Fähigkeiten, die explizit auf .NET-Entwickler ausgerichtet sind – SQLXML-verwaltete Klassen
und Diffgramme. Mit SQLXML-verwalteten Klassen können die Entwickler die Vorteile der WebReleases direkt in der .NET-Umgebung nutzen. Sie können diese Klassen statt der entsprechenden
ADO.NET-Klassen verwenden. Um ein Beispiel zu geben, Sie können statt der SqlDataAdapterKlasse von ADO.NET die SqlXMLAdapter-Klasse von SQLXML einsetzen. Zusätzlich zur größeren
Leistungsvielfalt ist die Syntax von SQLXML-verwalteten Klassen leichter beherrschbar. Das zweite
neue Feature von besonderem Gewicht für .NET-Entwickler sind Diffgramme. Diese Art von XMLDokumenten ermöglicht die Aktualisierung von SQL Server-Datenbanken direkt aus dem .NET Framework heraus. In Kapitel 6 finden Sie eine Abhandlung aller Erweiterungen, die mit Web-Release
2 vorgestellt wurden.
Überblick über Web-Release 3 (SQLXML 3.0)
Web-Release 3 ist Bestandteil des Microsoft SQL Server 2000 Web Services Toolkit. Web-Release 3 ist
als eigenständiges Produkt seit dem 9. Februar 2002 verfügbar. Das Toolkit wurde etwas später (14.
Februar 2002) freigegeben. Das wichtigste Feature des Microsoft SQL Server 2000 Web Services Toolkits ist dessen Fähigkeit, gespeicherte Prozeduren von SQL Server als XML-Webdienste bereitzustellen. In Kapitel 13 wird auf diesen Aspekt des Toolkits genauer eingegangen, denn dieses Kapitel
behandelt die Programmierung von XML-Webdiensten. Es gibt zwei URLs zum Herunterladen von
Web-Release 3. Wenn Sie die Hauptfunktionen des Web-Releases 3 benötigen, ohne die speziellen
Features, die mit dem Microsoft SQL Server 2000 Web Services Toolkit vorgestellt wurden, können
Sie das Web-Release mit folgendem URL herunterladen: http://msdn.microsoft.com/downloads/
default.asp?URL=/downloads/sample.asp?url=/MSDN-FILES/027/001/824/msdncompositedoc.xml.
Wenn Sie alle Features des Toolkits benötigen, können Sie auf die Webseite mit folgendem URL
zugreifen. Diese Site stellt eine viel größere Datei für den Download bereit, als das grundlegende WebRelease 3 (12, 3 MB im Vergleich zu 2,7 MB), sowie eine Verknüpfung zum Microsoft SQAP Toolkit,
welches Sie benötigen, um XML-Webdienste veröffentlichen zu können. Die Site beinhaltet darüber
hinaus Verknüpfungen zu Webcasts und technischen Dokumenten, die hilfreich sein könnten: http://
msdn.microsoft.com/downloads/default.asp?url=/downloads/sample.asp?url=/MSDN-FILES/
027/001/872/msdncompositedoc.xml&frame=true.
HINWEIS: Ich habe die Beispiele zu diesem Kapitel mit der Version entwickelt, die alle Features des
Toolkits umfasst. Auch wenn Sie nur die einfache Version des Web-Releases 3 herunterladen, empfehle ich Ihnen dringend den Download des SOAP Toolkits 2.0, welches ebenfalls über eine Verknüpfung auf der gleichen Seite wie das Web-Release heruntergeladen werden kann. Die Beispiele
aus Kapitel 13 erfordern SOAP (Sie sollten das also gleich alles in einem Aufwasch erledigen).
Neben der Fähigkeit, XML-Webdienste zu veröffentlichen, umfasst das Web-Release 3 die gleichen
Fähigkeiten, wie die früheren Web-Releases, mit einer Reihe gewisser Verbesserungen und Bugfixes.
Beispielsweise unterstützt Web-Release 3 parentID-Vermerke für Diffgramme. Die verwaltete Klasse
SqlXmlAdapter verwendet diese Vermerke während der Ausführung von Datenverarbeitungsaufgaben für eine SQL Server-Datenbank aus einer Visual Basic .NET-Anwendung heraus. Viele der Verbesserungen stehen über virtuelle IIS-Verzeichnisse für SQL Server zur Verfügung.
Web-Release 3 beinhaltet die Fähigkeit, virtuelle Verzeichnisse die mit früheren Web-Release-Versionen erstellt wurden, aktualisieren zu können. Ich empfehle Ihnen die Installation von Web-Release 3,
wenn Sie keine Anwendungen erstellt haben, die mit einem der beiden früheren Web-Releases ausgeführt werden. Schließlich umfasst Web-Release 3 die beiden früheren Web-Releases (zusammen mit
den Verbesserungen, die mit Web-Release 3 vorgestellt wurden). Wie für neue Software typisch, ist
Web-Release 3 mit den vorhergehenden Versionen auf Grund von geringfügigen funktionellen VerProgrammieren von XML mit Visual Basic .NET
453
677.book Page 454 Thursday, December 5, 2002 2:26 PM
besserungen und Bugfixes nicht vollständig abwärtskompatibel. Wenn Sie also Anwendungen erstellt
haben, die mit einem der beiden früheren Web-Releases ausgeführt werden, sollten Sie diese Lösungen vor der Installation von Web-Release 3 testen. Eine attraktive Option für diejenigen, die Anwendungen mit früheren Web-Releases erstellt haben, ist die Möglichkeit, Web-Release 3 neben den früheren Web-Releases ausführen zu können. Dies ist möglich, denn die Installation von Web-Release 3
(auch als SQLXML 3.0 bezeichnet) überschreibt keine Dateien der früheren Web-Releases. Einschränkungen und spezielle Fragen werden im Abschnitt Understanding the Side-by-Side Installation Issues (und den nachfolgenden drei Abschnitten) aus dem Thema About This Release in der
Dokumentation von Web-Release 3 erörtert. Sie können diese Dokumentation aus der Programmgruppe SQLXML 3.0 im Windows-Startmenü öffnen.
HINWEIS: Wenn Ihnen nur eine Testumgebung zur Verfügung steht, sollten Sie die virtuellen IISVerzeichnisse von Web-Release 1 und Web-Release 2 mit dem Dienstprogramm IIS Virtual Directory Management for SQLXML 3.0 aktualisieren. Doppelklicken Sie im Dienstprogramm IIS
Virtual Directory Management for SQLXML 3.0 auf das Stammverzeichnis der alten virtuellen
Verzeichnisse. Wechseln Sie dann zur Registerkarte Version 3 und klicken Sie auf Aktualisieren
auf Version 3. Schließen Sie die Aktualisierung durch Auswahl von Ja und OK ab.
SQLXML-verwaltete Klassen
Mit SQLXML-verwalteten Klassen können Sie in Ihren Visual Basic .NET-Programmen die Features
des zweiten und dritten Web-Releases verwenden. Es gibt drei SQLXML-verwaltete Klassen. Die
Namen der Klassen sind SqlXmlCommand, SqlXmlParameter und SqlXmlAdapter. Diese Klassen
werden in Visual Basic .NET-Prozeduren verwendet, um Objekte zu erstellen und deren Eigenschaften und Methoden programmatisch zu kontrollieren. Die SQLXML-verwalteten Klassen unterstützen
keine Ereignisse.
Sie können SQLXML-verwaltete Klassen zwar in .NET Framework-Anwendungen einsetzen, doch
gibt es keinerlei Dokumentation zu diesen Klassen in der Hilfe zu Visual Studio .NET oder zu Visual
Basic .NET. Die Hilfedatei aus dem Web-Release 3 gibt Auskunft über die Eigenschaften und Methoden, die von den SQLXML-verwalteten Klassen bereitgestellt werden. Darüber hinaus umfasst das
Hilfesystem mehrere Codebeispiele, die Sie wahrscheinlich nützlich finden werden. Eine der technischen Dokumentationen (mit dem Titel SQLXML Managed Classes), welche Bestandteil des Microsoft SQL Server 2000 Web Services Toolkit ist, umfasst weitere Hintergrundinformationen, die ich für
ein Verständnis zur Verwendung dieser nützlichen Klassen als hilfreich empfunden habe.
HINWEIS: Alle an dieser Stelle erwähnten Quellen für Hilfeinformationen zu SQLXML-verwalteten
Klassen gehen insbesondere auf die Verwendung der Klassen in C#-Programmen ein und beinhalten Quellcode für die Verwendung der Klassen mit C#. Da das Hilfesystem zum .NET Framework
Codebeispiele für Visual Basic .NET als auch für C# bereitstellt, könnte der Eindruck entstehen,
dass die SQLXML-verwalteten Klassen nur mit C# funktionieren. Ich kann sämtliche C#-Beispiele
in die Visual Basic .NET-Syntax übersetzen. Dieses Kapitel umfasst mehrere Visual Basic .NETBeispiele, die Sie als Anleitung für die Übersetzung von C#-Beispielen verwenden können.
Die SqlXmlCommand-Klasse
Sie können SqlXmlCommand-Objekte instantiieren, indem Sie eine Verbindungszeichenfolge für
das jeweilige Objekt als Bestandteil eines Ausdrucks mit dem New-Operator angeben. Es gibt bei den
SQLXML-verwalteten Klassen keine explizite Connection-Klasse. Die Verbindungszeichenfolge
muss den SQLOLEDB-Datenprovider angeben, sowie den Server, die Datenbank und einen Sicherheitsmechanismus, wie das auch in ADO und ADO.NET üblich ist. z. B.:
454
Kapitel 12
677.book Page 455 Thursday, December 5, 2002 2:26 PM
Dim cmd1 As SqlXmlCommand = New SqlXmlCommand(provider=sqloledb; _
server=Servername; _
database=Datenbankname; _
user id=Benutzeranmeldung; _
password=Benutzerkennwort)
Bevor Sie eine SQLXML-verwaltete Klasse verwenden (oder instantiieren) können, müssen Sie in
Ihrem Visual Basic .NET-Modul eine Referenz auf den Namespace Microsoft.Data.SqlXml angeben.
Sie können diese Referenz in Visual Basic .NET hinzufügen, wenn Sie den Codeeditor öffnen und
den Befehl Verweis hinzufügen aus dem Menü Projekt wählen. Wählen Sie im Dialogfeld Verweis
hinzufügen auf der Registerkarte .NET aus der Spalte Komponentenname den Eintrag Microsoft.Data.SqlXml aus. Haben Sie auf Ihrer Arbeitsstation sowohl das Web-Release 2 als auch das
Web-Release 3 installiert, müssen Sie die passende Microsoft.Data.SqlXml-Version für das WebRelease angeben, die Sie verwenden wollen. Web Release 3 hat die Versionsnummer 3.0.1523.0; die
Versionsnummer von Web Release 2 ist 2.0.1125.0. Nach dem Hinzufügen der Referenz zu Ihrem
Projekt müssen Sie eine Imports-Anweisung in den Modulen angeben, in denen Sie verwaltete Klassen verwenden wollen, es sei denn, Sie beabsichtigen, den einzelnen Referenzen auf die Klassen den
Namespacebezeichner Microsoft.Data.SqlXml voranzustellen.
HINWEIS: Es sollte bis zu dieser Stelle in diesem Buch deutlich geworden sein, dass ich mich nicht
strikt an Programmierkonventionen halte. Ich glaube, dass bestimmte Umstände – sowohl technischer als auch nicht technischer Natur – wesentlichen Einfluss auf die Einhaltung von Programmierkonventionen haben sollten. Um ein Beispiel zu geben, die Anforderungen an Codebeispiele,
die dafür ausgelegt sind, Designfeatures zu illustrieren, sind nicht notwendigerweise die gleichen,
wie für Produktivsoftware, die sich auch wieder von Prototypsoftware unterscheiden kann. Ungeachtet dessen werden viele Leser einen Ausgangspunkt mit Richtlinien zur Verwendung von Namespace-Präfixen oder Imports-Anweisungen wünschen. Ziehen Sie die Verwendung von Präfixen in Betracht, wenn Sie für ein bestimmtes Objekt die Aufmerksamkeit ausdrücklich auf die
Quelle des Namespaces richten wollen.
SqlXmlCommand-Methoden
Wie der Name verrät, können SqlXmlCommand-Objekte SQL-Anweisungen für eine Datenbank auf
einem SQL Server ausführen und ein Resultset im XML-Format zurückgeben. Beispielsweise generiert die ExecuteStream-Methode ein Resultset für eine SQL-Anweisung und erstellt ein neues
Stream-Objekt für das Resultset im XML-Format. Ein Stream-Objekt repräsentiert eine ByteSequenz, z. B. eine Byte-Sequenz für ein XML-Dokument. Bevor Sie mit den Inhalten eines StreamObjektes arbeiten können, müssen Sie dieses typischerweise an einen Reader übergeben, damit der
Reader die Ausgabe in einem XML-Dokument speichern kann, welches Sie anzeigen oder als Textzeichen verarbeiten können.
Es gibt verschiedene Arten von Stream-Objekten. Die Beispiele aus diesem Kapitel demonstrieren,
wie FileStream- und MemoryStream-Objekte funktionieren, welche im Namespace System.IO definiert sind. FileStream-Objekte verweisen auf Dateien im Dateisystem. MemoryStream-Objekte sind
Speichervariablen, auf die Sie verweisen können, solange diese gültig sind. Die ExecuteToStreamMethode des SqlXmlCommand-Objektes übergibt das Resultset an ein existierendes Stream-Objekt,
statt ein neues Stream-Objekt anzulegen.
Sie können SqlXmlCommand-Objekte verwenden, um XmlReader-Objekte mit der ExecuteXmlReader-Methode zurückzugeben. Ein XmlReader-Objekt ist ein Element aus dem System.XmlNamespace. Prozeduren, die XmlReader-Objekte verwenden, können schnell, nicht zwischengespeichert, und nur vorwärts gerichtet auf ein Stream-Objekt mit XML-Daten zugreifen. Ein üblicher
Programmieren von XML mit Visual Basic .NET
455
677.book Page 456 Thursday, December 5, 2002 2:26 PM
Grund für die Erstellung eines XmlReader-Objektes ist die Auswahl einer Teilmenge von Knoten aus
einem XML-Dokument, das mit dem XmlReader-Objekt verknüpft ist. Ein Knoten kann einer Zeile
mit Daten entsprechen, die im XML-Dokument enthalten ist. Aus diesem Blickwinkel betrachtet ist
die Auswahl einer Teilmenge von Knoten äquivalent zur Verwendung einer WHERE-Klausel in einer
SELECT-Anweisung, um eine Teilmenge von Zeilen aus einer Tabelle oder Sicht anzugeben.
Sie können außerdem die Methoden CreateParameter und ClearParameters für Instanzen der
SqlXmlCommand-Klasse aufrufen. Die CreateParameter-Methode gestattet Ihnen die Angabe eines
Parameters für das SqlXmlCommand-Objekt, damit Sie Werte zur Laufzeit festlegen können. Mit
dieser Fähigkeit können Ihre Prozeduren Werte für Befehle auf der Grundlage von Benutzereingaben
und anderen Aspekten der Arbeitsumgebung dynamisch setzen. Wenn Sie ein SqlXmlCommandObjekt mit anderen Parametern oder ohne Parameter wieder verwenden wollen, müssen Sie die
ClearParameters-Methode aufrufen, um alle vorhandenen Parameter zu löschen.
Eine letzte Methode vervollständigt die von der SqlXmlCommand-Klasse bereitgestellte Funktionalität. Die ExecuteNonQuery-Methode ist für solche Befehle dienlich, die kein Resultset zurückgeben,
z. B. Diffgramme.
SqlXmlCommand-Eigenschaften
Die möglichen Angaben für die CommandType-Eigenschaft eines SqlXmlCommand-Objektes weisen auf die speziellen Rollen hin, die SqlXmlCommand-Objekte spielen können. Die folgende Aufzählung von CommandType-Einstellungen bestimmt alle möglichen Quellen für ein SqlXmlCommand-Objekt.
b SqlXmlCommandType.Sql Weist darauf hin, dass der Befehl eine SQL-Quelle für den Befehl
angibt, z. B. eine SELECT-Anweisung mit einer FOR XML-Klausel.
b SqlXmlCommandType.XPath Ist angebracht, wenn Sie eine Abfragezeichenfolge mit einem
XPath-Ausdruck angeben.
b SqlXmlCommandType.TemplateFile Ermöglicht die Ausführung einer Vorlagedatei, die entweder SQL- oder XPath-Syntax beinhaltet. Der Pfad auf die Datei wird in der CommandText-Eigenschaft angegeben. Die CommandText-Eigenschaft verweist als speziell auf die Vorlagedatei. Diese
Vorlagedateien haben das gleiche Format wie die Dateien, die in Kapitel 6 angesprochen wurden, diese müssen sich aber nicht in einem virtuellen IIS-Verzeichnis befinden.
b SqlXmlCommandType.Template Ermöglicht dem SqlXmlCommand-Objekt die Ausführung des
Inhaltes einer Vorlagedatei in SQL- oder XPath-Syntax mit einem Pfad, der in der CommandTextEigenschaft angegeben werden muss. Die CommandStream-Eigenschaft bezeichnet die Parameter
zum Öffnen eines FileStream-Objekts mit der Vorlage. Der Parameter SqlXmlCommandType.Template verweist lediglich auf den Pfad und den Dateinamen der Vorlagedatei – aber nicht
auf die eigentlichen Inhalte.
b SqlXmlCommandType.UpdateGram Gibt ein Updategramm an, das vom SqlXmlCommandObjekt ausgeführt werden soll.
b SqlXmlCommandType.Diffgram Bezeichnet ein Diffgramm als Argument des SqlXmlCommand-Objektes.
Verwenden Sie die CommandText-Eigenschaft, um die Quelle des SqlXmlCommand-Objektes anzuzeigen. Um ein Beispiel zu geben, die CommandType-Einstellung SqlXmlCommandType.TemplateFile gestattet Ihnen die Verwendung der CommandText-Eigenschaft zur Angabe eines Pfades und
eines Dateinamens für die Vorlagedatei. In Visual Basic .NET-Anwendungen brauchen Sie den Text
einer Abfrageanweisung nicht auf die gleiche Art und Weise zu schützen, wie bei Webanwendungen
und virtuellen IIS-Verzeichnissen. Dies ergibt sich aus der Tatsache, dass die Benutzer Visual Basic
456
Kapitel 12
677.book Page 457 Thursday, December 5, 2002 2:26 PM
.NET-Anwendungen mit kompilierten .exe-Dateien ausführen. Normalerweise werden Sie entweder
die SQL- oder die XPath-Syntax zur Angabe der CommandText-Eigenschaft mit einer dazugehörigen
CommandType-Eigenschaftseinstellung verwenden.
Ausgewählte andere SqlXmlCommand-Eigenschaften werden in den Beispielen zu diesem Kapitel
verwendet. Wenn Ihr Resultset kein einzelnes übergeordnetes oder Stammelement umfasst, können
Sie eines mit der RootTag-Eigenschaft angeben. Wenn Sie eine XPath-Abfrage ausführen, können Sie
den Pfad auf die Datei eines Zuordnungsschemas, das mit der Abfrage verknüpft ist, über die SchemaPath-Eigenschaft des SqlXmlCommand-Objekts angeben. Ein Zuordnungsschema kann mit speziellen Kommentaren Beziehungen zwischen den Elementen und Attributen eines Schemas bezeichnen, das ein XML-Dokument und eine SQL Server-Datenquelle darstellt. Die XslPath-Eigenschaft
gestattet Ihnen die Angabe eines Dateinamens und eines Pfades auf eine Datei, die die unbearbeitete
XML-Ausgabe, die von der CommandText-Eigenschaft spezifiziert wird, in ein anderes Format überführt, z. B. eine HTML-Tabelle. Siehe den Abschnitt SqlXmlCommand Object aus der Dokumentation zum Web-Release 3 für eine Zusammenfassung der SqlXmlCommand-Eigenschaften, die in diesem Kapitel nicht behandelt werden.
Die SqlXmlParameter-Klasse
SqlXmlCommand-Objekte können über hierarchisch voneinander abhängige Parameter verfügen,
die von SqlXmlParameter-Objekten repräsentiert werden. Verwenden Sie die CreateParameterMethode eines SqlXmlCommand-Objektes, um ein SqlXmlParameter-Objekt zu instantiieren. Nach
der Instantiierung können Sie den Name- und Value-Eigenschaften des SqlXmlParameter-Objektes
Werte zuweisen. Die Name-Eigenschaft bietet eine bequeme Möglichkeit zur Referenzierung des
SqlXmlParameter-Objektes und die Value-Eigenschaft ermöglicht Ihnen die Zuweisung eines Wertes an den Parameter zur Laufzeit.
Die SqlXmlAdapter-Klasse
SqlXmlAdapter-Objekte können für den gleichen Zweck eingesetzt werden, wie SqlDataAdapterObjekte im Namespace System.Data.SqlClient. Nach der Deklarierung einer Variablen als SqlXmlAdapter-Objekte können Sie die Variable mit einem Ausdruck instantiieren, der den New-Operator
für die SqlXmlAdapter-Klasse umfasst. Das SqlXmlAdapter-Objekt kann eine Variable als Argument
akzeptieren, die auf ein SqlXmlCommand-Objekt verweist. Die Syntax für diese Konstruktion wird
an dieser Stelle dargestellt, wobei cmd1 ein zuvor instantiiertes SqlXmlCommand-Objekt repräsentiert. Das Argument cmd1 bezeichnet die Datenquelle, auf die mit dem SqlXmlCommand-Objekt
zugegriffen wird.
Dim dap1 As SqlXmlAdapter
Dap1 = New SqlXmlAdapter (cmd1)
SqlXmlAdapter-Objekte verfügen über zwei Methoden namens Fill und Update. Verwenden Sie die
Fill-Methode, um ein Dataset zu füllen. Rufen Sie die Update-Methode auf, um in der Datenquelle,
auf die das SqlXmlAdapter-Objekt verweist, Zeilen einzufügen, zu modifizieren oder zu löschen. Bei
diesen Methoden brauchen Sie nur das Dataset als Argument anzugeben. Es gibt keine Notwendigkeit zur Angabe einer bestimmten Tabelle aus dem Dataset. Ich mag das SqlXmlAdapter-Objekt
wegen der einfachen Vorgehensweise, im Vergleich zu SqlDataAdapter-Objekten aus dem Namespace System.Data.SqlClient, mit der ich Datenverarbeitungsaufgaben ausführen kann. Ein paar
Beispiele werden später in diesem Kapitel die neue Syntax demonstrieren, mit der die Notwendigkeit
der UpdateCommand-Eigenschaft (und in diesem Sinne auch die InsertCommand- und DeleteCommand-Eigenschaften) eliminiert wird.
Programmieren von XML mit Visual Basic .NET
457
677.book Page 458 Thursday, December 5, 2002 2:26 PM
Diffgramme für die Datenverarbeitung
Ein Diffgramm ist ein XML-Format zur Darstellung der Datenwerte in einem Dataset. Das .NET Framework verwendet dieses XML-Format automatisch für die Übermittlung von Daten zwischen einem
Client und einer SQL Server-Datenbank. Darüber hinaus können Sie das Diffgrammformat direkt mit
SQL Server-Datenbanken verwenden, ähnlich wie Sie Updategramme einsetzen können. In Kapitel 6 finden Sie Beispiele zur Verwendung von Updategrammen für die Datenverarbeitung mit einer
SQL Server 2000-Datenbank, um mehr über die Möglichkeiten zu erfahren, die Ihnen Diffgramme in
Webanwendungen für SQL Server bieten.
Der folgende Code zeigt das allgemeine Layout von Diffgrammen. Beachten Sie, dass dieser mit einer
Deklaration beginnt, die das Diffgramm als ein XML-Dokument bezeichnet. Danach werden mehrere
Namespaces referenziert. Die für Datenverarbeitungsaufgaben wichtigsten Bereiche aus dem Dokument sind die Abschnitte DataInstance und before. Der DataInstance-Abschnitt bezeichnet den
aktuellen Wert aller Zeilen aus der Datenquelle. Um ein Beispiel zu geben, dieser Abschnitt umfasst
all diejenigen Zeilen, die über modifizierte Spaltenwerte verfügen, sowie alle eingefügten Zeilen und
alle nicht modifizierten Zeilen, die nicht aus der Datenquelle gelöscht wurden. Der before-Abschnitt
enthält die ursprünglichen Werte für modifizierte Zeilen. Gelöschte Zeilen werden ebenfalls im
before-Abschnitt aufgeführt, aber nicht im DataInstance-Abschnitt. Der errors-Abschnitt ist optional. Dieser Abschnitt umfasst Fehlermeldungen für die Zeilen aus dem DataInstance-Abschnitt.
Eine Ansammlung von Attributen unterstützt bestimmte Objektive, z. B. die Zuordnung von Zeilen
aus dem DataInstance-Abschnitt zu den entsprechenden Zeilen in den before- und errors-Abschnitten, sowie die Hervorhebung von Zeilen, die an Einfüge-, Aktualisierungs- und Löschaufgaben beteiligt sind.
<?xml version="1.0"?>
<diffgr:diffgram
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DataInstance>
</DataInstance>
<diffgr:before>
</diffgr:before>
<diffgr:errors>
</diffgr:errors>
</diffgr:diffgram>
Wenn Sie ein Visual Basic-Entwickler sind und mit dem .NET Framework arbeiten wollen, wird es
Sie freuen, zu hören, dass Sie Diffgramme einsetzen können, ohne deren Format wirklich erlernen zu
müssen. Das Kapitel 10 und das Kapitel 11 verdeutlichen beispielsweise, wie Datenverarbeitungsaufgaben mit Windows Forms und ASP.NET-Seiten ausgeführt werden können. In beiden Fällen verwendet ADO.NET Diffgramme im Hintergrund. Ich denke, dass das Verständnis des Formats
und des Layouts von Diffgrammen mir hilft, die Gründe für die Syntax zur Angabe von Datenverarbeitungsaufgaben im .NET Framework zu erfassen. Meine beiden bevorzugtesten Ressourcen für die
Entwicklung dieses Verständnisses sind:
b Der Abschnitt Diffgramme aus der Dokumentation zu Visual Studio .NET. Sie können auf diese
Dokumentation über das Startmenü von Windows zugreifen.
458
Kapitel 12
677.book Page 459 Thursday, December 5, 2002 2:26 PM
b Der Abschnitt Using DiffGrams to Modify Data aus der Dokumentation zum Web-Release 3.
Diese Dokumentation wird mit der Standardversion des Web-Releases 3 mitinstalliert. Sie können
auf diese Dokumentation über das Startmenü von Windows zugreifen.
Dieses Kapitel umfasst eine Reihe von Beispielen zur Verarbeitung von ADO.NET-Datasets mit
SQLXML-verwalteten Klassen. Eines dieser Beispiele betont die Verwendung von Diffgrammen im
.NET Framework für Datenverarbeitungsaufgaben. Das zweite Beispiel verdeutlicht, wie einfach es
ist, diese ADO.NET-Lösung von einer Windows-Lösung in eine ASP.NET-Anwendung zu konvertieren. Beide Beispiele bestätigen, dass Sie Datenverarbeitungsaufgaben auf der Basis von Diffgrammen
ausführen können, ohne mit diesen in Ihrem Code umgehen zu müssen.
Die Tatsache, dass Sie Diffgramme ohne eigentliche Programmierung verwenden können, wirft eine
interessante Frage über die allgemeine Rolle von XML für typische .NET Framework-Entwickler auf.
Es gibt keinen Zweifel, dass für erfahrene und fortgeschrittene .NET Framework-Entwickler ein gutes
Verständnis von XML eine Voraussetzung darstellt. Es bleibt aber abzuwarten, bis zu welchem Grad
typische Entwickler die sämtliche (oder wenigstens die meisten) Details der XML-Programmiersprachen beherrschen müssen (siehe den nächsten Abschnitt für einen Überblick zu einigen dieser Sprachen). Um ein Beispiel zu geben, es könnte sein, dass XML-Syntax weitestgehend nicht erforderlich
ist, wenn Sie XML mit Visual Basic .NET oder mit SELECT-Anweisungen, die eine FOR XML-Klausel umfassen, indirekt verarbeiten. Setzt sich dieser Trend fort, könnte XML einer großen Menge von
Funktionen zugrunde liegen, wobei typische Entwickler in der Lage sind, andere, bekanntere Sprachen zu verwenden, um die XML-Konstrukte zu verarbeiten. Dies ähnelt der Vorgehensweise, bei der
Visual Basic-Entwickler ADO als Möglichkeit verwendet haben, um OLE DB-Datenprovider zu programmieren. Auf der anderen Seite könnte sich XML als eine notwendige Syntax für „echte“ Programmierer herausstellen. Wenn Sie beispielsweise die Bedeutung abwägen, die XML in Computerpublikationen beigemessen wird, könnten Sie in der Tat leicht zu diesem Schluss kommen. Ich bin
mir nicht sicher, wo Sie in diesem Kontinuum enden werden. Jedoch ist klar, dass die Vermeidung
von XML-Themen, ein Risiko für Ihre Zukunft als Entwickler darstellt.
Überblick über XML-Technologien
XML umfasst nicht nur grundlegende Designfragen zu XML-Dokumenten, die Daten enthalten. Dieser Abschnitt stützt sich auf die Abhandlung zu XML-Dokumentformaten und diesbezüglichen Technologien aus Kapitel 6. Darüber hinaus bietet dieser Abschnitt einen Überblick über XML-seitige
Aufgaben, die Sie mit dem .NET Framework ausführen können.
XML-Datenformate
XML-Formate verfügen über mehrere separate Features.
b Tags können für bestimmte Dokumente angepasst werden.
b Sie können Daten entweder in Elementen oder in Attributen darstellen.
b Alle XML-Dokumente beginnen mit einer Deklaration, die die XML-Version des Dokuments
bekannt gibt.
Diese und weitere Syntaxmerkmale wurden in Kapitel 6 in ausreichendem Maße diskutiert, um
den Stoff dieses Kapitel bewältigen zu können. Überfliegen Sie die Abschnitte zu XML-Formaten und
XML-Schemata, um sicherzustellen, dass Sie das erforderliche Hintergrundwissen für die Ausführungen im aktuellen Kapitel besitzen. Sie können auch die Website des World Wide Web Consortium
besuchen (http://www.w3c.org oder http://www.w3.org), wenn Sie an umfassenden Informationen
zu den neuesten öffentlichen XML-Standards interessiert sind.
Programmieren von XML mit Visual Basic .NET
459
677.book Page 460 Thursday, December 5, 2002 2:26 PM
XML-Dokumente
Das XML-Datenformat gewinnt aus vielen Gründen Anerkennung. Einer der wichtigsten Gründe für
Datenbankentwickler ist die Fähigkeit von XML-Daten, hierarchische Beziehungen widerzuspiegeln.
Die Art und Weise, wie hierarchische Beziehungen in XML-Dokumenten beschrieben werden, unterscheidet sich sehr von den relationalen Datenmodellen, die hierarchische Beziehungen mit Verbindungen zwischen zwei oder mehreren Tabellen darstellen. Ein XML-Dokument kann beispielsweise
eine Ansammlung von Bestellungen mit den dazugehörigen einzelnen Posten, also den Detailinformationen, physisch verschachtelt darstellen. In der hierarchischen Repräsentierung, die in XML-Formaten beliebt ist, wird jede Zeile aus der Tabelle mit den Bestellungen nur einmal dargestellt, unabhängig davon, wie viele Posten der jeweiligen Bestellung zugeordnet sind. Im relationalen Modell
würde die Ansammlung der Bestellungen hingegen als eine einzelne, flache, virtuelle Tabelle mit den
Daten aus der Posten-Tabelle, die den Daten aus der Bestellungstabelle zugeordnet sind, dargestellt.
Identische Spaltenwerte aus der Tabelle mit den Bestellungen würden bei einer relationalen Repräsentierung in der virtuellen Tabelle für jeden Posten wiederholt werden.
Eine weitere sehr wichtige Charakteristik der XML-Formatierung ist die Repräsentierung der Daten
als Text. Dies bedeutet, dass Sie (und andere Personen) die Daten ohne zusätzliche spezielle Umsetzungen lesen können. Frühere Datenformate verwendeten typischerweise ein binäres Datenformat,
wodurch die Daten des Dokuments nicht unmittelbar lesbar dargestellt wurden und darüber hinaus
schlechter über Firewalls transportiert werden konnten. Es gibt zwar ein funktionsreiches Programmiermodell für die Verarbeitung von XML-Datendokumenten, es ist aber wichtig zu verstehen, dass
XML-Dokumente nur Textdokumente sind. Es ist also möglich, übliche Textanalysemethoden zu verwenden, um ausgewählte Daten aus einem XML-Dokument zu extrahieren. Ich werde eine benutzerdefinierte Analysetechnik später in diesem Kapitel beschreiben.
XML-Schemata
Zusätzlich zu den Daten aus XML-Dokumenten werden Sie häufig mit dem Schema von XMLDokumenten arbeiten. Schemata von XML-Dokumenten dienen ähnlichen Aufgaben wie die Schemata von Datenbanken. Insbesondere beschreibt ein Schema die Datenelemente und die Beziehungen zwischen den Ansammlungen von Datenelementen. Sie können das .NET Framework sowohl als
Hilfe für die Erstellung neuer Schemata verwenden, als auch für die Erstellung von Schemata für existierende Dokumente.
Dieses Kapitel konzentriert sich exklusiv auf Schemata im XSD-Format. XSD ist der aktuelle Standard für die Repräsentierung der Struktur eines Dokumentes. Bei der ersten Freigabe von SQL Server
verwendete Microsoft das XDR-Format für die Festlegung der Strukturen von Dokumenten. Als die
Entscheidung für das XDR-Format fiel, gab es noch keinen universell anerkannten Standard, wie
XSD, für die Repräsentierung der Struktur eines Dokumentes. Microsoft hat ein XSLT-Stylesheet für
die Übersetzung von Schemata im XDR-Format in das entsprechende XSD-Format veröffentlicht. Sie
können dieses Stylesheet unter http://msdn.microsoft.com/downloads/default.asp?url=/downloads/sample.asp?url=/MSDN-FILES/027/001/539/msdncompositedoc.xml finden.
Als ein .NET-Entwickler, der mit SQL Server arbeitet, werden Sie XML-Dokumente häufig für SQL
Server-Datenquellen erstellen wollen. In diesem Fall kann das .NET Framework eine Darstellung des
Schemas für die XML-Dokumente vom Schema der SQL Server-Datenquelle, welche die Werte für
das XML-Dokument bereitstellt, ableiten. In der Tat können Sie ADO.NET-Objekte verwenden und
Diffgramme oder ein XSD-Schema indirekt mit dem .NET Framework aufbauen.
Einer der Gründe für die manuelle Erstellung eigener Schemata ist die Erstellung eines stark typisierten DataSets. Diese Art von Dataset kann sich wie eine benutzerdefinierte Klasse verhalten, mit der
Ausnahme, dass es die Eigenschaften, Methoden und Ereignisse von ADO.NET-Datasets erbt. Geben
460
Kapitel 12
677.book Page 461 Thursday, December 5, 2002 2:26 PM
Sie das Schema für die Klasse zur Entwurfszeit an. Das Schema definiert die Struktur des stark typisierten DataSets. Sie können dann jederzeit eine Instanz des DataSets mit dem gleichen New-Operator instantiieren, den Sie auch für die Instantiierung andere Objekte verwenden. Sie können das typisierte Dataset mit einem SqlDataAdapter-Objekt füllen. Stark typisierte DataSets haben einen
deutlichen Vorteil gegenüber den Standard-DataSets die .NET für Sie erstellen kann. Um ein Beispiel
zu geben, Sie können sich explizit auf die Spalten über deren Namen beziehen, statt deren Spaltenposition innerhalb eines DataTable-Objektes im Dataset angeben zu müssen. Siehe das Thema
»Arbeiten mit typisierten DataSets« und dessen Verknüpfungen in der Dokumentation von Visual
Studio .NET für weitere Details zu diesem DataSet-Typ, Anweisungen zu dessen Erstellung und
Codebeispielen zu dessen Verwendung.
Ein kommentiertes Schema ist ein spezieller Typ eines Schemas für die Angabe der Struktur eines
XML-Dokumentes, wobei Sie gleichzeitig eine externe Quelle für die Struktur angeben. Statt mit dem
.NET Framework ein Schema implizit aufzubauen, können Sie dieses explizit erstellen. Das Thema
Using Annotations in XSD Schemas aus der Dokumentation zum Web-Release 3 umfasst viele hilfreiche Verknüpfungen für eine genauere Abhandlung der manuellen Techniken, die Sie verwenden
können, um kommentierte Schemata zu erstellen. Ein allgemeines Verständnis dieses Themas in Verbindung mit den zahlreichen Beispielen aus der .NET Framework-Dokumentation und den Beispielen aus diesem Buch kann Ihnen dabei helfen, kommentierte Schemata zu lesen und für benutzerdefinierte Erweiterungen in Ihren Anwendungen anzupassen. Zwei übliche Einsatzgebiete für
kommentierte Schemata im .NET Framework sind der Aufbau von XML-Dokumenten anhand einer
Datenbank und die Benennung von Spalten in einem XML-Dokument mit Namen, die sich von der
zugrunde liegenden Datenquelle unterscheiden.
XPath-Abfragen
XPath ist eine Sprache, die Ihnen den Zugriff auf die Bereiche eines XML-Dokumentes ermöglicht.
Sie können XPath verwenden, um ein XML-Dokument abzufragen, ähnlich wie Sie SQL verwenden,
um eine Datenbank abzufragen. Ein XPath-Abfrageausdruck kann eine Auswahl aus Dokumentabschnitten oder -typen treffen, beispielsweise aus den Elementen, Attributen und dem Text eines
Dokumentes. Sie können Knoten für übergeordnete, untergeordnete und gleichartige Elemente eines
angegebenen Dokumententyps angeben. Ein übergeordneter Knoten ist ein Typ, der den aktuellen
Typ beinhaltet. Um ein Beispiel zu geben, eine Bestellung ist ein übergeordnetes Element von einzelnen Posten aus der Bestellung. Im umgekehrten Sinne ist ein untergeordnetes Element ein Element
des aktuellen Typs. Jeder Typ, den Sie in der Auswahl einer XPath-Abfrage verwenden, kann einen
Satz von Knoten zurückgeben. Diese Knoten entsprechen generell den Zeilen aus dem Resultset
einer SQL-Anweisung, allerdings ist die Syntax zur Angabe des XML-Dokumenttyps mit einer
XPath-Abfrage komplett anders aufgebaut, als die traditionelle SQL-Syntax.
Sie können SQLXML-verwaltete Klassen verwenden, um XPath-Abfragen zu formulieren und auszuführen. Sie können Abfrageanweisungen sogar dynamisch zur Laufzeit erstellen. Der Satz von
Knoten, der von der XPath-Abfrage zurückgegeben wird, ist in einem XmlNodeList-Objekt enthalten. Das .NET Framework gibt Visual Basic-Entwicklern die Möglichkeit, die einzelnen Knoten aus
der Liste der Knoten zu durchlaufen, um die Ergebnisse des XPath-Abfrageausdrucks zu untersuchen. Mehrere Codebeispiele im übrigen Teil dieses Kapitels demonstrieren die Syntax für die Ausführung dieser Art von Aufgaben. In Kapitel 6 finden Sie eine weitere Abhandlung der XPathSprache und zusätzliche Ressourcen zu deren Erlernung.
Programmieren von XML mit Visual Basic .NET
461
677.book Page 462 Thursday, December 5, 2002 2:26 PM
XSLT-Formatierung
XSLT ermöglicht die programmatische Umwandlung von Dateien im XML-Format in verschiedene
andere Formate. XSLT hat viele potentielle Einsatzgebiete. Dieses Buch behandelt jedoch nur die
Fähigkeit von XSLT zur Umwandlung von XML-Dateien in HTML-Tabellen auf einer Webseite. Sie
können XSLT-Transformationen in .NET-Anwendungen mit SQLXML-verwalteten Klassen bewerkstelligen. Eine .xslt-Datei ist eine separate Datei. Eine .NET-Anwendung kann sich auf diese .xsltDatei über eine Eigenschaftszuweisung an ein SqlXmlCommand-Objekt beziehen.
Eine .xslt-Datei kann Stylesheet-Elemente, HTML-Code und Verarbeitungsanweisungen für die
Extrahierung der Inhalte aus dem XML-Dokument enthalten. Eine .xslt-Datei ist ein Dateityp, den
sehr wahrscheinlich eher Webentwickler als Visual Basic-Entwickler erstellen werden. Mit ausreichendem Vorbedacht und Zusammenarbeit kann der Webentwickler den Visual Basic-Entwicklern
einen Satz von .xslt-Standarddateien zur Verfügung stellen. Wurde eine .xslt-Datei bereitgestellt,
kann der Visual Basic-Entwickler diese unmittelbar referenzieren, um die Daten für eine Webseite zu
formatieren. Das heißt, der Visual Basic-Entwickler kann mithilfe einer .xslt-Datei eine HTML-Datei
direkt erstellen. Der Visual Basic-Entwickler kann die SqlXmlCommand-Klasse verwenden, um Zeilen aus einer SQL Server-Datenquelle im XML-Format zu extrahieren. Danach kann der Entwickler
eine Eigenschaftszuweisung für die SqlXmlCommand-Klasse vornehmen, um die Formatierung der
Zeilen für die Anzeige auf einer Webseite in einer HTML-Tabelle zu aktivieren. Die Webseite ist statischer Natur. Allerdings kann das .NET Framework den Benutzern über den Aufruf eines Programms
zur Erstellung statischer Seiten auf Anforderung die Erstellung von Inhalten im Webformat gestatten.
Generieren von XML-Dokumenten mit dem
.NET Framework
Dieser Abschnitt demonstriert Methoden für die Erstellung und Ablage von XML-Dokumenten auf
der Grundlage von SQL Server-Datenquellen. Die Beherrschung der Konzepte für die Umsetzung
dieser Art von Aufgaben bringt Sie mit den Techniken für die Arbeit mit XML-Inhalten in Visual
Basic .NET-Anwendungen in Kontakt. Da XML in vielen Einsatzbereichen wichtig ist, einschließlich
im Bereich der Veröffentlichung von Inhalten als HTML, ist es wichtig, dass Sie diese Techniken
erlernen.
Für viele der Beispiele aus diesem Kapitel werden Sie eine Referenz auf den Namespace Microsoft.Data.SqlXml hinzufügen müssen. Lesen Sie den Abschnitt »SQLXML-verwaltete Klassen«
in diesem Kapitel für detaillierte Anweisungen zum Hinfügen einer Referenz auf den Namespace
Microsoft.Data.SqlXml. Darüber hinaus gehen einige Beispiele von der Existenz einer ImportsAnweisung für diesen Namespace und für andere ausgewählte Namespaces aus. Ich habe sämtliche
Beispiele aus diesem Kapitel, mit Ausnahme eines Beispiels, mit den folgenden Imports-Anweisungen am Anfang des Moduls entwickelt. Bei der Untersuchung der einzigen Ausnahme werde ich bei
deren Beschreibung spezielle Anweisungen zur Einrichtung der Umgebung geben.
Imports
Imports
Imports
Imports
462
Microsoft.Data.SqlXml
System.Data.SqlClient
System.Xml
System.IO
Kapitel 12
677.book Page 463 Thursday, December 5, 2002 2:26 PM
Erstellen eines XML-Dokuments mit T-SQL
Eine der natürlichsten Möglichkeiten für SQL Server-Entwickler zur Erstellung von XML-Dokumenten besteht in der Verwendung einer SQL-Anweisung. Wie bereits in Kapitel 6 erwähnt, können
Sie mit SQL und der FOR XML-Klausel XML-Fragmente erstellen (wenn das Resultset mehr als eine
einzelne Zeile umfasst). Eigentlich stellen diese Fragmente fast komplette XML-Dokumente dar, mit
der Ausnahme des Stammelementes. Eine Strategie zur Erstellung eines Resultsets in Form eines
XML-Dokumentes ist also die Ausführung einer SQL-Anweisung mit einer FOR XML-Klausel und
die Deklarierung eines Stammelementes. Da eine SQL-Anweisung nichts weiter ist, als ein Befehl für
eine SQL Server-Instanz, können Sie ein SqlXmlCommand-Objekt verwenden, um den Befehl auszuführen und ein XML-Dokument zurückzugeben.
Das SqlXmlCommand-Objekt verfügt über mehrere Features, die sich besonders für den Zugriff auf
eine SQL Server-Datenquelle und die Rückgabe eines XML-Dokuments eignen. Der Konstruktor des
SqlXmlCommand-Objektes akzeptiert eine direkte Verbindungszeichenfolge. Dies bedeutet, dass es
keine Notwendigkeit gibt, ein separates Verbindungsobjekt instantiieren zu müssen, wenn Sie lediglich einen Befehl ausführen wollen. Weiterhin können Sie mit der RootTag-Eigenschaft des SqlXmlCommand-Objektes ein Stammelement angeben, um das von der SQL-Anweisung mit der FOR
XML-Klausel zurückgegebene XML-Fragment in ein vollständiges XML-Dokument zu konvertieren.
Zwei weitere Eigenschaften gestatten Ihnen die Vervollständigung der SQL-Spezifikation für das
SqlXmlCommand-Objekt. Geben Sie als CommandType-Eigenschaft SqlXmlCommandType.Sql
an, um anzuzeigen, dass Ihr SqlXmlCommand-Objekt eine SQL-Anweisung ausführt. Weisen Sie
dann die SQL-Anweisung der CommandText-Eigenschaft zu. Nun kann die ExecuteToStreamMethode des SqlXmlCommand-Objekts das XML-Dokument als eine Sequenz von Bytes zurückgeben.
Die nun folgende Prozedur SaveDBQueryAsXmlToFile illustriert die Syntax für die Erstellung einer
Datei, die ein XML-Dokument auf der Grundlage einer SQL-Anweisung enthält. Die Prozedur
beginnt mit der Angabe einer Verbindungszeichenfolge für ein SqlXmlCommand-Objekt. Da dieses
Objekt eine Instanz einer SQLXML-verwalteten Klasse mit gleichem Namen darstellt, muss in der
Verbindungszeichenfolge der SQLOLEDB-Datenprovider angegeben werden. Der Konstruktor des
SqlXmlCommand-Objektes referenziert diese Verbindungszeichenfolge, um das Objekt zu instantiieren. Im nächsten Codeblock des Beispiels werden dann die Eigenschaften des SqlXmlCommandObjektes zur Rückgabe eines XML-Dokumentes gesetzt. Insbesondere weist die CommandTextEigenschaft darauf hin, dass das Dokument alle Zeilen aus der Shippers-Tabelle enthalten wird. Die
RootTag-Eigenschaft bezeichnet die Zeichenfolge Shippers für die Verwendung als Stammelement
des Dokumentes.
Wie Sie erkennen können ist die Übergabe der zurückgelieferten Informationen vom SqlXmlCommand-Objekt an eine Datei ein aus mehreren Schritten bestehender Prozess. Bevor die ExecuteToStream-Methode des SqlXmlCommand-Objekts aufgerufen wird, müssen Sie einen Namen und
einen Pfad für die Datei angeben, in der das vom SqlXmlCommand-Objekt generierte XML-Dokument gespeichert werden soll. In der Prozedur wird diese Anforderung mit einer Zuweisung der Zeichenfolge namens myXMLfile erfüllt. Dem zugewiesenen Wert entspricht der Pfad und der Dateiname des Dokuments. (Sie sollten einen anderen Pfad auf die Datei angeben, wenn der Pfad auf
Ihrem Computer nicht gültig ist.) Als nächstes instantiiert die Prozedur ein FileStream-Objekt, um
das XML-Dokument zu speichern. Der Kontruktor erwartet zwei Argumente. Das eine Argument ist
eine Zeichenfolgenvariable, myXMLfile, die den Namen und den Pfad auf die Datei angibt. Das
zweite Argument weist darauf hin, dass die Datei stets neu angelegt werden soll – selbst wenn im Pfad
bereits eine Datei mit gleichem Namen existieren sollte. Zum Abschluss übernimmt die ExecuteToStream-Methode das FileStream-Objekt als ein Argument, damit das SqlXmlCommand-Objekt
Programmieren von XML mit Visual Basic .NET
463
677.book Page 464 Thursday, December 5, 2002 2:26 PM
weiß, wo das von diesem Objekt generierte XML-Dokument abgelegt werden soll. Die Prozedur wird
dann mit dem Schließen des FileStream-Objekts beendet. Dieser Schritt übergibt die Kontrolle von
der Datei zurück an die Anwendung.
Sub SaveDBQueryAsXmlToFile()
' Angeben einer Verbindungszeichenfolge für SqlXmlCommand.
Dim cnn1String As String = _
"Provider=SQLOLEDB;Server=(local);" & _
"database=Northwind;" & _
"Integrated Security=SSPI"
' Angeben der Verbindung für das SqlXmlCommand-Objekt cmd1.
Dim cmd1 As SqlXmlCommand = _
New Microsoft.Data.SqlXml.SqlXmlCommand(cnn1String)
' Bezeichnen der Datenquelle für cmd1.
cmd1.RootTag = "Shippers"
cmd1.CommandType = SqlXmlCommandType.Sql
cmd1.CommandText = "SELECT * FROM Shippers " & _
"FOR XML AUTO"
' Angeben des Pfades und der Datei für das XML-Resultset.
' Danach Instantiieren eines Stream-Objekts für
' die Dateiinhalte.
Dim myXMLfile As String = _
"c:\SQL Server Development with VBDotNet\" & _
"Chapter12\myShippersFromFORXML.xml"
Dim myFileStream As New System.IO.FileStream _
(myXMLfile, System.IO.FileMode.Create)
' Ausführen von cmd1 und
' Speichern des Resultsets im Stream-Objekt.
cmd1.ExecuteToStream(myFileStream)
' Schließen des FileStream-Objekts, um die
' Ressource freizugeben.
myFileStream.Close()
End Sub
Die Abbildung 12.1 zeigt ein XML-Dokument, das von der Prozedur SaveDBQueryAsXmlToFile
generiert wurde. Ich bin in das Verzeichnis der Datei anhand des an myXMLfile übergebenen Pfades
gewechselt und habe die Datei im Windows-Explorer geöffnet. Das Stammelement ist Shippers, entsprechend dem Wert, der der RootTag-Eigenschaft des SqlXmlCommand-Objekts zugewiesen
wurde. Die Zeilenwerte aus der Shippers-Tabelle erscheinen als Attribute in dem jeweils einer Zeile
entsprechenden Element. Auf Grund der Art und Weise, wie die FOR XML-Klausel das Resultset formatiert, verfügt jede Zeile über den gleichen Elementnamen. Der Name des Elements entspricht dem
Namen der Zeilenquelle für die SELECT-Anweisung – namentlich Shippers für die Shippers-Tabelle.
HINWEIS: Es ist zwar eine gute Praxis, den Namen des Stammelementes von den anderen Elementen im XML-Dokument verschieden zu benennen, allerdings beweisen die SaveDBQueryAsXmlToFile-Prozedur und deren in Abbildung 12.1 dargestellte Ausgabe, dass Sie mit einem SqlXmlCommand-Objekt auch XML-Dokumente generieren können, deren Stammelement den gleichen
Namen wie die anderen Elemente besitzt.
464
Kapitel 12
677.book Page 465 Thursday, December 5, 2002 2:26 PM
Abbildung 12.1: Die Ausgabe der SaveDBQueryAsXmlToFile-Prozedur wurde mit einem Browser im
Windows-Explorer geöffnet
Erstellen von XML-Dokumenten mit einem kommentierten
Schema
Ein kommentiertes Schema macht es möglich, dass Sie das Format von Resultsets angegeben können. Bei Angabe einer FOR XML-Klausel in einer SELECT-Anweisung erscheinen die Spaltenwerte
im Resultset stets als Attribute.
Das folgende XML-Skript zeigt ein kommentiertes Schema für die Shippers-Tabelle. Das Schema
trägt den Namen Shippers1.xsd und befindet sich im Stammordner des XMLSamples-Projekt. Nach
der ersten XML-Dokumentdeklarierung (denken Sie daran, dass das XSD-Schema ein XML-Dokument ist), spezifiziert das Listing zwei Namespaces für die Formulierungen im Schema. Der erste
Namespace verweist auf die Site des World Wide Web Consortium für die XML-Schemaspezifikation.
Der zweite Namespace verweist auf einen universellen Ressourcennamen (URN) von Microsoft für
die Zuordnung von kommentierten Schemas.
Der Hauptbereich des Schemas beginnt mit der Deklaration eines Elements namens Shipper. Dieses
Element verfügt über das Kommentarattribut sql:relation, welches dieses Element an die Datenquelle
Shippers bindet. Wenn eine Anwendung mit einer Verbindung zur Northwind-Datenbank dieses
Schema referenziert, kann die Anwendung Zeilen aus der Shippers-Tabelle entsprechend dem Format des Schemas abfragen. Das Schema definiert die Formatierung der ShipperID-Spaltenwerte als
Attribute und CompanyName und Phone als Elemente. Der Einsatz des sequence-Elementes
bewirkt, dass das CompanyName-Element für jeden Shipper-Eintrag vor dem Phone-Element stehen
muss.
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:sql="urn:schemas-microsoft-com:mapping-schema">
<xs:element name="Shipper" sql:relation="Shippers">
<xs:complexType>
<xs:sequence>
<xs:element name="CompanyName" type="xs:string" />
<xs:element name="Phone" type="xs:string" />
</xs:sequence>
<xs:attribute name="ShipperID" type="xs:int" />
Programmieren von XML mit Visual Basic .NET
465
677.book Page 466 Thursday, December 5, 2002 2:26 PM
</xs:complexType>
</xs:element>
</xs:schema>
Sie können ein kommentiertes Schema zusammen mit einem SqlXmlCommand-Objekt verwenden,
um ein Resultset aus der Shippers-Tabelle der Northwind-Datenbank zurückzugeben, und Sie können das Resultset lokal ablegen, wenn Sie dieses als XML-Dokument in einer Datei speichern. Wenn
Sie ein kommentiertes Schema zur Formatierung eines von einem SqlXmlCommand-Objekt zurückgegebenen Resultset verwenden sollen, müssen Sie den Ort der Schemadatei in einer der SqlXmlCommand-Eigenschaften angeben. Geben Sie den Pfad auf das Schema mit der SchemaPath-Eigenschaft an. Sie können den Pfad entweder als absolute oder als relative Adresse angeben. Wenn Sie
eine relative Adresse verwenden, ist die Adresse relativ zur .exe-Datei der .NET-Anwendung, die sich
im \Bin-Unterordner des Projektstammordners befindet. Wenn Sie also das Schema im Stammordner
der Anwendung abspeichern, sollten Sie die SchemaPath-Eigenschaft wie folgt setzen ../Schemaname.xsd. Die Zeichen ../ geben das dem \Bin-Unterordner übergeordnete Verzeichnis an, welches
der Stammordner der Anwendung ist. Wenn Sie die SchemaPath-Eigenschaft verwenden, müssen
Sie die CommandText-Eigenschaft für das SqlXmlCommand-Objekt mit einem XPath-Ausdruck
angeben. Wenn Sie nur eine einzelne Tabelle zurückgeben wollen und das Schema nur eine Tabelle
bezeichnet, kann der XPath-Ausdruck sehr einfach aufgebaut sein. Führen Sie einfach die äußersten
Elemente im Schema auf. In unserem Fall ist dies Shipper.
Die RunAnnotatedSchemaXPathQuery-Prozedur zeigt die Syntax für die Generierung eines XMLDokumentes anhand des kommentierten Schemas Shippers1.xsd. Ungeachtet vieler Ähnlichkeiten
mit dem vorangegangenen Beispiel unterscheiden sich diese doch in mehreren Gesichtspunkten. Die
wichtigsten Unterschiede wurden in Fettschrift dargestellt. Beachten Sie, dass das SqlXmlCommand-Objekt aus diesem Beispiel über eine SchemaPath-Eigenschaft verfügt. Sie können dieser
Eigenschaft einen Zeichenfolgenwert zuweisen, um auf den Ort des kommentierten Schemas hinzuweisen. Als nächstes gibt die CommandType-Eigenschaft eine XPath-Abfrage an. Die CommandText-Eigenschaft definiert die Abfrage in Form eines XPath-Ausdrucks. Neben diesen Unterschieden
sind alle weiteren Änderungen kosmetischer Natur oder sind wenigstens nicht wesentlich. Die wichtigste dieser geringfügigen Änderungen ist im Pfad und Dateinamen für die Speicherung des vom
SqlXmlCommand-Objekt generierten XML-Dokumentes zu finden. In diesem Beispiel lautet der
Dateiname myShippersFROMANNOTATEDSCHEMA.xml. Auf Grund des vom vorangegangenen
Beispiel verschiedenen Namens können Sie die Ausgabe der beiden Beispiele unmittelbar miteinander vergleichen.
Sub RunAnnotatedSchemaXPathQuery()
' Angeben einer Verbindungszeichenfolge für SqlXmlCommand.
Dim cnn1String As String = _
"Provider=SQLOLEDB;Server=(local);" & _
"database=Northwind;" & _
"Integrated Security=SSPI"
' Angeben der Verbindung für das SqlXmlCommand-Objekt cmd1.
Dim cmd1 As SqlXmlCommand = _
New Microsoft.Data.SqlXml.SqlXmlCommand(cnn1String)
' Bezeichnen des Stammelements für die XML-Datei.
cmd1.RootTag = "Shippers"
' Angeben einer XPath-Abfrage auf der Basis eines
' kommentierten Schemas, das das Shipper-Element
466
Kapitel 12
677.book Page 467 Thursday, December 5, 2002 2:26 PM
' aus dem Schema Shippers1.xsd verwendet, welches sich
' im übergeordneten Verzeichnis der
' EXE-Datei der Anwendung befindet.
cmd1.SchemaPath = ("..\Shippers1.xsd")
cmd1.CommandType = SqlXmlCommandType.XPath
cmd1.CommandText = "Shipper"
' Benennen der Datei für das XML-Resultset, danach
' Instantiieren eines Stream-Objektes für die
' Inhalte der Datei.
Dim myXMLfile As String = _
"c:\SQL Server Development with VBDotNet\" & _
"Chapter12\myShippersFROMANNOTATEDSCHEMA.xml"
Dim myFileStream As New System.IO.FileStream _
(myXMLfile, System.IO.FileMode.Create)
' Ausführen von cmd1 und Speichern des Resultsets
' im Stream-Objekt bevor das Stream-Objekt geschlossen wird.
cmd1.ExecuteToStream(myFileStream)
myFileStream.Close()
End Sub
Die Abbildung 12.2 zeigt das XML-Dokument, das mit der RunAnnotatedSchemaXPathQuery-Prozedur abgespeichert wurde. Beachten Sie, dass dieses Dokument ein anderes Format aufweist als das
Dokument auf der Grundlage einer SELECT-Anweisung mit einer FOR XML-Klausel. Tatsächlich
hat das Dokument aus Abbildung 12.2 das Format, welches vom vorigen kommentierten Schema
definiert wurde. Sie können das Schema anpassen, um nur eine Teilmenge von Spaltenwerten zu
erfassen, oder die Elemente anders anordnen oder die Spaltenwerte austauschen, die als Elemente
und Attribute dargestellt werden. Der Einsatz einer XPath-Abfrage mit einem kommentierten Schema
versetzt Sie also in die Lage, das Format des XML-Dokumentes angeben zu können.
Abbildung 12.2: Die Ausgabe
der RunAnnotatedSchemaXPathQuery-Prozedur
wurde im Windows-Explorer
mit einem Browser geöffnet
Programmieren von XML mit Visual Basic .NET
467
677.book Page 468 Thursday, December 5, 2002 2:26 PM
Erstellen kommentierter Schemata
Bis jetzt haben Sie erfahren, wie flexibel kommentierte Schemata sind. Sie könnten sich nun fragen,
ob es eine einfache Möglichkeit gibt, um diese mit Visual Studio .NET zu erstellen. Als Entwickler
haben Sie die Wahl zwischen wenigstens ein paar Techniken für die Erstellung kommentierter Schemata und deren Implementierung in Ihre Anwendungen.
Erstellen eines Schemas mit Code
Nehmen wir an, dass Ihnen bereits ein Schema zur Verfügung steht, z. B. Shippers1.xsd, das mit
einem anderen Texteditor entwickelt wurde. Es wäre sinnvoll, den Text des kommentierten Schemas
nach Visual Studio .NET zu kopieren, um das Schema zu optimieren und im Verzeichnis der Anwendung abzuspeichern. Visual Studio .NET bietet zu diesem Zweck einen XML-Designer. Wählen Sie
aus dem Menü Projekt von Visual Studio .NET den Befehl Neues Element hinzufügen und wählen
Sie aus dem Dialogfeld Neues Element hinzufügen die Vorlage XML-Schema, um ein neues Fenster
im XML-Designer zu öffnen. Akzeptieren Sie den vorgeschlagenen Namen oder geben Sie einen
neuen Namen ein, z. B. Shippers2. Der Designer wird automatisch die .xsd-Dateinamenserweiterung
hinzufügen und die Schemadatei im Stammordner der aktuellen Anwendung abspeichern. Falls
gewünscht, können Sie dieses Verhalten außer Kraft setzen.
HINWEIS: Die Speicherung von kommentierten Schemadateien und anderen Ressourcendateien im
Ordner der Anwendung erleichtert die Bereitstellung. Die Bereitstellung wird erleichtert, da sich
alle Dateien in einem gemeinsamen Ordner befinden, den Sie auf andere Computer kopieren können.
Der XML-Designer unterstützt die Anzeige eines Schemas in zwei Ansichten – einer grafischen in der
Schema-Ansicht und einer textbasierten in der XML-Ansicht. Sie können die gewünschte Ansicht
über die Registerkarten im unteren Bereich des Fensters wählen. Um ein neues Schema von Grund
auf zu erstellen, sollten Sie zur XML-Ansicht wechseln. Die Vorlage fügt automatisch eine Deklaration des Dokumenttyps hinzu sowie verschiedene andere Namespace- und diesbezügliche Einstellungen. Sie können weitere Einstellungen hinzufügen oder vorhandene entsprechend Ihren Erfordernissen anpassen. Um ein Beispiel zu geben, Sie können die Deklaration eines benutzerdefinierten
Namespaces hinzufügen, um spezielle Attribute und Elementnamen zu definieren. Beginnen Sie mit
der Eingabe des neuen Schemas nach der letzten Namespacedeklaration und vor dem abschließenden Schematag (</xs:schema>).
Wenn Sie den Text eines bereits existierenden Schemas in den Designer kopieren wollen, sollten Sie
den Text in die Zwischenablage von Windows kopieren und dann zu Visual Studio .NET wechseln.
Zeigen Sie die XML-Ansicht eines neuen Designerfensters an. In Abhängigkeit von der Quelle des
Originalschemas werden Sie das kopierte Schema editieren müssen. Eckige Klammern (< und >)
könnten beispielsweise als XML-Steuerzeichen < und > dargestellt werden. Dieses Erfordernis
ist mir besonders beim Kopieren von Beispielen aus der Visual Studio .NET-Dokumentation aufgefallen. Sie können die Option Ersetzen aus dem Menü Bearbeiten unter Suchen und Ersetzen in Visual
Studio .NET wählen, um alle Steuerzeichen in < und > zu ändern. Die Abbildung 12.3 zeigt die XMLAnsicht eines kopierten Schemas bei der Bearbeitung.
468
Kapitel 12
677.book Page 469 Thursday, December 5, 2002 2:26 PM
Abbildung 12.3: Die XML-Ansicht eines kopierten Schemas kurz vor dem Ersetzen des Steuerzeichens
< mit <
Grafische Erstellung eines Schemas
Einige Leser könnten die Tatsache begrüßen, dass Visual Studio .NET kommentierte Schemas mit
grafischen Techniken erstellen kann. Wieder werden Sie mit einer neuen Vorlage beginnen. Der
Name des ersten Schemas, das Sie in einem Projekt erstellen, wird XMLSchema1.xsd lauten, es sei
denn, Sie definieren einen benutzerdefinierten Namen. Der Zähler wird für jedes nachfolgende
Schema, das Sie mit der Standardnamenskonvention zum Projekt hinzufügen, um eins erhöht.
Öffnen Sie im neuen Fenster des XML-Designers die Schema-Ansicht und wählen Sie dann aus dem
Menü Ansicht den Befehl Server-Explorer. Expandieren Sie im Fenster Server-Explorer den Knoten
Server und den Server, den Sie verwenden wollen, expandieren Sie dann SQL Server und die
gewünschte SQL Server-Instanz, und wählen Sie dann die Datenbank auf dieser Serverinstanz aus.
Expandieren Sie Tabellen, um die Tables-Ansammlung aus der Datenbank als Quelle für das Schema
anzugeben. Ziehen Sie dann eine oder mehrere Tabellen aus dem Fenster Server-Explorer auf die
Schema-Ansicht Ihres neuen Schemas, XMLSchema1.xsd. Die Abbildung 12.4 zeigt das Schema
XMLSchema1.xsd nachdem die Shippers-Tabelle aus der Northwind-Datenbank einer SQL ServerInstanz namens CCS1 angegeben wurde. Die grafische Ansicht zeigt die Definition eines ShippersEintrags in einem Dokument. Die Definition des Primärschlüssels ist erkennbar – beachten Sie das
Symbol eines Schlüssels neben dem ShipperID-Element in der Definition der Entität Shippers.
Dieses grafisch erstellte Schema kommt Ihren Erfordernissen zwar sehr nahe, erfordert allerdings
eine geringfügige Optimierung für die Verwendung mit einem SqlXmlCommand-Objekt. Sie können
diese Anpassung in der XML-Ansicht vornehmen. Das folgende Listing entspricht dem Schema aus
Abbildung 12.4 in der XML-Ansicht. Die Zeilen der Elemente ShipperID, CompanyName und
Phone werden jeweils mit einem Zeilenumbruch dargestellt. Im Designer erscheint jedes dieser Elemente als eine lange Zeile. Die in fett dargestellten Zeilen müssen entfernt werden. Diese zu entfernenden Zeilen werden in der XML-Ansicht des Designers nicht in Fettschrift dargestellt. Wenn Sie
die Zeilen mit fett dargestelltem Text löschen und das Schema als XMLSchema1.xsd abspeichern,
erstellen Sie ein Schema, das Sie wie das manuell erstellte Schema Schippers1.xsd verwenden können. Die Anweisungen zum Editieren des Schemas führen zur Entfernung des Document-Feldes und
der Primärschlüsselangabe für ShipperID aus der Schema-Ansicht von XMLSchema1.xsd.
Programmieren von XML mit Visual Basic .NET
469
677.book Page 470 Thursday, December 5, 2002 2:26 PM
Abbildung 12.4: Die ursprüngliche grafische Ansicht der Shippers-Tabelle, die von der NorthwindDatenbank auf das Schema XMLSchema1.xsd gezogen wurde.
HINWEIS: Das grafisch generierte Schema verwendet keine speziellen SQLXML-XSD-Kommentarattribute, wie sql:relation, denn grafisch generierte kommentierte Schemata können über die Verbindung des SqlXmlCommand-Objektes eine Verbindung herstellen und die Namen der Elemente
und Attribute mit denen der Quelldatenbankobjekte synchronisieren. Um ein Beispiel zu geben,
der Elementname Shippers entspricht der Shippers-Tabelle aus der Northwind-Datenbank. Auf
ähnliche Weise entsprechen die Namen ShipperID, CompanyName und Phone den Spaltennamen aus der Shippers-Tabelle.
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema id="XMLSchema1" targetNamespace="http://tempuri.org/XMLSchema1.xsd"
elementFormDefault="qualified"
xmlns="http://tempuri.org/XMLSchema1.xsd"
xmlns:mstns="http://tempuri.org/XMLSchema1.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="Document">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="Shippers">
<xs:complexType>
<xs:sequence>
<xs:element name="ShipperID" msdata:ReadOnly="true"_
470
Kapitel 12
677.book Page 471 Thursday, December 5, 2002 2:26 PM
msdata:AutoIncrement="true" type="xs:int" />
<xs:element name="CompanyName" type="xs:string" />
<xs:element name="Phone"_
type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:unique name="DocumentKey1" msdata:PrimaryKey="true">
<xs:selector xpath=".//mstns:Shippers" />
<xs:field xpath="mstns:ShipperID" />
</xs:unique>
</xs:element>
</xs:schema>
Für die Generierung von XML-Dokumenten auf der Grundlage der Inhalte aus der Shippers-Tabelle
der Northwind-Datenbank habe ich eine Prozedur namens RunNETGeneratedSchemaXPathQuery
erstellt. Diese Prozedur ist mit dem Schema RunAnnotatedSchemaXPathQuery, das weiter oben
angegeben wurde, mit Ausnahme zweier Zeilen identisch. Die beiden zu ersetzenden Zeilen werden
an dieser Stelle angegeben. Beachten Sie, dass das neue Beispiel ein anderes Schema verwendet, als
das vorige Beispiel. Darüber hinaus wurde die CommandText-Eigenschaft von Shipper zu Shippers
geändert. Dies ist erforderlich, denn das Schema XMLSchema1.xsd verwendet Shippers, um den
Elementnamen für Shipper-Einträge anzugeben, wogegen Shipper1.xsd den Namen Shipper verwendete. Würden Sie die CommandText-Eigenschaft des SqlXmlCommand-Objekts nicht anpassen,
würde die XPath-Abfrage aus dem Beispiel fehlschlagen.
cmd1.SchemaPath = ("..\XMLSchema1.xsd")
cmd1.CommandText = "Shippers"
Das komplette Listing der RunNETGeneratedSchemaXPathQuery-Prozedur ist in den Beispieldateien zu diesem Buch zu finden.
Dynamische Angabe von XML-Resultsets
Der vorangegangene Abschnitt konzentrierte sich auf die Erstellung von XML-Resultsets auf der
Grundlage einer festen Quelle, z. B. allen Zeilen und allen Spalten aus der Shippers-Tabelle. Diese
allgemeine Strategie hat den Vorteil, dass die Ressourcen aus der Remotedatenbank lokal gespeichert
werden. Die Beispiele aus diesem Abschnitt erweitern die Funktionalität der Beispiele aus dem vorangegangenen Abschnitt, um Datenquellen zu unterstützen, die dynamisch zur Laufzeit definiert
werden. Sie können lokale XML-Dokumente abfragen, die Sie entweder mit der aktuellen Prozedur
temporär oder zuvor mit einer anderen Prozedur erstellt haben. Das erste Beispiel aus diesem
Abschnitt erstellt ein spezifisches XML-Dokument und speichert dieses lokal ab, bevor das Dokument mit einem bestimmten XPath-Ausdruck abgefragt wird. Das zweite Bespiel aus diesem
Abschnitt verdeutlicht die temporäre Erstellung von XML-Dokumenten und deren Abfrage auf beliebige Art und Weise.
Der Einsatz eines XML-Dokumentes als Quelle Ihrer Abfragen eliminiert die Abhängigkeit von einer
Verbindung zum Datenbankserver. Es gibt allerdings Situationen, in denen Ihre Anwendung auf die
aktuellsten Daten zugreifen muss (in denen deshalb ein lokales XML-Dokument ungeeignet ist). Die
Programmieren von XML mit Visual Basic .NET
471
677.book Page 472 Thursday, December 5, 2002 2:26 PM
abschließenden Beispiele aus diesem Abschnitt demonstrieren zwei fortschreitend flexiblere Strategien
für die Abfrage einer Remotedatenbank von SQL Server und die Anzeige der Ergebnisse mit XML.
Ausführen einer XPath-Abfrage für ein spezifisches
XML-Dokument
Sie können ein Resultset nicht nur in einem XML-Dokument speichern, Sie können das Dokument
auch direkt verwenden und abfragen. Wenn Sie mit einem XML-Dokument arbeiten, können Sie dieses jedoch nicht mit einer SQL-Anweisung abfragen. In dieser Situation stellt XPath eine ideale
Lösung dar, um ein Resultset abzuleiten, das bestimmten Kriterien entspricht. Das Beispiel aus diesem Abschnitt, RunXPathQueryWithArgumentForALocalDocument, fragt ein lokales Dokument
ab. Die Prozedur erstellt ein Dokument anhand der Products-Tabelle aus der Northwind-Datenbank.
Danach extrahiert die Prozedur die Knoten, deren Discontinued-Wert gleich 1 ist. Dieser Wert signalisiert, dass das entsprechende Produkt nicht mehr länger für den Verkauf verfügbar ist.
Die Prozedur beginnt mit der Verwendung einer SELECT-Anweisung mit FOR XML-Klausel, um alle
Zeilen aus der Products-Tabelle der Northwind-Datenbank zu extrahieren. Statt die ExecuteToStream-Methode, wie im Beispiel aus dem vorangegangenen Abschnitt demonstriert, zu verwenden,
wird in diesem Beispiel die ExecuteXmlReader-Methode des SqlXmlCommand-Objekts aufgerufen.
Wie bereits erwähnt liefert diese Methode ein XMLReader-Objekt (xrd1) zurück, welches den
schnellen, vorwärtsgerichteten, nicht zwischengespeicherten Zugriff auf das Stream-Objekt ermöglicht, das die XML-Daten enthält. Statt der Speicherung des XML-Dokumentes in einem FileStreamObjekt, wie in den Beispielen aus dem vorangegangenen Abschnitt, stellt dieses Beispiel die XMLDaten über ein XMLReader-Objekt zur Verfügung. Der nächste Schritt ist die Erstellung eines XMLDokumentes auf der Grundlage der Inhalte des XMLReader-Objekts. Die Prozedur erledigt dies in
zwei Schritten. Erstens, es wird ein XMLDocument-Objekt deklariert, xdc1. Zweitens, die Prozedur
ruft die Load-Methode für das Dokument mit dem XMLReader-Objekt als Argument auf. Unmittelbar nach dem Füllen des XML-Dokumentes mit dem XMLReader-Objekt schließt die Prozedur das
XMLReader-Objekt, um dessen Ressourcen so schnell wie möglich wieder freizugeben.
Das Laden des XML-Dokumentes mit dem XMLReader-Objekt stellt die XML-Daten aus der
SELECT-Anweisung im Arbeitsspeicher bereit. Wäre die Aktualität der Daten kein Problem (weil die
Daten sich nur selten oder nie ändern) könnten Sie das xdc1-Objekt mit einer zuvor abgespeicherten
Kopie des XML-Dokumentes laden. (Ein nachfolgendes Beispiel demonstriert die Syntax für diese
Vorgehensweise.) Das Beispiel aus dem vorangegangenen Abschnitt demonstrierte, wie XML-Daten
von einem Remoteserver lokal abgelegt werden können.
Mithilfe eines XPath-Ausdrucks generiert die Prozedur ein XmlNodeList-Objekt (xnl1), welches, wie
bereits erwähnt, eine Ansammlung von Knoten aus einem Dokument darstellt. Die Ansammlung entspricht in unserem Fall dem XPath-Ausdruck aus der RunXPathQueryWithArgumentForALocalDocument-Prozedur. Ein Knoten ist ein XPath-Objekt aus einem Dokument. Dieses Objekt kann
Elemente, Attribute und andere Features von XML-Dokumenten umfassen. Denken Sie daran, dass
das XML-Dokument in diesem Fall das Resultset einer SELECT-Anweisung mit einer FOR XMLKlausel aus der Prozedur darstellt.
Die XPath-Anweisung liefert alle Elemente zurück, deren Discontinued-Attribut einem Wert von 1
entspricht. Der XPath-Ausdruck wird auf alle Knoten im XML-Dokument angewendet, denn die
Konten werden anhand der DocumentElement-Eigenschaft ausgewählt, welche das Stammelement
des XML-Dokumentes beinhaltet. Nach der Erstellung des XmlNodeList-Objekts greift die Prozedur
auf die Liste der Knoten zweimal zu. Erstens, es wird die Anzahl der Knoten in xnl1 bestimmt. Zweitens, die Prozedur gibt die XML-Daten der einzelnen Knoten in xnl1 aus.
472
Kapitel 12
677.book Page 473 Thursday, December 5, 2002 2:26 PM
Sub RunXPathQueryWithArgumentForALocalDocument()
' Angeben einer Verbindungszeichenfolge für SqlXmlCommand.
Dim cnn1String As String = _
"Provider=SQLOLEDB;Server=(local);" & _
"database=Northwind;" & _
"Integrated Security=SSPI"
' Angeben einer Verbindung für das SqlXmlCommand-Objekt cmd1.
Dim cmd1 As SqlXmlCommand = _
New Microsoft.Data.SqlXml.SqlXmlCommand(cnn1String)
' Bezeichnen der Datenquelle für cmd1 mit
' einem Resultset in XML-Format.
cmd1.RootTag = "Products"
cmd1.CommandType = SqlXmlCommandType.Sql
cmd1.CommandText = "SELECT * FROM Products FOR XML AUTO"
' Übergeben des Resultsets von cmd an einen XmlReader und
' Laden eines XmlDocument-Objekts mit den
' Inhalten des XmlReader–Objekts.
Dim xrd1 As System.Xml.XmlReader = cmd1.ExecuteXmlReader()
Dim xdc1 As New System.Xml.XmlDocument()
xdc1.Load(xrd1)
' Schließen des XmlReader–Objekts.
xrd1.Close()
' Angeben einer XPath-Abfrage für die Knoten
' aus dem XmlDocument xdc1 mit einem
' Discontinued-Wert von 1.
Dim xnl1 As System.Xml.XmlNodeList = _
xdc1.DocumentElement.SelectNodes _
("//Products[@Discontinued=1]")
' Deklarieren eines Knotens und einer Zeichenfolge.
Dim xnd1 As System.Xml.XmlNode
Dim str1 As String
' Anzeigen einer Meldung für jeden Knoten, um die Inhalte,
' einschließlich der XML-Tags anzuzeigen.
Debug.WriteLine( _
"Die Anzahl von Zeilen in diesem Resultset ist " & _
xnl1.Count.ToString & ".")
For Each xnd1 In xnl1
str1 = xnd1.OuterXml
Debug.WriteLine(str1)
Next
End Sub
Die Abbildung 12.5 zeigt einen Ausschnitt aus dem Ausgabefenster mit den von der RunXPathQueryWithArgumentForALocalDocument-Prozedur generierten Ergebnissen. Die Abbildung zeigt acht
Produkte aus dem anhand der Products-Tabelle erstellten XML-Dokument an, deren DiscontinuedWert 1 ist. Die ProductID-Spaltenwerte der nicht mehr verfügbaren Produkte lauten 5, 9, 17, 24, 28,
29, 42 und 53. Beachten Sie, dass die ProductID-Spaltenwerte als XML-Attributswerte dargestellt
Programmieren von XML mit Visual Basic .NET
473
677.book Page 474 Thursday, December 5, 2002 2:26 PM
werden. Dies entspricht der Tatsache, dass die Prozedur die OuterXML-Anweisung aufruft, um die
tatsächlichen XML-Daten für jeden einzelnen Knoten von xnl1 auszugeben.
Abbildung 12.5: Die RunXPathQueryWithArgumentForALocalDocument-Prozedur liefert
XML-Informationen zu nicht mehr länger verfügbaren Produkten zurück
Ausführen einer XPath-Abfrage für beliebige XML-Dokumente
Das vorangegangene Beispiel ist interessant, denn es demonstriert eine praktische Einsatzmöglichkeit
für XML-Dokumente auf der Grundlage von Datenbankobjekten. Insbesondere können Sie Datenbankinhalte über eine lokale Kopie aus einem XML-Dokument verarbeiten. Allerdings funktioniert
das Beispiel aus dem vorangegangenen Abschnitt mit nur einem XML-Dokument. Damit das Beispiel
auch mit einem anderen XML-Dokument eingesetzt werden kann, müssen Sie die interne Struktur
der Prozedur analysieren und bestimmte Codezeilen ändern. Dies ist schwierig. Es wäre viel besser,
wenn Sie Parameter übergeben könnten, um das XML-Dokument und die Abfrage zu definieren,
damit die Prozedur ein passendes Resultset generieren kann. Das Beispiel aus diesem Abschnitt
demonstriert, wie eine derartige Lösung programmiert werden kann.
Ich habe zwei Codeabschnitte entwickelt, um die Beispielprozedur aus diesem Abschnitt aufzurufen.
Der erste Codeabschnitt führt die gleiche XPath-Abfrage für das gleiche XML-Dokument aus dem
vorangegangenen Beispiel aus. Der Unterschied besteht darin, dass dieses Beispiel die SQL-Informationen für die Definition des Dokumentes und die Definition der XPath-Abfrage für das Dokument
als Argumente übergibt. Es ist nicht überraschend, dass der Aufruf der Prozedur in diesem Abschnitt
das gleiche Resultset wie das Beispiel aus dem vorangegangenen Abschnitt generiert.
Der zweite Codeblock verwendet die gleiche Prozedur, um eine andere XPath-Abfrage für ein anderes
XML-Dokument auszuführen. Es ist zwar nicht verwunderlich, dass wir unterschiedliche Ergebnisse
mit der gleichen Prozedur erhalten, das Beispiel ist aber dennoch interessant, denn es demonstriert,
wie einfach es ist, dieses Verhalten mit einer XPath-Abfrage und einem XML-Dokument zu erreichen
– beide sind typischen Visual Basic-Entwicklern unbekannt.
Der erste Codeblock besteht aus drei Codezeilen. Die erste Zeile weist der Zeichenfolgenvariablen
strSQL einen Wert zu. Diese Speichervariable enthält die SQL-Zeichenfolge für das Resultset, welche
von der RunXPathQueryWithArgumentForAnyLocalDocument-Prozedur verwendet wird, um ein
XML-Dokument zu füllen. Die zweite Codezeile weist der Zeichenfolgenvariablen strXPath einen
Wert zu. Diese Variable speichert die XPath-Abfrage für das von der Prozedur generierte XML-Dokument. Durch die Anwendung dieser XPath-Abfrage auf das XML-Dokument wird das Resultset generiert. Ein mögliches Resultset ist in Abbildung 12.5 dargestellt. Die letzte Codezeile aus dem ersten
Codeblock übergibt die Variablen strSQL und strXPath an die RunXPathQueryWithArgumentForAnyLocalDocument-Prozedur. Die Prozedur führt wiederum die SQL-Abfrage aus und füllt das
474
Kapitel 12
677.book Page 475 Thursday, December 5, 2002 2:26 PM
XML-Dokument mit dem Resultset. Zum Abschluss listet die Prozedur die Knoten im Ausgabefenster
auf.
Dim strSQL As String = "SELECT * FROM Products FOR XML AUTO"
Dim strXPath As String = "//Products[@Discontinued=1]"
RunXPathQueryWithArgumentForAnyLocalDocument(strSQL, strXPath)
Der zweite Codeblock für den Aufruf der RunXPathQueryWithArgumentForAnyLocalDocumentProzedur wird als nächstes dargestellt. Da dieser Abschnitt die gleichen Variablen verwendet, wie der
vorangegangene, sollten Sie wenigstens einen dieser Blöcke auskommentieren, um einen Kompilierungsfehler auf Grund einer doppelten Deklaration der Variablen zu vermeiden. Bei diesem Kommentar ging ich davon aus, dass beide Codeabschnitte in der gleichen Prozedur existieren, wie das in
der Prozedur main von Module1 aus dem XMLSamples-Projekt der Fall ist. Der zweite Codeblock
definiert über die SQL-Zeichenfolge ein anderes XML-Dokument als der erste Codeblock. Das XMLDokument aus dem ersten Codeabschnitt beinhaltete eine Liste von Produkten. Das XML-Dokument
des zweiten Codeabschnitts enthält hingegen eine Liste von Angestellten. Darüber hinaus ändert sich
die XPath-Abfrage, um eine bestimmte Teilmenge von Angestellten zu ermitteln. Der wichtigste
Punkt des zweiten Codeblocks ist, dass Sie eine beliebige SQL-Zeichenfolge verwenden können, um
ein XML-Dokument zu erstellen, und dann eine passende XPath-Abfrage, um dieses abzufragen. Sie
erreichen diese Flexibilität ohne den internen Code der RunXPathQueryWithArgumentForAnyLocalDocument-Prozedur anpassen zu müssen. Sie können diese Anwendung unmittelbar erweitern,
wenn Sie eine Liste von vorformulierten SQL-Abfrageanweisungen mit dazugehörigen XPath-Abfrageanweisungen bereitstellen. Auf diese Weise können Sie die Aufgabe der Generierung und Verwendung von XML-Dokumenten erheblich vereinfachen.
Dim strSQL As String = "SELECT * FROM Employees FOR XML AUTO"
Dim strXPath As String = "//Employees[@EmployeeID>4]"
RunXPathQueryWithArgumentForAnyLocalDocument(strSQL, strXPath)
Ungeachtet der wesentlich erweiterten Anwendungsflexibilität ist die Prozedur aus diesem Abschnitt
annähernd mit derjenigen aus dem vorangegangenen Abschnitt identisch. Der Hauptunterschied
besteht darin, dass zwei Zeichenfolgenvariablen – strSQL und strXPath – übergeben werden. Darüber hinaus ändert die Prozedur die Zuweisung der RootTag-Eigenschaft, damit diese nicht an eine
Liste von Produkten sondern an eine Liste von beliebigen Entitäten gebunden wird. Die Anwendung
verwendet stets eine Verbindung zur Northwind-Datenbank. Sie können die Verbindungszeichenfolge allerdings ebenfalls parametrisieren, um noch größere Anwendungsflexibilität zu erzielen. Zu
guter Letzt sollten Sie die Verbindungszeichenfolge ändern, damit diese auf eine passende Datenbank
ihrer Anwendung verweist.
Sub RunXPathQueryWithArgumentForAnyLocalDocument( _
ByVal strSQL As String, ByVal strXPath As String)
' Angeben einer Verbindungszeichenfolge für SqlXmlCommand.
Dim cnn1String As String = _
"Provider=SQLOLEDB;Server=(local);" & _
"database=Northwind;" & _
"Integrated Security=SSPI"
' Angeben einer Verbindung für das SqlXmlCommand-Objekt cmd1.
Dim cmd1 As SqlXmlCommand = _
New Microsoft.Data.SqlXml.SqlXmlCommand(cnn1String)
Programmieren von XML mit Visual Basic .NET
475
677.book Page 476 Thursday, December 5, 2002 2:26 PM
' Bezeichnen der Datenquelle für cmd1 mit
' einem Resultset in XML-Format.
cmd1.RootTag = "MyRoot"
cmd1.CommandType = SqlXmlCommandType.Sql
cmd1.CommandText = strSQL
' Übergeben des Resultsets von cmd an einen XmlReader und
' Laden eines XmlDocument-Objekts mit den
' Inhalten des XmlReader–Objekts.
Dim xrd1 As System.Xml.XmlReader = cmd1.ExecuteXmlReader()
Dim xdc1 As New System.Xml.XmlDocument()
xdc1.Load(xrd1)
' Schließen des XmlReader–Objekts.
xrd1.Close()
' Angeben einer XPath-Abfrage für die Knoten
' aus dem XmlDocument xdc1.
Dim xnl1 As System.Xml.XmlNodeList = _
xdc1.DocumentElement. _
SelectNodes(strXPath)
' Deklarieren eines Knotens und einer Zeichenfolge.
Dim xnd1 As System.Xml.XmlNode
Dim str1 As String
' Anzeigen einer Meldung für jeden Knoten, um die Inhalte,
' einschließlich der XML-Tags anzuzeigen.
Debug.WriteLine( _
"Die Anzahl von Zeilen im Resultset ist " & _
xnl1.Count.ToString & ".")
For Each xnd1 In xnl1
str1 = xnd1.OuterXml
Debug.WriteLine(str1)
Next
End Sub
Ausführen parametrisierter SQL Server-Abfragen
Unter Umständen werden Ihre Anwendungen nicht in der Lage sein, XML-Dokumente als Datenquelle zu verarbeiten, da auf die aktuellsten Daten zugegriffen werden muss. In diesem Fall können
Sie eine parametrisierte SQL Server-Abfrage verwenden. Der Parameter aus der Abfrageanweisung
gibt Ihren Benutzern die Möglichkeit, ein Resultset für eine bestimmte Abfrage zur Laufzeit angeben
zu können. Die SQLXML-verwalteten Klassen aus den Web-Releases 2 und 3 ermöglichen diese Art
von Abfragen. Das Beispiel aus diesem Abschnitt demonstriert den Einsatz der Klasse SqlXmlParameter. Die Verwendung von Parametern in SQL-Anweisungen ist beispielsweise für Prototyptests von
SQL-Code für gespeicherte Prozeduren nützlich, oder in Fällen, in denen Ihnen keine gespeicherte
Prozedur mit den Parametern zur Verfügung steht, die Sie benötigen, um eine Aufgabe auszuführen.
Das Beispiel aus diesem Abschnitt hat darüber hinaus den Zweck, Sie an die Techniken zur Angabe
von Parametern in SQL-Anweisungen zu erinnern, und zu verdeutlichen, wie StreamReader-Objekte
verwendet werden, um das Resultset einer Abfrage zu erfassen. Das Beispiel RunSQLParameterQuery beginnt mit der Angabe einer Verbindungszeichenfolge und der Instantiierung eines SqlXml-
476
Kapitel 12
677.book Page 477 Thursday, December 5, 2002 2:26 PM
Command-Objektes auf der Grundlage dieser Zeichenfolge. Als nächstes setzt das Beispiel
ausgewählte SqlXmlCommand-Eigenschaften, um die auszuführende Abfrage zu definieren.
Beispielsweise wird die CommandText-Eigenschaft auf eine SQL-Zeichenfolge gesetzt, die einen
Parameter mit einem Fragezeichen (?) angibt. Die Benutzer können das SqlXmlCommand-Objekt
ausführen, um die in der Liste der SELECT-Anweisung angegebenen Informationen zu ermitteln. Der
Wert des Country-Parameters bezeichnet das Land, für das das SqlXmlCommand-Objekt Ergebnisse
zurückgeben soll. Im Listing der Prozedur wurde der Wert für den Country-Parameter mit Brazil fest
codiert. Die Syntax für die Parameterzuweisung erfordert die Deklaration eines SqlXmlParameterObjektes, den Aufruf der CreateParameter-Methode des SqlXmlCommand-Objektes sowie eine
Zuweisungsanweisung für die Value-Eigenschaft des SqlXmlParameter-Objektes.
Dieses Beispiel demonstriert außerdem noch eine weitere Möglichkeit zur Erfassung der XML-Daten,
die vom SqlXmlCommand-Objekt zurückgegeben werden. Im vorliegenden Fall übergibt das Beispiel das Resultset der Abfrage mit dem SqlXmlParameter-Objekt an ein Dialogfeld zur Anzeige. Die
ExecuteStream-Methode des SqlXmlParameter-Objektes erstellt ein MemoryStream-Objekt mit den
XML-Daten, die von der über die CommandText-Eigenschaft angegebene Abfrage erstellt werden.
Der Einsatz des MemoryStream-Objektes als Argument zur Instantiierung eines StreamReaderObjektes versetzt die Prozedur in die Lage, die vom SqlXmlParameter-Objekt generierten XMLDaten als Zeichenfolge zu erfassen. Die ReadToEnd-Methode des StreamReader-Objektes liefert
eine Zeichenfolge mit allen XML-Daten zurück, die vom SqlXmlParameter-Objekt generiert wurden. Unter Verwendung der Anweisung srd1.ReadToEnd als Argument für die MsgBox-Funktion
zeigt die Prozedur die vom SqlXmlParameter-Objekt generierten XML-Daten an.
Sub RunSQLParameterQuery()
' Angeben einer Verbindungszeichenfolge für SqlXmlCommand.
Dim cnn1String As String = _
"Provider=SQLOLEDB;Server=(local);" & _
"database=Northwind;" & _
"Integrated Security=SSPI"
' Angeben einer Verbindung für das SqlXmlCommand-Objekt cmd1.
Dim cmd1 As SqlXmlCommand = _
New Microsoft.Data.SqlXml.SqlXmlCommand(cnn1String)
' Bezeichnen der Datenquelle für cmd1 mit einem Parameter.
cmd1.RootTag = "Customers"
cmd1.CommandType = SqlXmlCommandType.Sql
cmd1.CommandText = "SELECT ContactName, " & _
"CompanyName, City " & _
"FROM Customers " & _
"WHERE Country = ?For XML Auto"
' Erstellen eines Parameters für cmd1 und
' Zuweisen eines Wertes an diesen Parameter.
Dim prm1 As SqlXmlParameter
prm1 = (cmd1.CreateParameter())
prm1.Value = "Brazil"
' Deklarieren und Instantiieren eines Streams im
' Arbeitsspeicher und füllen des Streams mit dem
' XML-Resultset von cmd1.
Dim stm1 As New System.IO.MemoryStream()
stm1 = cmd1.ExecuteStream()
' Kopieren des Resultsets aus dem Stream in einen
Programmieren von XML mit Visual Basic .NET
477
677.book Page 478 Thursday, December 5, 2002 2:26 PM
' StreamReader und Anzeige der Streaminhalte in
' einem Dialogfeld.
Dim srd1 As New System.IO.StreamReader(stm1)
MsgBox(srd1.ReadToEnd)
srd1.Close()
End Sub
Parametrisieren beliebiger SQL-Abfragen
Genauso, wie Sie das zu verarbeitende XML-Dokument parametrisieren können, können Sie das
vorangegangene Beispiel auch erweitern, um die Abfrage zu parametrisieren, statt nur eine bestimmte
Abfrage zu verwenden. Der Trick zur Ausführung dieser Aufgabe ist, sowohl die Abfrage als auch die
Parameterwerte an die Prozedur zu übergeben, die die Abfrage ausführen soll. Auf der anderen Seite
muss die Prozedur zur Ausführung der Abfrage aus dem vorangegangenen Beispiel angepasst werden,
um diese Parameter zu akzeptieren und diese zur Generierung einer Zeichenfolge für das Dialogfeld
zu verwenden, welches die Ergebnisse am Ende der Prozedur anzeigt.
Der folgende Codeblock zeigt den Setupcode, der erforderlich ist, bevor die Prozedur zur Ausführung
der Abfrage und zur Anzeige der Ergebnisse in einem Dialogfeld aufgerufen werden kann. Beachten
Sie, dass der Setupcode eine andere Abfrage angibt, als das Beispiel aus dem vorangegangenen
Abschnitt. Die Abfrage aus diesem Abschnitt ist für die Shippers-Tabelle bestimmt. Die Abfrage aus
dem vorangegangenen Abschnitt verwendete die Customers-Tabelle. Nichtsdestoweniger ist der
Code für die Ausführung der Abfrage annähernd in beiden Abschnitten der gleiche. Wichtiger ist die
Tatsache, dass Sie eine Abfrage für jede beliebige Tabelle und Kombinationen von Tabellen ausführen
können, ohne Änderungen an der RunSQLParameterQueryWithPassedParams-Prozedur vornehmen zu müssen. Ihre Anwendung muss nur zwei Zuweisungen vornehmen – eine für die Zeichenfolgenvariable zur Angabe der Abfrage (strSQL) und eine andere für die Zeichenfolge zur Angabe eines
Parameterwertes (strPrm1Value).
Dim strSQL As String = "SELECT * FROM Shippers " & _
"WHERE ShipperID = ?For XML Auto"
Dim strPrm1Value As String = "1"
RunSQLParameterQueryWithPassedParams( _
strSQL, strPrm1Value)
Das folgende Listing zeigt den Code der RunSQLParameterQueryWithPassedParams-Prozedur. Die
Zeilen, die im Vergleich zur RunSQLParameterQuery-Prozedur aus dem vorigen Abschnitt geändert
wurden, sind in Fettschrift dargestellt. Beachten Sie, dass nur vier Zeilen geändert wurden. Diese dienen hauptsächlich der Aufnahme und Verwendung der übergebenen Zeichenfolgenvariablen, die die
Abfragesyntax und den Parameterwert angeben. Die Zuweisung der RootTag-Eigenschaft wurde
ebenfalls geändert, um beliebige SQL-Abfragezeichenfolgen zu unterstützen. Neben diesen geringfügigen Änderungen braucht die vorige Prozedur nicht weiter angepasst zu werden, um diese mit beliebigen SQL-Abfragezeichenfolgen verwenden zu können.
Sub RunSQLParameterQueryWithPassedParams( _
ByVal strSQL As String, _
ByVal strPrm1Value As String)
' Angeben einer Verbindungszeichenfolge für SqlXmlCommand.
Dim cnn1String As String = _
"Provider=SQLOLEDB;Server=(local);" & _
"database=Northwind;" & _
478
Kapitel 12
677.book Page 479 Thursday, December 5, 2002 2:26 PM
"Integrated Security=SSPI"
' Angeben einer Verbindung für das SqlXmlCommand-Objekt cmd1.
Dim cmd1 As SqlXmlCommand = _
New Microsoft.Data.SqlXml.SqlXmlCommand(cnn1String)
' Bezeichnen der Datenquelle für cmd1 mit einem Parameter.
cmd1.RootTag = "MyRoot"
cmd1.CommandType = SqlXmlCommandType.Sql
cmd1.CommandText = strSQL
' Erstellen eines Parameters für cmd1 und
' Zuweisen eines Wertes an diesen Parameter.
Dim prm1 As SqlXmlParameter
prm1 = (cmd1.CreateParameter())
prm1.Value = strPrm1Value
' Deklarieren und Instantiieren eines Streams im
' Arbeitsspeicher und füllen des Streams mit dem
' XML-Resultset von cmd1.
Dim stm1 As New System.IO.MemoryStream()
stm1 = cmd1.ExecuteStream()
' Kopieren des Resultsets aus dem Stream in einen
' StreamReader und Anzeige der Streaminhalte in
' einem Dialogfeld.
Dim srd1 As New System.IO.StreamReader(stm1)
MsgBox(srd1.ReadToEnd)
srd1.Close()
End Sub
Das Zusammenspiel von XML und DataSets
XML-Dokumente und ADO.NET-Datasets arbeiten in vielen Szenarien zusammen. Ein Verständnis
dieses Zusammenspiels und Kenntnisse über diese Szenarien können Ihnen bei der Abfrage und Verarbeitung von Daten auf der lokalen Clientarbeitsstation und auf einem Datenbankserver helfen. Dieser Abschnitt bietet eine Auswahl von Beispielen, die verdeutlichen, wie XML-Dokumente mit DataSets zu diesem Zweck eingesetzt werden können. Wie schon bei vielen anderen Themen in diesem
Buch ist auch diese Präsentation nicht als allumfassende Abhandlung aller möglichen Gesichtspunkte zu diesem Thema gedacht. Stattdessen zielt dieser Abschnitt darauf ab, eine feste Grundlage
zu vermitteln, die dazu befähigt, weiterzugehen und mehr zu lernen, in welcher Richtung auch immer
Ihr Bedarf liegt.
Erstellen hierarchischer XML-Dokumente
Einer der wirklich wertvollen Aspekte von DataSet-Objekten in ADO.NET ist, das diese Objekte auf
XML aufbauen. Dies bedeutet, dass Sie die Elemente in einem Dataset verarbeiten und dabei indirekt
XML-Strukturen modifizieren können. Dieses Feature ist insbesondere dann nützlich, wenn Sie mit
Zeilenquellen arbeiten, die sich aus mehreren Tabellen zusammensetzen und über Eltern/KindBeziehungen verfügen, denn dieses Feature befreit den Entwickler von der Darstellung dieser komplexen Beziehungen in einem XSD-Schema. ADO.NET und XML sind zwar relativ neue Technolo-
Programmieren von XML mit Visual Basic .NET
479
677.book Page 480 Thursday, December 5, 2002 2:26 PM
gien für Visual Basic-Entwickler, das Objektmodell für DataSets in ADO.NET erleichtert jedoch die
Verständlichkeit für all diejenigen, die über Kenntnisse im Umgang mit Objekten verfügen. Das
Kapitel 10 enthält einen allgemeinen Überblick zu den Objekten von ADO.NET. Die Abbildung
10.1 in Kapitel 10 bietet einen Überblick über das DataSet-Objektmodell und zahlreiche Codebeispiele demonstrieren in Kapitel 10 verschiedene ADO.NET-Programmierthemen, einschließlich
des DataSet-Objekts und dessen hierarchisch abhängigen Objekte.
Ein DataSet-Objekt und dessen dazugehöriges XML-Dokument sind zwei Seiten der gleichen
Münze. Mit der WriteXml-Methode des DataSet-Objekts können Sie sowohl die Inhalte eines XMLDokuments als auch das dem Dokument zugrunde liegende Schema abspeichern. Verfügt das Dataset
über Änderungen, die noch nicht in die Remotedatenbank übernommen wurden, können Sie darüber
hinaus mit der WriteXml-Methode Diffgramme erstellen, die das Dataset mit sämtlichen noch nicht
ausgeführten Änderungen repräsentieren. Denken Sie daran, dass Diffgramme die aktuellen sowie
die vorhergehenden Werte beinhalten. Diffgramme stehen unmittelbar zur Verfügung, denn
ADO.NET übermittelt die Änderungen vom Client an die SQL Server-Instanz in Form von Diffgrammen.
Das Beispiel aus diesem Abschnitt demonstriert, wie Sie ein Dataset mit drei Hierarchieebenen auf
der Grundlage dreier Tabellen aus der Northwind-Datenbank erstellen können. Diese Tabellen sind
die Customers-, Orders- und Order Details-Tabellen. Individuelle Kunden sind die übergeordneten
Elemente individueller Bestellungen und Bestellungen sind wiederum den Details zu den (oder den
Einzelposten der) Bestellungen übergeordnet. Diese Art von verschachtelten Beziehungen wird von
XML-Dokumenten besonders gut repräsentiert, denn das Dokument gibt die tatsächliche Verschachtelung statt eines einzelnen flachen Rowsets wieder.
Das Beispiel stützt sich auf zwei Prozeduren. Die erste Prozedur SaveThreeTierDasAsXmlDocument ruft die zweite Prozedur auf, die ein Dataset generiert und dieses dann als XML-Dokument
ablegt. Unter Verwendung der WriteXml-Methode vermeidet die SaveThreeTierDasAsXmlDocument-Prozedur den Einsatz von SQLXML-verwalteten Klassen. Dies bedeutet, dass die in diesem
Kapitel demonstrierten Techniken relativ robust aufgebaut sind, denn diese können mit einer beliebigen Datenquelle, auf die ADO.NET zugreifen kann, eingesetzt werden. Darüber hinaus erfordern die
Prozeduren, die den Einsatz von DataSet-Objekten demonstrieren, weder die Installation von WebRelease 2 noch von Web-Release 3, was bei Einsatz verwalteter Klassen erforderlich wäre. Die zweite
Prozedur, CreateThreeTierDataSet, ist eine Function-Prozedur, welche ein Dataset-Objekt an die
aufrufende Prozedur zurückgibt. Dieses Dataset wird von der ersten Prozedur als XML-Dokument in
einer Datei abgespeichert.
Die SaveThreeTierDasAsXmlDocument-Prozedur beginnt mit der Instantiierung eines DataSetObjekts und der Füllung dieses Objekts mit dem von der Function-Prozedur CreateThreeTierDataSet zurückgelieferten DataSets. Nach der Füllung des DataSets bereitet die Prozedur die Speicherung
der Daten in einer Datei mit Unicode-Zeichen vor. Diese Aktion erfordert mehrere Schritte. Die Prozedur beginnt diesen Prozess mit der Zuweisung des Namens des XML-Dokuments an eine Zeichenfolgenvariable (str1). Als nächstes instantiiert die Prozedur ein FileStream-Objekt (fst1), um mit der
Datei zu arbeiten, in der das XML-Dokument abgespeichert wird. Danach instantiiert die Prozedur
ein XmlTextWriter-Objekt (txw1), um die XML-Daten aus dem Dataset in das FileStream-Objekt zu
kopieren. Die WriteXml-Methode verwendet txw1 als eines von zwei Argumenten, um die XMLDaten aus dem Dataset in eine Datei zu kopieren. Das andere Argument, welches im vorliegenden
Fall auf XmlWriteMode.WriteSchema gesetzt wurde, legt fest, wie die WriteXml-Methode die
Inhalte aus dem Dataset in der Datei abspeichern soll. Das Argument XmlWriteMode.WriteSchema
gibt an, dass die WriteXml-Methode mit dem Kopieren des Schemas des Dokumentes beginnen und
nach dem Schema mit den Inhalten des XML-Dokumentes fortsetzen soll. Nach dem Schreiben des
480
Kapitel 12
677.book Page 481 Thursday, December 5, 2002 2:26 PM
Dokuments gibt die Prozedur die Ressourcen frei und übergibt die Kontrolle an die Prozedur durch
Schließen des XmlTextWriter- und des FileStream-Objekts.
Die CreateThreeTierDataSet-Prozedur beginnt mit der Instantiierung eines Verbindungsobjekts. Dieses Objekt wird geöffnet, um eine Verbindung zur Northwind-Datenbank herzustellen. Die Prozedur
instantiiert als nächstes ein DataSet-Objekt (das1) und verwendet das Verbindungsobjekt, um ein
SqlDataAdapter-Objekt (dap1) mit der Customers-Tabelle aus der Northwind-Datenbank zu verknüpfen. Danach kopiert die Prozedur über einen Aufruf der Fill-Methode des dap1-Objektes die
Zeilen aus der Customers-Tabelle in ein DataTable-Objekt von das1 namens Customers. Nachdem
die Customers-Tabelle aus der Northwind-Datenbank zum Dataset das1 hinzugefügt wurde, verweist die Prozedur dap1 auf die Orders-Tabelle aus der Northwind-Datenbank. Nun wird die
Orders-Tabelle zu das1 hinzugefügt. Die Prozedur wiederholt diesen Prozess ein drittes und letztes
Mal, um in das1 das DataTable-Objekt OrderDetails mit den Spaltenwerten aus der Order DetailsTabelle der Northwind-Datenbank zu erstellen.
Nach diesen drei Aufrufen der Fill-Methode beinhaltet das Dataset das1 drei nicht miteinander in
Beziehung stehende Tabellen. Wir benötigen ein DataRelation-Objekt, um die hierarchischen Beziehungen zwischen den Tabellen anzugeben. In der Tat benötigt das1 zwei DataRelation-Objekte. Ein
DataRelation-Objekt drückt die Beziehungen zwischen den DataTable-Objekten Customers und
Orders aus. Ein zweites DataRelation-Objekt repräsentiert die Beziehungen zwischen den DataTable-Objekten Orders und OrderDetails. Die Prozedur erstellt das erste DataRelation-Objekt über
einen Aufruf der Add-Methode der Relations-Ansammlung des DataSets das1. Das erste Argument,
welches das DataRelation-Objekt benennt, wurde auf den Wert CustOrders gesetzt. Die nächsten
beiden Argumente identifizieren die Spalten, die verwendet werden sollen, um die beiden Datentabellen miteinander zu verknüpfen. Durch Setzen der Nested-Eigenschaft des DataRelation-Objektes
auf True veranlassen Sie die verschachtelte Darstellung der Bestellungen innerhalb der Kunden im
XML-Dokument. Der Standardwert der Nested-Eigenschaft ist False. In diesem Fall würde die WriteXml-Methode zwei Sätze von Spaltenwerten ohne Verschachtelung der Werte aus der einen Tabelle
mit den Werten aus der anderen Tabelle darstellen. Mit einem zweiten Aufruf der Add-Methode der
Relations-Ansammlung des DataSets das1 erstellt die Prozedur die zweite Datenbeziehung, um die
Eltern/Kind-Struktur zwischen den DataTable-Objekten Orders und OrderDetails anzugeben. Zum
Abschluss wird die Return-Anweisung der CreateThreeTierDataSet-Prozedur aufgerufen, um das
Dataset das1 an die aufrufende Prozedur zu übergeben.
Sub SaveThreeTierDasAsXmlDocument()
' Deklarieren und Instantiieren des DataSet das1
' und Füllen von das1 mit dem von der Function-Prozedur
' zurückgegebenen Dataset.
Dim das1 As New DataSet()
das1 = CreateThreeTierDataSet()
' Deklarieren einer Zeichenfolge für den Dateinamen,
' um ein FileStream-Objekt anhand eines XmlTextWriters mit
' den Inhalten des DataSets das1 abzuspeichern.
Dim str1 As String = _
"c:\SQL Server Development with VBDotNet\" & _
"Chapter12\myCustomersSchema.xml"
Dim fst1 As New System.IO.FileStream _
(str1, System.IO.FileMode.Create)
Dim txw1 As New System.Xml.XmlTextWriter _
(fst1, System.Text.Encoding.Unicode)
' Schreiben der XML-Daten von das1 zusammen mit dem Schema.
Programmieren von XML mit Visual Basic .NET
481
677.book Page 482 Thursday, December 5, 2002 2:26 PM
das1.WriteXml(txw1, XmlWriteMode.WriteSchema)
' Schließen von TextWriter und FileStream.
txw1.Close()
fst1.Close()
End Sub
Function CreateThreeTierDataSet()
' Öffnen einer Verbindung zur Northwind-Datenbank.
Dim cnn1 As SqlConnection = _
New SqlConnection( _
"Data Source=localhost;" & _
"Initial Catalog=northwind;" & _
"Integrated Security=SSPI")
cnn1.Open()
' Deklarieren und Instantiieren eines DataSets (das1).
Dim das1 As DataSet = New DataSet("CustomerOrders")
' Deklarieren und Instantiieren eines DataAdapter (dap1), um
' das DataTable-Objekt Customers von das1 zu füllen.
Dim dap1 As SqlDataAdapter = _
New SqlDataAdapter( _
"SELECT CustomerID, CompanyName, ContactName, Phone " & _
"FROM Customers", cnn1)
dap1.Fill(das1, "Customers")
' Wiederverwenden von dap1, um
' das DataTable-Objekt Orders von das1 zu füllen.
dap1.SelectCommand.CommandText = _
"SELECT OrderID, OrderDate, CustomerID FROM Orders"
dap1.Fill(das1, "Orders")
' Wiederverwenden von dap1, um
' das DataTable-Objekt OrderDetails von das1 zu füllen.
dap1.SelectCommand.CommandText = _
"SELECT * FROM [Order Details]"
dap1.Fill(das1, "OrderDetails")
' Schließen der Verbindung.
cnn1.Close()
' Angeben einer Beziehung zwischen den DataTable-Objekten
' Customers und Orders mit den Orders-Elementen
' verschachtelt in den Customers-Elementen.
das1.Relations.Add("CustOrders", _
das1.Tables("Customers").Columns("CustomerID"), _
das1.Tables("Orders").Columns("CustomerID")). _
Nested = True
' Angeben einer Beziehung zwischen den DataTable-Objekten
' Orders und OrderDetails mit den OrderDetails-Elementen
' verschachtelt in den Orders-Elementen.
das1.Relations.Add("OrderDetail", _
482
Kapitel 12
677.book Page 483 Thursday, December 5, 2002 2:26 PM
das1.Tables("Orders").Columns("OrderID"), _
das1.Tables("OrderDetails").Columns("OrderID"), _
False).Nested = True
Return das1
End Function
Wenn die SaveThreeTierDasAsXmlDocument-Prozedur die WriteXml-Methode mit dem zweiten
Parameter gleich XmlWriteMode.WriteSchema aufruft, schreibt die Methode eigentlich zwei statt
nur einem Dokument. Das dem XML-Argument entsprechende XSD-Schema erscheint vor den
eigentlichen Daten. Die .NET-Dokumentation spricht bei dieser Art von Schema von einem InlineSchema, denn es wird zusammen mit den nachfolgenden XML-Daten in der Datei abgelegt. Das
Schema für das XML-Dokument von das1 ist hinreichend komplex, denn es spezifiziert die Spalten
aus drei Tabellen, zwei Angaben zu Datenbeziehungen und unterstützende Elemente, wie Einschränkungen, um die DataRelation-Objekte zu aktivieren. Die Abbildung 12.6 und die Abbildung 12.7
zeigen Ausschnitte aus dem Schema in Browserfenstern. Das Schema ist zu groß, um in ein Fenster
zu passen. Dieses Schema erscheint am Anfang des XML-Dokuments, das in der SaveThreeTierDasAsXmlDocument-Prozedur angegeben wurde. Der Dateiname des XML-Dokuments ist myCustomersSchema.xml aus dem Verzeichnis C:\SQL Server Development with VBDot-Net\Chapter12.
Beim Testen der Anwendung auf Ihrem Computer könnte es erforderlich sein, den Zielordner für das
XML-Dokument zu ändern und einen auf Ihrer Arbeitsstation existierenden Ordner anzugeben.
Abbildung 12.6: Der erste Teil
des Inline-Schemas für ein
XML-Dokument aus der Datei
myCustomersSchema.xml
Programmieren von XML mit Visual Basic .NET
483
677.book Page 484 Thursday, December 5, 2002 2:26 PM
Abbildung 12.7: Der zweite Teil
des Inline-Schemas für ein
XML-Dokument aus der Datei
myCustomersSchema.xml
Wie Sie aus der Größe und Komplexität des Schemas erkennen können, ist es von Wert, das Schema
automatisch anlegen zu können. Die Erstellung eines DataSets mit Programmcode sollte an dieser
Stelle im Buch keine Schwierigkeit mehr darstellen. Auf jeden Fall ist es sehr wahrscheinlich, dass
Sie den Komfort der programmatischen Erstellung von DataSets bei der Programmierung von
Anwendungen mit ADO.NET bald schätzen werden. Die Verwendung eines programmatisch erstellten DataSets als Grundlage für ein Schema könnte deshalb ein sinnvoller Ansatz sein, wenn Sie sich
nicht mit dem Aufbau eines XSD-Schemas von Grund auf auskennen. In der Tat könnte die Generierung eines Schemas und die Zuordnung dieses Schemas zum Design eines DataSets eine Möglichkeit
darstellen, wie Sie mit Visual Basic .NET die XSD-Syntax erlernen können, sodass Sie bald Ihre eigenen komplexen Schemata von Grund auf erstellen können. Die Abbildung 12.8 zeigt einen Ausschnitt mit dem Anfang der XML-Daten aus der Datei myCustomersSchema.xml. Die gesamte erste
Bestellung (OrderID 10643) ist zu erkennen sowie der Anfang der zweiten Bestellung (OrderID
10692) des Kunden mit einem CustomerID-Wert von ALFKI. Beachten Sie, wie die Bestellungen mit
den Kunden verschachtelt wurden. Außerdem wurden die Einzelposten, oder Details, zu den Bestellungen mit den Bestellungen verschachtelt.
484
Kapitel 12
677.book Page 485 Thursday, December 5, 2002 2:26 PM
Abbildung 12.8: Ein Ausschnitt mit dem Anfang der XML-Daten aus der Datei
myCustomersSchema.xml
Abfragen von untergeordneten Daten aus einem Dataset
mit XPath
Das hierarchische Design des DataSets das1 aus dem vorigen Beispiel stellt eine Quelle dar, die für
eine Demonstration der Abfrage von untergeordneten Daten mit der XPath-Abfragesyntax geeignet
ist. Wie bereits erwähnt, verfügt das Dataset über Detailinformationen zu den Bestellungen, die den
Bestellungen untergeordnet sind, die wiederum den Kunden untergeordnet sind. In Abbildung 12.8
ist der erste UnitPrice-Wert von 45,6 eine untergeordnete Information der ersten Bestellung mit
einem OrderID-Wert von 10643. Diese OrderID gehört zu dem Kunden mit dem CustomerID-Wert
ALFKI. Die XPath-Abfragesyntax ermöglicht Ihnen die Erstellung eines Resultsets für die Kunden
auf der Basis beliebiger untergeordneter Werte, z. B. UnitPrice. Das Beispiel aus diesem Abschnitt
veranschaulicht, wie derartige XPath-Abfragen aufgebaut werden. Das Beispiel vermittelt darüber
hinaus, wie die Knoten in einem Resultset aufgelistet werden. XPath-Abfragen liefern zwar auch eine
Ansammlung von Knoten in einem XmlNodeList-Objekt zurück, die Aufzählung enthält jedoch die
einzelnen Werte ohne die zusätzlichen XML-Tags, welche die Werte in einem XML-Dokument voneinander abtrennen.
Die RunXPathQueryForThreeTierXmlDocument-Prozedur, welche das Beispiel aus diesem
Abschnitt implementiert, beginnt mit der Instantiierung eines neuen DataSets namens das1. Dieses
Dataset wird dann mit den verschachtelten Daten gefüllt, die mit der CreateThreeTierDataSet-Funktion erstellt wurden. (Siehe den vorangegangenen Abschnitt für ein Listing dieser Function-Proze-
Programmieren von XML mit Visual Basic .NET
485
677.book Page 486 Thursday, December 5, 2002 2:26 PM
dur.) Da ADO.NET für jedes Dataset automatisch ein XML-Dokument erstellt, können Sie entweder
das Dataset oder das zugrunde liegende XML-Dokument abfragen und identische Resultsets erhalten.
Die RunXPathQueryForThreeTierXmlDocument-Prozedur vermittelt eine Strategie zur Verarbeitung des XML-Dokumentes eines DataSets. Nach der Füllung des DataSets instantiiert die Prozedur
ein neues XmlDataDocument-Objekt (xdc1) auf der Grundlage des DataSets das1. Die XmlDataDocument-Klasse ist eine Erweiterung der XmlDocument-Klasse, mit der .NET-Anwendungen die
XML-Daten eines DataSets in ein XML-Dokument laden können. XmlDataDocument-Objekte
ermöglichen den Einsatz von W3C-Verarbeitungstechniken für XML-Dokumente in Anwendungen,
z. B. XPath-Abfragen. Die Prozedur demonstriert diese Möglichkeit unter Verwendung einer XPathAbfrage, die alle Kundenknoten auswählt, deren untergeordnete Informationen einen UnitPrice-Wert
von größer als 100 beinhalten.
Mit dem XPath-Ausdruck wird ein XmlNodeList-Objekt (xnl1) anhand der Struktur des mit dem
abgefragten XmlDataDocument-Objekt verknüpften DataSets erstellt. Die Verknüpfung zwischen
dem XmlDataDocument-Objekt und dem Dataset das1 ermöglicht die Auswahl einzelner Werte
jedes Knotens aus dem XmlNodeList-Objekt als Spaltenwerte eines DataRow-Objektes aus dem
DataSet-Objektmodell. In der Prozedur wird die Implementierung dieses Ansatzes durch die Deklarierung des DataRow-Objektes (myRow) vorbereitet. Bevor mit einer Schleife begonnen wird, liefert
die Prozedur die Anzahl von Konten aus der Knotenliste xnl1 zurück. Die Schleife verwendet eine
For Each-Anweisung, um nacheinander alle Knoten aus xnl1 zu durchlaufen. Die GetRowFromElement-Methode übernimmt einzelne Werte aus dem aktuellen Knoten in das DataRow-Objekt
myRow. Die Methode übernimmt die Werte ohne jegliche XML-Tags. Sobald die Werte eines Knotens
als Spaltenwerte im myRow-Objekt zur Verfügung stehen, erstellt die Prozedur eine Zeichenfolge aus
den ersten vier Spaltenwerten. Das Schema aus Abbildung 12.6 bestätigt, dass die Spalten den Werten für CustomerID, CompanyName, ContactName und Phone entsprechen. Die letzte Anweisung
aus der Schleife gibt die vier Spaltenwerte im Ausgabefenster aus.
Sub RunXPathQueryForThreeTierXmlDocument()
' Deklarieren und Instantiieren des DataSets das1
' und Füllen des DataSets mit dem von der Function' Prozedur CreateThreeTierDataSet zurückgegebenen Dataset.
Dim das1 As New DataSet()
das1 = CreateThreeTierDataSet()
' Deklarieren und Instantiieren eines XmlDataDocument-Objekts
' auf der Grundlage der Inhalte von das1.
Dim xdc1 As System.Xml.XmlDataDocument = _
New XmlDataDocument(das1)
' Generieren eines Resultsets mit allen Kunden, die
' Produkte mit einem UnitPrice von größer als 100
' bestellt haben.
Dim xnl1 As XmlNodeList = _
xdc1.DocumentElement.SelectNodes( _
"descendant::Customers" & _
"[Orders/OrderDetails/UnitPrice>100]")
' Deklarieren von Objekten für eine Schleife durch das Resultset.
Dim myRow As DataRow
Dim xnd1 As XmlNode
Dim str1 As String
486
Kapitel 12
677.book Page 487 Thursday, December 5, 2002 2:26 PM
’ Durchlaufen des Resultsets und Ausgeben der Werte
' im Ausgabefenster.
Debug.WriteLine("Es gibt " & _
xnl1.Count.ToString & " in diesem Resultset.")
For Each xnd1 In xnl1
myRow = xdc1.GetRowFromElement(CType(xnd1, XmlElement))
str1 = myRow(0) & ", " & myRow(1) & _
", " & myRow(2) & ", " & myRow(3)
Debug.WriteLine(str1)
Next
End Sub
Die Abbildung 12.9 stellt einen Ausschnitt aus dem Ausgabefenster dar, das die von der Prozedur
RunXPathQueryForThreeTierXmlDocument generierten Werte aufführt. Die erste Zeile aus diesem
Ausschnitt gibt die Anzahl der Kunden wieder, die Posten mit einem UnitPrice-Wert von größer als
100 gekauft haben. Danach listet das Fenster die einzelnen Kunden auf, die diesem Kriterium entsprechen. Für jeden Kunden zeigt die Liste die dazugehörigen Werte für CustomerID, CompanyName, ContactName und Phone an.
Abbildung 12.9: Ein Ausschnitt mit den ursprünglich ausgegebenen Informationen aus der Prozedur
RunXPathQueryForThreeTierXmlDocument
Abfragen von untergeordneten Daten aus einem XML-Dokument
mit XPath
Im Beispiel aus dem vorigen Abschnitt wird ein neues Dataset über einen Aufruf der Prozedur CreateThreeTierDataSet erstellt, mit der das Dataset generiert wurde. Bei Anwendungen, deren Daten
sich nur langsam oder in festen Intervallen ändern, könnten Sie die Leistungsfähigkeit unter Umständen verbessern, wenn Sie eine zuvor abgespeicherte Kopie des XML-Dokumentes des DataSets verwenden. Der Einsatz einer zuvor abgespeicherten Kopie eines XML-Dokumentes kann die Last auf
dem Datenbankserver verringern und die Reaktionszeit der Anwendung verbessern. Die bereits
erwähnte Prozedur SaveThreeTierDasAsXmlDocument speichert XML-Dokumente auf der Grundlage der gleichen verschachtelten Datenstruktur ab, die von der CreateThreeTierDataSet-Prozedur
generiert wurde. Die das XML-Dokument beinhaltende Datei heißt myCustomersSchema.xml und
der Pfad auf die Datei lautet C:\SQL Server Development with VBDotNet\Chapter12. Wenn Sie
den Dateinamen des Dokuments oder dessen Pfad zwecks Tests auf Ihrem System angepasst haben,
werden Sie diese Informationen im Beispiel zu diesem Abschnitt ebenfalls ändern müssen.
Das Beispiel aus diesem Abschnitt stützt sich auf zwei Prozeduren. Die erste Prozedur
RunXPathQueryForSavedThreeTierXmlDocument verarbeitet das in myCustomersSchema.xml
Programmieren von XML mit Visual Basic .NET
487
677.book Page 488 Thursday, December 5, 2002 2:26 PM
abgespeicherte XML-Dokument. Die zweite Prozedur MyTagValue extrahiert die Tagwerte aus einer
Zeichenfolge. Die Zeichenfolge enthält Werte, die durch XML-Tags voneinander getrennt sind. Die
Zeichenfolgenwerte, die an die MyTagValue-Prozedur übergeben werden, entsprechen den Knoten,
die von der XPath-Abfrage zurückgegeben werden.
Die RunXPathQueryForSavedThreeTierXmlDocument-Prozedur beginnt mit der Instantiierung
eines XML-Dokuments, xdc1. Danach wird die zuvor abgespeicherte Datei myCustomersSchema.xml geladen. Die Prozedur verwendet ein XmlTextReader-Objekt, um auf das XML-Dokument in der Datei myCustomersSchema.xml zuzugreifen, den Stammknoten zu öffnen und die
Daten aus der Datei in das Objekt xdc1 zu laden.
Nach dem Laden des zuvor abgespeicherten XML-Dokumentes führt das Beispiel die gleiche XPathAbfrage aus, wie das vorangegangene Beispiel. Die Syntax der XPath-Abfrage aus diesem Beispiel ist
zwar mit dem vorangegangenen Beispiel identisch, die Quelle der Abfrage unterscheidet sich aber in
mehreren wichtigen Gesichtspunkten. Erstens, die Quelle dieses Beispiels erfordert keine Zugriffe auf
den Datenbankserver, denn es wird mit einer lokal abgespeicherten Datei gearbeitet, die das XMLDokument enthält. Wenn der Datenbankserver oder die Verbindung temporär nicht zur Verfügung
stehen, kann diese lokale Ressource die Robustheit der Anwendung wesentlich verbessern. Zweitens,
es gibt kein Dataset für das zugrunde liegende XML-Dokument. Dies bedeutet, dass die von der
XPath-Abfrage zurückgelieferten Knoten Zeichenfolgen ohne dazugehörige Zeilenstruktur darstellen. Dementsprechend muss die Prozedur die Elemente aus den Knoten anders verarbeiten, als das
vorangegangene Beispiel.
Diese Prozedur generiert eine identische Ausgabe, die in Abbildung 12.9 dargestellt ist. Die ausgegebenen Informationen werden jedoch auf andere Weise zusammengestellt, als im vorigen Beispiel. Der
neue Ansatz der Extrahierung von Tagwerten ist erforderlich, denn es gibt keine zugrunde liegende
Zeilenstruktur eines DataSets, um die Extrahierung der Werte zu vereinfachen. Jeder Knoten aus dem
Resultset der XPath-Abfrage aus diesem Beispiel wird als Zeichenfolge dargestellt. Tags trennen die
Tagwerte voneinander in jeder Zeichenfolge ab. In Abbildung 12.8 können Sie erkennen, dass die
Tags <CustomerID> und </CustomerID> den Tagwert ALFKI einschließen. Sie können also jeden
Tagwert über die Angabe des anführenden und abschließenden Tags ermitteln. Unter Verwendung
der Mid-Funktion, können Sie die in den Tags enthaltenen Tagwerte extrahieren. Die Prozeduren
RunXPathQueryForSavedThreeTierXmlDocument und MyTagValue arbeiten zusammen, um die
ersten vier Tagwerte für jeden einzelnen Knoten aus dem Resultset der XPath-Abfrage zu extrahieren.
Die RunXPathQueryForSavedThreeTierXmlDocument-Prozedur übergibt den Tagnamen jedes der
vier ersten Tags eines jeweiligen Knotens und die MyTagValue-Prozedur liefert die Zeichenfolge des
dazugehörigen Tagwertes zurück. Danach fasst die RunXPathQueryForSavedThreeTierXmlDocument-Prozedur die Tagwerte zusammen und gibt diese im Ausgabefenster aus.
Sub RunXPathQueryForSavedThreeTierXmlDocument()
' Die Prozedur verwendet ein gespeichertes Dokument
' anstatt das Dokument mit einem neuen Dataset neu
' zu erstellen.
' Deklarieren und Instantiieren eines XML-Dokumentes.
Dim xdc1 As New System.Xml.XmlDocument()
' Deklarieren und Instantiieren eines Reader-Objekts auf
' der Grundlage eines zuvor gespeicherten XML-Dokuments;
' wechseln zum Stammelement des Dokuments und laden
' der Daten in xdc1.
Dim xrd1 As XmlTextReader = _
New XmlTextReader _
("c:\SQL Server Development with VBDotNet\" & _
488
Kapitel 12
677.book Page 489 Thursday, December 5, 2002 2:26 PM
"Chapter12\myCustomersSchema.xml")
xrd1.MoveToContent()
xdc1.Load(xrd1)
' Schließen des XmlTextReader-Objekts.
xrd1.Close()
' Generieren eines Resultsets mit allen Kunden, die Produkte
' mit einem UnitPrice von größer als 100 bestellt haben.
Dim xnl1 As XmlNodeList = _
xdc1.DocumentElement.SelectNodes( _
"descendant::Customers" & _
"[Orders/OrderDetails/UnitPrice>100]")
' Deklarieren der Objekte für eine Schleife durch das Resultset.
Dim xnd1 As XmlNode
Dim str1, str2 As String
' Durchlaufen des Resultsets und Ausgeben der
' Werte im Ausgabefenster.
Debug.WriteLine("Es gibt " & _
xnl1.Count.ToString & " in diesem Resultset.")
For Each xnd1 In xnl1
' Die inneren XML-Daten des Knotens.
str1 = xnd1.OuterXml
' Den CustomerID-Tagwert bestimmen.
str2 = MyTagValue("CustomerID", str1)
' Den CompanyName-Tagwert bestimmen.
str2 = str2 & ", " & MyTagValue("CompanyName", str1)
' Den ContactName-Tagwert bestimmen.
str2 = str2 & ", " & MyTagValue("ContactName", str1)
' Den Phone-Tagwert bestimmen.
str2 = str2 & ", " & MyTagValue("Phone", str1)
' Ausgeben der ersten vier Tagwerte.
Debug.WriteLine(str2)
Next
End Sub
Function MyTagValue(ByVal TagName As String, _
ByVal strXML As String)
' Deklarieren und Zusammenstellen der
' Konstanten für den jeweiligen Tag.
Dim str1 = "<" & TagName & ">"
Dim str2 = "</" & TagName & ">"
Dim int1, int2 As Integer
int1 = InStr(strXML, str1) + Len(str1)
int2 = InStr(strXML, str2)
Programmieren von XML mit Visual Basic .NET
489
677.book Page 490 Thursday, December 5, 2002 2:26 PM
' Ermitteln und Zurückgeben des Tagwerts;
' strXML ist die Zeichenfolge mit den
' auszuwertenden XML-Daten,
' int1 ist die Startposition,
' int2 - int1 ist die Anzahl der Zeichen.
Dim TagValue As String = Mid(strXML, _
int1, int2 - int1)
Return TagValue
End Function
Verwenden von DataSets zur Aktualisierung von Datenbanken
über Diffgramme
An dieser Stelle sollten Sie verstanden haben, dass Sie mit DataSets und XML-Dokumenten Datenbankoperationen ausführen und identische Ergebnisse erhalten können. Diese allgemeine Regel trifft
auch auf Datenbankaktualisierungen zu. Wie bereits früher in diesem Kapitel erwähnt, aktualisiert
ADO.NET Datenbanken mithilfe von Diffgrammen, welche XML-Dokumente darstellen, die aktuelle
und vorherige Spaltenwerte aus einem DataTable-Objekt eines DataSets separat angeben können.
Wenn eine ADO.NET-Anwendung die Update-Methode eines DataAdapter-Objekts aufruft und ein
Dataset angibt, sendet die Anwendung ein Diffgramm an das auf einem Server ausgeführte .NET Framework. Das .NET Framework versucht wiederum die Aktualisierung mit dem Datenbankserver
durchzuführen und gibt alle erforderlichen Rückgabeinformationen an den Client zurück, z. B. einen
Identity-Wert oder eine Benachrichtigung, dass die Datenbank die Aktualisierung zurückwies, weil
sich ein vorheriger Wert seit der Zeit, da das Dataset ursprünglich gefüllt wurde, geändert hat.
Das Beispiel aus diesem Abschnitt interagiert mit XML auf zwei verschiedenen Wegen. Erstens, es
wird ein kommentiertes Schema verwendet, um die Spaltenwerte anzugeben, die von der Remotedatenquelle zurückgegeben werden sollen. Nach der Abfrage der Werte von der Remotedatenquelle füllt
das Beispiel ein DataTable-Objekt im Dataset auf dem Clientcomputer. Zweitens, das Beispiel aktualisiert einen Spaltenwert im lokalen DataTable-Objekt. Danach generiert die Prozedur ein Diffgramm, das die Änderung enthält, bevor die Update-Methode des DataAdapter-Objektes aufgerufen
wird, um das Diffgramm an den Datenbankserver zu senden. Es ist zwar möglich, mit Diffgrammen
genauso wie mit Updategrammen (siehe Kapitel 6) direkt zu arbeiten, Visual Basic-Entwickler werden es jedoch wahrscheinlich allgemein als bequemer empfinden, das ADO.NET-Objektmodell einzusetzen, um die Werte lokal und auf dem Remoteserver zu aktualisieren.
Das folgende Schemalisting zeigt den Inhalt der Datei EmployeesFirstLastNames.xsd, die im Beispiel zu diesem Abschnitt verwendet wird. Die Datei befindet sich im Stammordner des XMLSamples-Projekts. (Die Zeilen für die Elemente FName und LName wurden mit einem Zeilenumbruch auf
zwei Zeilen dargestellt, denn diese sind für eine einzige Zeile zu lang.) Nach der Deklaration des
Namespaces für das W3C-konforme XSD-Schema und die Zuordnung von Microsoft-Attributen
deklariert das Listing den Namen Emp für das Employees-Objekt auf der Datenbankverbindung. Das
sql:relation-Attribut stellt die Zuordnung zwischen Emp und Employees her. Da das Beispiel auf die
Northwind-Datenbank zugreift, entspricht der Name Emp der Ansammlung abgefragter Werte aus
der Employees-Tabelle. Das Schema gibt FName und LName als Namen im lokalen Dataset an, die
den Spaltenwerten FirstName und LastName aus der Employees-Tabelle auf dem Datenbankserver
zugeordnet sind. Das Attribut sql:field gibt die serverseitigen Spalten an, auf die die Spalten des lokalen DataSets verweisen.
490
Kapitel 12
677.book Page 491 Thursday, December 5, 2002 2:26 PM
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:sql="urn:schemas-microsoft-com:mapping-schema">
<xsd:element name="Emp" sql:relation="Employees">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="FName" _
sql:field="FirstName" type="xsd:string" />
<xsd:element name="LName" _
sql:field="LastName" type="xsd:string" />
</xsd:sequence>
<xsd:attribute name="EmployeeID" type="xsd:integer" />
</xsd:complexType>
</xsd:element>
</xsd:schema>
Die folgende PopulateModifyUpdateWithDiffGram-Prozedur beginnt mit der Angabe einer Verbindungszeichenfolge. Die Verbindungszeichenfolge wird dann verwendet, um ein SqlXmlCommandObjekt zu konstruieren. Die Informationen aus der Verbindungszeichenfolge verweisen auf die
Northwind-Datenbank auf der lokalen Standardinstanz von SQL Server. Als nächstes erstellt die
Prozedur ein lokales Dataset (das1) mit einer Datentabelle namens Emp auf der Grundlage der
Schemadatei EmployeesFirstLastNames.xsd. Dieses Dataset komplettiert die Einrichtung der Datenumgebung für das Beispiel.
Sub PopulateModifyUpdateWithDiffGram()
' Angeben einer Verbindung für das SqlXmlCommand-Objekt cmd1;
' Die Angabe der Verbindung muss den Provider (sqloledb) umfassen.
Dim cmd1 As New SqlXmlCommand("Provider=sqloledb;" & _
"Data Source=(local);" & _
"Initial Catalog=northwind;Integrated Security=SSPI")
' Angeben des SqlXmlCommand-Objekts zur Rückgabe
' des Vor- und Zunamens auf der Grundlage einer XPath-Abfrage.
cmd1.RootTag = "ROOT"
cmd1.CommandText = "Emp"
cmd1.CommandType = SqlXmlCommandType.XPath
cmd1.SchemaPath = "..\EmployeesFirstLastNames.xsd"
' Instantiieren eines SqlXmlAdapter-Objektes unter Verwendung
' des SqlXmlCommand-Objekts.
Dim dap1 As SqlXmlAdapter
dap1 = New SqlXmlAdapter(cmd1)
' Instantiieren eines neuen DataSet-Objekts (das1) und
' Füllen des DataSets via dap1.
Dim das1 As DataSet = New DataSet()
dap1.Fill(das1)
' Editieren des Wertes aus der ersten Spalte der ersten Zeile
' aus dem DataTable-Objekt Emp.
das1.Tables("Emp").Rows(0)(0) = "Nancie"
' Schreiben der XML-Daten als Diffgramm, bevor die
' Änderungen an den Server übermittelt werden.
Dim str1 As String = _
"c:\SQL Server Development with VBDotNet\" & _
Programmieren von XML mit Visual Basic .NET
491
677.book Page 492 Thursday, December 5, 2002 2:26 PM
"Chapter12\myDiffGram.xml"
Dim myFileStream As New System.IO.FileStream _
(str1, System.IO.FileMode.Create)
Dim xtw1 As New System.Xml.XmlTextWriter _
(myFileStream, System.Text.Encoding.Unicode)
das1.WriteXml(xtw1, XmlWriteMode.DiffGram)
' Ausführen der Aktualisierung der serverseitigen
' Datenquelle des DataSets das1; geben Sie keine
' spezifische Datentabelle im Dataset an.
dap1.Update(das1)
End Sub
Nach der Einrichtung der Datenumgebung weist die Prozedur der ersten Spalte aus der ersten Zeile
aus dem DataTable-Objekt Emp einen neuen Wert von Nancie zu. Die Rows-Ansammlung des
DataTable-Objekts Emp ermöglicht den Zugriff auf die Spaltenwerte der einzelne Zeilen innerhalb
des DataTable-Objekts. In der folgenden Zeile,
das1.Tables("Emp").Rows(0)(0) = "Nancie"
bezeichnet der erste Zähler in Klammern nach dem Rows-Schlüsselwort die Zeile und der zweite
Zähler in Klammern die Spalte innerhalb der Zeile. (Die Rows-Ansammlung basiert auf dem Wert 0
für die erste Spalte und die erste Zeile.)
Bevor die Aktualisierung der Northwind-Datenbank mit der Update-Methode des DataAdapterObjektes vorgenommen wird, kopiert die Prozedur das Dataset im Diffgrammformat in eine Datei
namens C:\SQL Server Development With VBDotNet\Chapter12\MyDiffGram.xml auf dem Laufwerk C: des lokalen Computers. Sie können den Namen und das Zielverzeichnis ändern, um Ihrer
Computerkonfiguration zu entsprechen.
Abbildung 12.10: Der
obere Teil aus der Datei
myDiffGram.xml,
die von der
PopulateModifyUpdateWith
DiffGram-Prozedur
generiert wird
492
Kapitel 12
677.book Page 493 Thursday, December 5, 2002 2:26 PM
Die Abbildung 12.10 und die Abbildung 12.11 stellen das mit dem Beispiel aus diesem Abschnitt in
der Datei MyDiffGram.xml erstellte Diffgramm dar. Die Abbildung 12.10 stellt ein Browserfenster
dar, das die obere Hälfte des Diffgramms zeigt und die Abbildung 12.11 zeigt die untere Hälfte des
Diffgramms im Browserfenster. Wie die Abbildung 12.10 verdeutlicht, lautet der Wert des FNameTags der Angestellten mit einem EmployeeID-Wert von 1 Nancie (siehe den oberen Bereich des
Fensters). In Abbildung 12.11 zeigt der before-Abschnitt des Diffgramms (siehe den unteren Bereich
des Fensters) den ursprünglichen Wert aller Änderungen aus dem Dataset, die noch nicht von der
Remotedatenquelle übernommen wurden. Im vorliegenden Beispiel können Sie erkennen, dass der
ursprüngliche Wert des FName-Tags der Angestellten mit einem EmployeeID-Wert von 1 Nancy lautet. Unmittelbar nach dem Aufruf der Update-Methode in der letzten Zeile der PopulateModifyUpdateWithDiffGram-Prozedur ändert sich das Diffgramm von das1. Insbesondere wird der beforeAbschnitt gelöscht, denn das Dataset enthält nun nur noch aktuelle Werte, bis erneut eine Veränderung am lokalen DataTable-Objekt Emp vorgenommen wird.
Abbildung 12.11: Der
untere Teil aus der Datei
myDiffGram.xml,
die von der
PopulateModifyUpdateWith
DiffGram-Prozedur
generiert wird
Sie werden wahrscheinlich die Employees-Tabelle aus der Northwind-Datenbank wiederherstellen
wollen, damit der Vornahme der EmployeeID 1 wieder Nancy statt Nancie lautet. Sie können dies
erreichen, wenn Sie Nancie in der Prozedur PopulateModifyUpdateWithDiffGram in Nancy
ändern und die Prozedur noch einmal ausführen.
HINWEIS: Wie ich bereits erwähnt habe werden es viele Visual Basic .NET-Entwickler vorteilhaft
finden, Datenverarbeitungsaufgaben über DataSet-Objekte auszuführen, statt Diffgramme oder
Updategramme direkt zu kodieren. Die Beispieldateien zu diesem Buch umfassen eine weitere Beispielprozedur, um die Flexibilität und Einfachheit dieser Vorgehensweise noch einmal zu verdeutlichen. Aus Gründen der Kürze wird das Listing zu dieser Prozedur nicht im Buch aufgeführt.
Programmieren von XML mit Visual Basic .NET
493
677.book Page 494 Thursday, December 5, 2002 2:26 PM
Verwenden von Diffgrammen im Web ohne virtuelle
Verzeichnisse
Eines der herausstechendsten Merkmale des vorigen Beispiels ist dessen Robustheit. Beispielsweise
kann ziemlich genau der gleiche Code in ASP.NET-Anwendungen verwendet werden. Darüber
hinaus kann eine ASP.NET-Anwendung Aktualisierungen über das Web unterstützen, ohne dass Sie
hierfür ein virtuelles Verzeichnis für eine Datenbank einrichten müssen. Dadurch wird die Administration Ihrer Webanwendungen vereinfacht.
Mit den folgenden fünf Schritten kann eine ASP.NET-Webanwendung namens XMLWebSample
erstellt werden. Mit diesen Schritten wird das Beispiel aus dem vorangegangenen Abschnitt so angepasst, dass es in einer ASP.NET-Lösung eingesetzt werden kann.
1. Beginnen Sie ein neues ASP.NET-Projekt namens XMLWebSample und fügen Sie eine Referenz
auf den Namespace Microsoft.Data.SqlXml wie weiter oben in diesem Kapitel beschrieben hinzu.
2. Wählen Sie die Standarddatei WebForm1.aspx in der Entwurfsansicht aus und öffnen Sie das
Modul der Seite, indem Sie auf die Seite mit der rechten Maus klicken und den Befehl Code anzeigen wählen. Fügen Sie am oberen Ende des Moduls der Seite folgende Zeile ein: Imports Microsoft.Data.SqlXml.
3. Kopieren Sie den Code aus der Prozedur PopulateModifyUpdateWithDiffGram aus dem vorigen
Projekt in die Page_Load-Ereignisprozedur der XMLWebSample-Anwendung.
4. Erstellen Sie im Stammordner des XMLWebSample-Projektes ein Schema, wie in EmployeesFirstLastNames.xsd. Sie können den XML-Designer für diese Aufgabe wie weiter oben in diesem
Kapitel beschrieben verwenden. (Es ist wahrscheinlich am einfachsten, das Schema in der XMLQuellansicht zu öffnen und die existierenden XML-Daten mit den XML-Daten aus der Datei EmployeesFirstLastNames.xsd aus den Beispieldateien zu diesem Buch zu ersetzen.) Nennen Sie das
Schema EmployeesFirstLastNames.xsd.
5. Ändern Sie die Einstellung der SchemaPath-Eigenschaft des SqlXmlCommand-Objekts in der
Page_Load-Ereignisprozedur von "..\EmployeesFirstLastNames.xsd" zu MapPath("EmployeesFirstLastNames.xsd").
Nach Abschluss dieser Schritte können Sie auf die Seite WebForm1.aspx mit der rechten Maustaste
im Projektmappen-Explorer klicken und den Befehl Erstellen und durchsuchen wählen. Dieser Prozess setzt das FirstName-Feld der Zeile aus der Employees-Tabelle mit einem EmployeeID-Wert von
1 auf Nancie. Sie können die ursprünglichen Vornamen wiederherstellen, wenn Sie Nancie in
Nancy ändern und den Befehl Erstellen und durchsuchen ein weiteres Mal wählen.
Zur leichteren Referenz wird die Page_Load-Ereignisprozedur an dieser Stelle aufgeführt. Die beiden
Zeilen, die sich in Bezug auf die PopulateModifyUpdateWithDiffGram-Prozedur geändert haben,
sind fett dargestellt. Der wichtigste Punkt ist, dass das folgende Listing zwar für ASP.NET vorgesehen
ist, aber fast identisch zur früheren Windows-Anwendung funktioniert. Die MapPath-Funktion gibt
den vollständigen Pfad auf die Datei zurück, die im Argument angegeben wird. Diese Webfunktion
gibt dem Entwickler die Möglichkeit, einen Pfad auf die Datei zu verwenden, ohne diesen in der
Anwendung explizit angeben zu müssen. Außerdem verbessert die MapPath-Funktion die Portabilität Ihres Codes, denn die Funktion berechnet den Pfad auf die Datei dynamisch, selbst wenn Sie den
Ordner der Anwendung ändern.
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
' Angeben einer Verbindung für das SqlXmlCommand-Objekt cmd1;
494
Kapitel 12
677.book Page 495 Thursday, December 5, 2002 2:26 PM
' Die Angabe der Verbindung muss den Provider (sqloledb) umfassen.
Dim cmd1 As New SqlXmlCommand("Provider=sqloledb;" & _
"Data Source=(local);" & _
"Initial Catalog=northwind;Integrated Security=SSPI")
' Angeben des SqlXmlCommand-Objekts zur Rückgabe
' des Vor- und Zunamens auf der Grundlage einer XPath-Abfrage.
cmd1.RootTag = "ROOT"
cmd1.CommandText = "Emp"
cmd1.CommandType = SqlXmlCommandType.XPath
cmd1.SchemaPath = MapPath("EmployeesFirstLastNames.xsd")
' Instantiieren eines SqlXmlAdapter-Objektes unter Verwendung
' des SqlXmlCommand-Objekts.
Dim dap1 As SqlXmlAdapter
dap1 = New SqlXmlAdapter(cmd1)
' Instantiieren eines neuen DataSet-Objekts (das1) und
' Füllen des DataSets via dap1.
Dim das1 As DataSet = New DataSet()
dap1.Fill(das1)
' Editieren des Wertes aus der ersten Spalte der ersten Zeile
' aus dem DataTable-Objekt Emp.
das1.Tables("Emp").Rows(0)(0) = "Nancie"
' Schreiben der XML-Daten als Diffgramm, bevor die
' Änderungen an den Server übermittelt werden.
Dim str1 As String = _
"c:\SQL Server Development with VBDotNet\" & _
"Chapter12\myDiffGram.xml"
Dim myFileStream As New System.IO.FileStream _
(str1, System.IO.FileMode.Create)
Dim xtw1 As New System.Xml.XmlTextWriter _
(myFileStream, System.Text.Encoding.Unicode)
das1.WriteXml(xtw1, XmlWriteMode.DiffGram)
' Ausführen der Aktualisierung der serverseitigen
' Datenquelle des DataSets das1; geben Sie keine
' spezifische Datentabelle im Dataset an.
dap1.Update(das1)
End Sub
Erstellen von HTML-Seiten mit XSLT
Wenn Sie mit der Programmierung mit Visual Basic .NET beginnen, sollte sich Ihre Arbeit als Webentwickler auf ASP.NET konzentrieren (siehe Kapitel 11). Diese Technologie wurde speziell so
ausgelegt, dass Visual Basic-Entwickler mit der Erstellung von Webanwendungen unmittelbar beginnen können. Wie Sie aus den vorangegangenen beiden Beispielen ersehen konnten, ist es einfach
Visual Basic-Code in ASP.NET zu übernehmen. Gelegentlich könnte es allerdings sinnvoll sein, in
der Webumgebung auszugebende Informationen unter Verwendung von XSLT zu generieren. Meiner
Erfahrung entsprechend findet XSLT besonders bei der Umsetzung von XML-Dokumenten in Tabellen auf HTML-Seiten gerne Verwendung. Bis zu diesem Punkt zielte dieses Kapitel darauf ab, prakti-
Programmieren von XML mit Visual Basic .NET
495
677.book Page 496 Thursday, December 5, 2002 2:26 PM
sche Kenntnisse zur Erstellung und Verarbeitung von XML-Dokumenten in .NET-Anwendungen zu
vermitteln. Der Rest dieses Kapitels widmet sich nun der Vorbereitung von XML-Dokumenten für die
Darstellung auf HTML-Seiten mittels XSLT.
Wenn Sie XSLT verwenden, um XML-Dokumente in HTML-Seiten zu transformieren, ist es dienlich,
praktische Kenntnisse zur Syntax der HTML-Formatierung sowie zu kaskadierenden Stylesheets zu
besitzen. Sie müssen natürlich auch wissen, wie auf die Tags in einem XML-Dokument zugegriffen
werden kann, um diese in Ihren HTML-Seiten darzustellen. Viele Visual Basic-Entwickler besitzen
nur geringe Erfahrung mit der HTML-Programmierung. Wenn dies auf Sie zutrifft, empfehle ich
Ihnen eine Reihe von Strategien. Verwenden Sie einen grafischen Webseitendesigner, z. B. denjenigen aus .NET oder FrontPage. Mit einem grafischen Webseitendesigner können Sie Seiten auf grafische Art und Weise erstellen und dann den HTML-Code der Seiten analysieren. Sie können diesen
Code dann in Ihre XSLT-Übersetzungsdatei übernehmen. Zweitens, wenn Sie Mitglied eines Projektteams sind, zu dem auch Webspezialisten gehören, sollten Sie das Projekt so planen, dass die Webspezialisten allgemeine .xslt-Dateien erstellen, die Sie in vielen Situationen und mit Leichtigkeit
anpassen können. Die Visual Basic-Entwickler können dann auf die XSLT-Übersetzungsdateien im
vorliegenden Format oder mit geringfügigen Anpassungen verweisen.
Die Dokumentation zu Visual Studio .NET umfasst mehrere Beispiele, die verdeutlichen, wie XMLDokumente geladen und mit XSLT umgewandelt werden können (siehe das Thema Die XslTransform.Load-Methode (XmlReader) aus der Visual Basic .NET-Dokumentation für ein Beispiel). Der
aktuelle Abschnitt aus diesem Buch umfasst eine Reihe von Beispielen, die diejenigen aus der Visual
Basic .NET-Dokumentation, die mit der SqlXmlCommand-Klasse arbeiten, vervollständigen. Erinnern Sie sich, dass Sie diese SQLXML-verwaltete Klasse verwenden können, um XML-Dokumente
für SQL-Anweisungen zu generieren. Die SQLXML-verwalteten Klassen wurden bereitgestellt, um
SQL Server-Entwickler zu unterstützen. Um ein Beispiel zugeben, die SchemaPath-Eigenschaft
erleichtert die Referenzierung eines kommentierten Schemas zur Filterung eines Resultsets von einem
Datenbankobjekt. Auf ähnliche Weise referenziert die XslPath-Eigenschaft eines SqlXmlCommandObjekts eine .xslt-Datei. Wenn Sie dieses Attribut angeben, können Ihre Prozeduren HTML-Seiten
statt unverarbeiteter und unformatierter XML-Tags und -Werte aus einer Dokumentdatei zurückgeben. Die angegebene XSLT-Übersetzungsdatei muss mit dem XML-Dokument, das anderenfalls vom
SqlXmlCommand-Objekt zurückgeliefert wird, synchronisiert werden. Zwei Beispiel-XSLT-Übersetzungsdateien verdeutlichen, wie diese Synchronisation implementiert wird.
Formatieren zweier Spalten aus der Employees-Tabelle
Wenn Sie die XslPath-Eigenschaft eines SqlXmlCommand-Objekts verwenden, greifen Sie auf das
zugrunde liegende XML-Dokument nicht direkt zu. Der interne Code der SqlXmlCommand-Klasse
konvertiert das XML-Dokument des Objekts automatisch in HTML-Code entsprechend den Anweisungen aus der Datei, auf die die XslPath-Eigenschaft verweist. Das folgende Beispiel übersetzt ein
XML-Dokument auf der Grundlage der Employees-Tabelle aus der Northwind-Datenbank. Statt nur
die endgültige HTML-Seite zu speichern, speichert die Prozedur zuerst das XML-Dokument ohne
Angabe der XslPath-Eigenschaft ab. Danach weist die Prozedur der XslPath-Eigenschaft eine Zeichenfolge zu, die auf eine .xslt-Datei verweist, und speichert das zweite Dokument im HTML-Format.
Die Prozedur SQLToXMLToHTMLForEmployees beginnt mit der Erstellung eines XML-Dokumentes mithilfe eines SqlXmlCommand-Objekts, das auf die Northwind-Datenbank verweist. Die SQLZeichenfolge für das Objekt extrahiert die Spalten EmployeeID, FirstName und LastName aus der
Employees-Tabelle unter Verwendung einer SELECT-Anweisung mit einer FOR XML-Klausel. Denken Sie daran, dass dieser Prozess ein XML-Fragment ohne eindeutigen äußeren Tag für das Doku-
496
Kapitel 12
677.book Page 497 Thursday, December 5, 2002 2:26 PM
ment zurückliefert. Die Prozedur weist aus diesem Grunde der RootTag-Eigenschaft des SqlXmlCommand-Objekts den Zeichenfolgenwert (“MyRoot”) zu. Als nächstes wird die Prozedur für die
Abspeicherung des XML-Dokumentes in einer Datei namens UnformattedEmployees.xml vorbereitet, bevor die ExecuteToStream-Methode aufgerufen wird, um das XML-Dokument zu speichern.
Die Vorbereitungsmaßnahmen ermöglichen es der ExecuteToStream-Methode, das Dokument direkt
aus dem SqlXmlCommand-Objekt an eine Datei zu übergeben. Nach der Abspeicherung des XMLDokuments setzt die Prozedur die XslPath-Eigenschaft des SqlXmlCommand-Objekts. Die Eigenschaft verweist auf die Datei MyXSL.xslt im Stammordner des XMLSample-Projektordners. Danach
ruft die Prozedur die ExecuteStream-Methode des SqlXmlCommand-Objekts auf, um die HTMLSeite im Arbeitsspeicher mit einem Stream-Objekt zu repräsentieren. Nach der Erfassung der HTMLDaten in Form eines Stream-Objekts setzt die Prozedur mit dem Auslesen des Stream-Objekts fort
und schreibt diese Informationen in eine externe Datei namens FormattedEmployees.html.
Sub SQLToXMLToHTMLForEmployees()
' Angeben eines SqlXmlCommand-Objekts.
Dim cmd1 As New SqlXmlCommand("Provider=sqloledb;" & _
"Data Source=(local);" & _
"Initial Catalog=northwind;Integrated Security=SSPI")
cmd1.CommandText = _
"SELECT EmployeeID, FirstName, LastName " & _
"FROM Employees FOR XML AUTO"
cmd1.CommandType = SqlXmlCommandType.Sql
cmd1.RootTag = "MyRoot"
' Angeben des Pfades und der Datei für das XML-Resultset,
' danach instantiieren eines Stream-Objekts
' für die Inhalte der Datei.
Dim myXMLfile As String = _
"c:\SQL Server Development with VBDotNet\" & _
"Chapter12\UnFormattedEmployees.xml"
Dim myFileStream As New System.IO.FileStream _
(myXMLfile, System.IO.FileMode.Create)
' Ausführen von cmd1 und Speichern
' des Resultsets im Stream-Objekt.
cmd1.ExecuteToStream(myFileStream)
' Schließen des FileStream-Objekts, um die Ressourcen freizugeben.
myFileStream.Close()
' Setzen der XslPath-Eigenschaft, um
' den Namen des XSLT-Stylesheets anzugeben.
cmd1.XslPath = "..\MyXSL.xslt"
' Rückgabe der HTML-Daten von cmd1 als Stream-Objekt
' im Arbeitsspeicher; danach erstellen eines StreamReaders,
' um die Inhalte aus dem Stream-Objekt auszulesen.
Dim stm1 As Stream
stm1 = cmd1.ExecuteStream
Dim srd1 As New StreamReader(stm1)
' Deklarieren und Instantiieren einer Zeichenfolge für
' den Namen der Datei, auf die das FileStream-Objekt mit
' den HTML-Inhalten verweisen soll.
Programmieren von XML mit Visual Basic .NET
497
677.book Page 498 Thursday, December 5, 2002 2:26 PM
Dim str1 As String = _
"c:\SQL Server Development with VBDotNet\" & _
"Chapter12\FormattedEmployees.html"
Dim fst1 As New FileStream(str1, FileMode.OpenOrCreate)
' Deklarieren und Instantiieren eines StreamWriter-Objekts,
' um die Datei mit den HTML-Inhalten zu füllen; danach auslesen
' der StreamReader-Inhalte in eine Zeichenfolge und schreiben der
' Zeichenfolge in fst1.
Dim swt1 As New StreamWriter(fst1)
Dim str2 As String = srd1.ReadToEnd
swt1.Write(str2)
' Schließen der Datei.
swt1.Close()
End Sub
Die Abbildung 12.12 zeigt die Datei UnFormattedEmployees.xml. Beachten Sie, dass diese Datei
neun Employee-Elemente umfasst. Jedes Element verfügt über drei Attribute mit Werten für EmployeeID, FirstName und LastName. Der Inhalt und das Layout folgen direkt aus der CommandTextEigenschaftszuweisung für das SqlXmlCommand-Objekt aus der Prozedur SQLToXMLToHTMLForEmployees. Die Datei UnFormattedEmployees.xml wird mit der Datei MyXSL.xslt übersetzt.
Abbildung 12.12: Die
Inhalte aus der Datei
UnFormattedEmployees.xml,
die mit der Prozedur
SQLToXMLToHTMLForEmployees generiert wurden
Die Abbildung 12.13 zeigt das übersetzte XML-Dokument, das mit dem Namen FormattedEmployees.html abgespeichert wurde. Darüber hinaus wird die zweite Spalte zur Anzeige des Nachnamens
in Kursiv- und Fettschrift dargestellt. Es gibt noch weitere Formatierungen, z. B. einen Tabellenkopf
mit Hintergrundfarbe. Die Datei MyXSL.xslt bewirkt sämtliche Layout- und Formatierungsänderungen, die zwischen Abbildung 12.12 und Abbildung 12.13 zu erkennen sind. Es gibt noch einen Unterschied zwischen diesen beiden Abbildungen. Die Abbildung 12.13 verfügt lediglich über zwei Spalten, das ursprüngliche XML-Dokument enthält jedoch drei Attribute für jedes Employee-Element im
Dokument. Dieser Unterschied beruht auf der Tatsache, dass die Datei MyXSL.xslt nur zwei der drei
Attribute zur Anzeige auswählt.
498
Kapitel 12
677.book Page 499 Thursday, December 5, 2002 2:26 PM
Abbildung 12.13: Die Inhalte aus der Datei FormattedEmployees.html, die mit der Prozedur
SQLToXMLToHTMLForEmployees generiert wurden
Das Listing für die Datei MyXSL.xslt wird als nächstes dargestellt. Diese Datei beginnt mit einer
Deklarierung als XML-Dokument und einer Referenz auf den Namespace des World Wide Web Consortium für XSLT-Dateien. Das Design der Umwandlungsdatei besteht aus zwei Hauptteilen, die mit
zwei xsl:template-Elementen bezeichnet wurden. Das erste Element stimmt mit dem Employees-Element aus dem XML-Quelldokument, namentlich UnformattedEmployees.xml, überein. Für jedes
Employees-Element aus dem Quelldokument wählt die Übersetzungsdatei zwei Attribute aus – FirstName und LastName. Die LastName-Auswahl ist in zwei Tags eingebettet, die den Attributswert in
Fett- und Kursivschrift darstellen. Dieses erste Segment der Datei definiert darüber hinaus das Zeilenlayout für die Ergebnisse mit <TR>-Anfangs- und -End-Tags. Jeder ausgewählte Wert erscheint mit
<TD>-Anfangs- und -End-Tag, um anzuzeigen, dass die Werte unterschiedliche Zellen in der Zeile
belegen. Das zweite xsl:template-Element aus der .xslt-Datei definiert den Rumpf des Dokumentes.
Dieses Element beginnt beispielsweise mit einem HTML-Anfangselement und wird mit einem
HTML-Endelement beendet. Der HEAD-Block weist dem Tabellenkopfelement (th) in hexadezimaler Schreibweise mithilfe des background-color-Attributs eine Farbe zu. Der BODY-Block umfasst
einen TABLE-Block und formatiert den Tabellenkopf. Das xsl:apply-templates-Element innerhalb
des TABLE-Blocks bewirkt die Einfügung des ersten xsl:template-Elements in das zweite xsl:template-Element. Über diese Einfügung werden der Tabelle nach dem Tabellenkopf Zeilen hinzugefügt.
Es ist wichtig, dass das xsl:apply-templates-Element das Element MyRoot im XML-Dokument
angibt, denn dieses Element beinhaltet sämtliche Employees-Elemente aus dem XML-Quelldokument, die übersetzt werden sollen. Geben Sie dieses Auswahlattribut nicht ordnungsgemäß an,
könnte die Tabelle leer dargestellt werden.
HINWEIS: Die XSLT-Syntax bezieht sich auf Element- und Attributsnamen unterschiedlich. Wenn
Sie einen Verweis auf ein Element angeben wollen, können Sie dessen Namen verwenden. Verwenden Sie beispielsweise Employees, um ein Employees-Element zu referenzieren. Wenn Sie
sich hingegen auf ein Attribut beziehen, müssen Sie dem Attributsnamen ein @-Zeichen voranstellen. Beziehen Sie sich beispielsweise mit @FirstName auf einen FirstName-Attributswert.
Programmieren von XML mit Visual Basic .NET
499
677.book Page 500 Thursday, December 5, 2002 2:26 PM
<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/
Transform" version="1.0">
<xsl:template match = 'Employees'>
<TR>
<TD><xsl:value-of select = '@FirstName' /></TD>
<TD><B><I><xsl:value-of select = '@LastName' /></I></B></TD>
</TR>
</xsl:template>
<xsl:template match = '/'>
<HTML>
<HEAD>
<STYLE>th { background-color: #CCCCCC }</STYLE>
</HEAD>
<BODY>
<TABLE border='1' style='width:300;'>
<TR><TH colspan='2'>Angestellte(r)</TH></TR>
<TR><TH >Vorname</TH><TH>Nachname</TH></TR>
<xsl:apply-templates select = 'MyRoot' />
</TABLE>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
Formatieren dreier Spalten aus der Shippers-Tabelle
Das letzte Beispiel aus diesem Kapitel demonstriert die vorangegangene Vorgehensweise mit einem
anderen XML-Quelldokument. Die XSLT-Übersetzung wird zwar auf ein XML-Dokument angewendet, allerdings werden Sie das der veröffentlichten HTML-Tabelle zugrunde liegende XML-Dokument normalerweise nicht anzeigen. Stattdessen werden Sie die XslPath-Eigenschaft des SqlXmlCommand-Objekts unmittelbar angeben, wenn Sie die ExecuteStream-Methode aufrufen. Danach
können Sie den Strom der HTML-Daten auslesen, um die Abspeicherung der Daten in einer Datei
vorzubereiten. Bei dieser direkteren Vorgehensweise wird das XML-Dokument, das als Quelle der
HTML-Tabelle dient, nicht offen gelegt. Wenn Sie das XML-Dokument jemals analysieren wollen,
können Sie jederzeit auf die Technik aus dem vorangegangenen Beispiel zurückgreifen.
Das Beispiel, das mit der SQLThroughXMLToHTMLForShippers-Prozedur implementiert wurde,
extrahiert Spalten aus der Shippers-Tabelle. Die SELECT-Anweisung für das SqlXmlCommandObjekt fragt alle Spalten aus der Shippers-Tabelle ab. Die Anweisung umfasst eine FOR XML-Klausel, um ein XML-Fragment zurückzuliefern. Die RootTag-Eigenschaft des SqlXmlCommandObjekts bezeichnet MyRoot als eindeutiges Element, das alle anderen Elemente im XML-Dokument
umfasst. Die XslPath-Eigenschaft des SqlXmlCommand-Objekts verweist auf die Datei MyXSLShippers.xslt im Stammverzeichnis des Ordners \XMLSamples. Dies ist der Ordner, in dem das Projekt abgespeichert wurde. Nach der Instantiierung des SqlXmlCommand-Objektes und der Angabe
der Eigenschaften dieses Objekts ruft die Prozedur die ExecuteStream-Methode auf, um im Arbeitsspeicher eine Stream-Variable mit den HTML-Daten für die Datei anzulegen, die von der Prozedur
letztendlich als FormattedShippers.html abgespeichert wird.
500
Kapitel 12
677.book Page 501 Thursday, December 5, 2002 2:26 PM
Sub SQLThroughXMLToHTMLForShippers()
' Angeben eines SqlXmlCommand-Objekts.
Dim cmd1 As New SqlXmlCommand("Provider=sqloledb;" & _
"Data Source=(local);" & _
"Initial Catalog=northwind;Integrated Security=SSPI")
cmd1.CommandText = _
"SELECT ShipperID, CompanyName, Phone " & _
"FROM Shippers FOR XML AUTO"
cmd1.CommandType = SqlXmlCommandType.Sql
cmd1.RootTag = "MyRoot"
' Setzen der XslPath-Eigenschaft, um
' den Namen des XSLT-Stylesheets anzugeben.
cmd1.XslPath = "..\MyXSLShippers.xslt"
' Rückgabe der HTML-Daten von cmd1 als Stream-Objekt
' im Arbeitsspeicher; danach erstellen eines StreamReaders,
' um die Inhalte aus dem Stream-Objekt auszulesen.
Dim stm1 As Stream
stm1 = cmd1.ExecuteStream
Dim srd1 As New StreamReader(stm1)
' Deklarieren und Instantiieren einer Zeichenfolge für
' den Namen der Datei, auf die das FileStream-Objekt mit
' den HTML-Inhalten verweisen soll.
Dim str1 As String = _
"c:\SQL Server Development with VBDotNet\" & _
"Chapter12\FormattedShippers.html"
Dim fst1 As New FileStream(str1, FileMode.OpenOrCreate)
' Deklarieren und Instantiieren eines StreamWriter-Objekts,
' um die Datei mit den HTML-Inhalten zu füllen; danach auslesen
' der StreamReader-Inhalte in eine Zeichenfolge und schreiben der
' Zeichenfolge in fst1.
Dim swt1 As New StreamWriter(fst1)
Dim str2 As String = srd1.ReadToEnd
swt1.Write(str2)
' Schließen der Datei.
swt1.Close()
End Sub
Die Abbildung 12.14 zeigt die von der Prozedur SQLThroughXMLToHTMLForShippers ausgegebenen Informationen. Der Titel Shippers erstreckt sich im Tabellenkopf dieses Beispiels über drei Spalten, im Gegensatz zu zwei Spalten im vorangegangenen Beispiel. Natürlich hat die Tabelle drei Spalten
und die Inhalte der ersten Spalte, welche die ShipperID-Werte aufführt, wurden horizontal zentriert.
Abgesehen von diesen Unterschieden entspricht das Layout der Tabelle dem Design des vorangegangenen Beispiels.
Programmieren von XML mit Visual Basic .NET
501
677.book Page 502 Thursday, December 5, 2002 2:26 PM
Abbildung 12.14: Die
Inhalte der Datei
FormattedEmployees.html,
die mit der Prozedur
SQLThroughXMLToHTMLForShippers generiert wurden
Ich habe das XML-Dokument zwar nicht dargestellt, denn Sie werden dieses normalerweise bei der
Erstellung einer HTML-Tabelle nicht anzeigen, es ist jedoch mit dem XML-Dokument aus Abbildung
12.12 ziemlich vergleichbar. Diese Abbildung zeit die XML-Ausgabe des vorigen Beispiels. Das Beispiel erstellte ein XML-Dokument mit der gleichen SELECT-Anweisung, die auch in diesem Beispiel
verwendet wurde. Der Hauptunterschied zwischen den XML-Daten der beiden Dokumente ist wichtig, aber minimal. Die Abbildung 12.12 lässt erkennen, dass das Stammelement des XML-Dokumentes aus dem vorangegangenen Beispiel Shippers lautet. Das Beispiel aus diesem Abschnitt verwendet
hingegen MyRoot für den Tag des Stammelementes des Dokuments. Diese Angabe des Stammelement-Tags ist wichtig, denn die .xslt-Datei verweist auf diese Bezeichnung bei der Umsetzung der
XML-Daten in HTML. Geben Sie den Tag für das Stammelement fehlerhaft an, werden Ihre HTMLDaten ebenfalls fehlerhaft sein. Dieser geringfügige Formatierungsunterschied zwischen diesem und
dem vorangegangenen Beispiel hilft, Fragen der XSLT-Syntax zu betonen, die das Layout und die
Formatierung der Inhalte auf einer HTML-Seite kontrollieren. Sie können das Listing der Datei
MyXSLShippers.xslt mit dem vorigen Listing der Datei MyXSL.xslt vergleichen, die verwendet
wurde, um das vorige XML-Dokument in eine HTML-Tabelle zu übersetzen. Wie zuvor verfügt die
Datei MyXSLShippers.xslt über zwei xsl:template-Elemente. Allerdings entspricht das erste Element
aus dieser Datei dem Shippers-Element aus dem Dokument, denn das zugrunde liegende XMLDokument verfügt über drei separate Zeilen, die jeweils mit einem Shippers-Element beginnen. Mit
dem Namen dieses Elements (Shippers) können Sie auf die Ansammlung aller Zeilen aus dem XMLDokument verweisen. Beachten Sie außerdem, dass das erste Element xsl:value-of-Elemente
umfasst. Die vorige Datei MyXSL.xslt beinhaltete nur zwei dieser Elemente – eines für jede Spalte.
Die Formatierungs-Tags, welche die Spaltenwerte umschließen, sind in diesem Beispiel ebenfalls
anders. Die ShipperID-Spaltenwerte verfügen beispielsweise über Formatierungen, die eine horizontale Zentrierung bewirken. Darüber hinaus gibt es keine Tags für Fett- oder Kursivschrift. Neben diesen unwesentlichen Unterschieden sind die .xslt-Dateien dieses und des vorigen Beispiels gleich. Die
beiden Beispiele ergänzen einander bei der Demonstration allgemeiner XSLT-Codiertechniken zur
Umwandlung von XML-Dokumenten in HTML-Tabellen.
502
Kapitel 12
677.book Page 503 Thursday, December 5, 2002 2:26 PM
<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/
Transform" version="1.0">
<xsl:template match = 'Shippers'>
<TR>
<TD align = 'middle'><xsl:value-of select = '@ShipperID' /></TD>
<TD><xsl:value-of select = '@CompanyName' /></TD>
<TD><xsl:value-of select = '@Phone' /></TD>
</TR>
</xsl:template>
<xsl:template match = '/'>
<HTML>
<HEAD>
<STYLE>th { background-color: #CCCCCC }</STYLE>
</HEAD>
<BODY>
<TABLE border='1' style='width:300;'>
<TR><TH colspan='3'>Zulieferer</TH></TR>
<TR><TH >ShipperID</TH><TH>Firmenname</TH><TH>Telefon</TH></TR>
<xsl:apply-templates select = 'MyRoot' />
</TABLE>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
Programmieren von XML mit Visual Basic .NET
503
677.book Page 504 Thursday, December 5, 2002 2:26 PM
Herunterladen