440 Datenaustausch Bild 11.11: Über HTTP eine Abfrage in der MS SQL Server-Datenbank ausführen 11.5.2 Ergebnis wird im XML-Format zurückgegeben Die SELECT-Anweisung kann beim MS SQL Server 2000 eine neue Klausel enthalten. Mit der Klausel „FOR XML“ werden die Daten im XML-Format und nicht als gewohntes Rowset zurückgegeben. Dabei existieren drei Möglichkeiten, die einen unterschiedlichen Grad an Flexibilität für die Definition des XML-Ergebnisses festlegen, das Sie von der Abfrage erhalten. • Raw • Auto • Explicit Die SQL-Erweiterung für die „FOR XML“-Klausel sieht folgendermaßen aus: SELECT… FROM… WHERE… ORDER BY… FOR XML (raw | auto [, ELEMENTS] | explicit) „Raw“-Modus Die erste Möglichkeit, der „Raw“-Modus, ist ein einfacher Modus. Er nimmt eigentlich nur das Ergebnis der Abfrage und definiert, dass jede Zeile ein XML-Zeilenelement wird. Es gibt keine Verschachtelung, da der MS SQL Server keine geschachtelten Tabellen kennt. Die MS SQL Server und XML 441 einzelnen Spalten und deren Werte im Abfrageergebnis werden in XML als AttributWertpaare in der Zeile abgebildet. Der Attributname bildet sich dabei aus dem Spaltennamen. Der Aufbau des XML-Ergebnisses ähnelt beim „Raw“-Modus dem Aufbau einer CSV-Datei, nur mit dem Unterschied, dass es XML-Format ist. Die nächste Abfrage stellt eine einfache Verknüpfung zwischen den beiden Tabellen „Abteilung“ und „Mitarbeiter“ dar. Es sollen der Abteilungsname und die Nachnamen der einzelnen Mitarbeiter angezeigt werden. SELECT abt_name, Nachname FROM Abteilung, Mitarbeiter WHERE Abteilung.abt_nr = Mitarbeiter.Abteilungs_nr FOR XML raw Diese „SELECT“-Anweisung können Sie im SQL Server Query Analyzer eingeben. Da das Ergebnis in einer Zeile zurückgeliefert wird, ist es sinnvoll, das Resultat nicht anzeigen, sondern in eine Datei speichern zu lassen. In dieser Datei können Sie dann selber Zeilenumbrüche zum besseren Lesen einfügen. Falls Sie, wie oben beschrieben, ein virtuelles Stammverzeichnis bezogen auf die MS SQL Server-Datenbank „Firma“ angelegt haben, können Sie den SQL-Code auch im Browser ausführen. Die vollständige Zeile lautet dafür folgendermaßen: http://Galah/Firma?sql=SELECT abt_name, Nachname FROM Abteilung, Mitarbeiter WHERE Abteilung.abt_nr = Mitarbeiter.Abteilungs_nr FOR XM raw&root=root Das Ergebnis enthält keine strukturellen Informationen, sondern nur für jede existierende Kombination eine Zeile, das heißt ein XML-Element mit dem allgemeinen Bezeichner „row“. Es können keine Rückschlüsse mehr gezogen werden, welche Daten aus welcher Tabelle stammen. <row abt_name="Vertrieb <row abt_name="Marketing <row abt_name="Vertrieb … <row abt_name="Support " Nachname="Keller " Nachname="Huber " Nachname="Müller "/> "/> "/> " Nachname="Müller "/> „Auto“-Modus Falls das Resultat eine Struktur besitzt, aber die Arbeit nicht zu aufwändig werden soll, können Sie den „Auto“-Modus einsetzen. Das Resultat der Abfrage wird in diesem Fall als geschachtelte XML-Elemente geliefert. Zusätzlich werden die Namen der Tabellen beziehungsweise Sichten zur Bildung des Elementnamens verwendet. Die Spaltennamen werden für die Attribute benutzt oder können die Unterelemente repräsentieren. Wenn dieselbe „SELECT“-Anweisung wie beim „Raw“-Modus verwendet wird, sieht das Ergebnis schon ein wenig anprechender aus. Da der Tabellenname mit übernommen wird, weiß man sofort, aus welcher Tabelle die einzelnen Daten stammen. 442 Datenaustausch Für die Abbildung wurde folgende Zeile in das Kombinationsfeld „Adresse“ des Internet Explorers eingegeben. Dies funktioniert nur, wenn das virtuelle Stammverzeichnis „Firma“ existiert. http://Galah/Firma?sql=SELECT abt_name, Nachname FROM Abteilung, Mitarbeiter WHERE Abteilung.abt_nr = Mitarbeiter.Abteilungs_nr FOR XM auto&root=root Bild 11.12: Die Klausel „FOR XML“ mit dem „Auto“-Modus Erscheinen mehrere Mitarbeiter derselben Abteilung direkt aufeinander folgend, werden sie zu einer Gruppe zusammengefasst, das heißt, die XML-Elemente werden geschachtelt. Die Schachtelung hängt von der Reihenfolge der angegebenen Tabellen ab. Da zuerst die Tabelle „Abteilung“ genannt wurde, stellt der Abteilungsname die oberste Hierarchie dar und kann somit mehrere Mitarbeiter der nächsten Hierarchieebene enthalten. Würden Sie in der „SELECT“-Anweisung die Tabelle „Mitarbeiter“ zuerst und dann die Tabelle „Abteilung“ schreiben, wäre die oberste Hierarchieebene der Nachname und es könnten keine Untereinträge gebildet werden. „Explicit“-Modus Als dritten Modus können Sie bei der „FOR XML“-Klausel den „Explicit“-Modus wählen. Damit legen Sie fest, dass die Struktur des XML-Resultats explizit definiert ist. Diese Definition erfolgt über zusätzliche Angaben zur Schachtelung direkt in der Abfrage. MS SQL Server und XML 443 Für den „Explicit“-Modus ist es notwendig, dass die Abfrage zwei bestimmte Spalten enthält, die als Metadatenspalten bezeichnet werden. • Die erste Spalte muss die Tagnummer des aktuellen Elements mit dem Datentyp „integer“ sein. • Die zweite Spalte muss die Tagnummer des übergeordneten Elements sein. Sie wird deswegen auch als „Parent“-Spalte bezeichnet. Auch hier wird der Datentyp „integer“ benötigt. Der Inhalt dieser beiden Spalten wird zum Erkennen und zur Darstellung der „Parent-Child“Hierarchie benötigt. Nur so kann die gewünschte Struktur im XML-Dokument richtig aufgebaut werden. Wenn in einer „Parent“-Zeile der Wert 0 oder Null steht, handelt es sich bei dem Element um die oberste Hierarchieebene. Es sollen wieder die einzelnen Abteilungen mit den dazugehörigen Mitarbeitern angezeigt werden. Im Gegensatz zu den letzten beiden Beispielen soll nun aber jeder Abteilungsname nur noch einmal erscheinen, und alle Mitarbeiter sollen unter der entsprechenden Abteilung aufgelistet werden. Für die Realisierung werden zwei „SELECT“-Anweisungen benötigt, die über die „UNION ALL“-Anweisung zu einem Ergebnis zusammengefasst werden. Die erste „SELECT“-Anweisung basiert nur auf der Tabelle „Abteilung“ und besteht aus vier Spalten. Da die Tabelle „Abteilung“ in der Hierarchie an der obersten Stelle steht, bekommt jeder Datensatz als „Tag“ den Wert 1 und als „Parent“ den Wert „Null“ übergeben. Die vierte Spalte enthält auch jeweils den Wert „Null“, da sie nur bei der nächsten „SELECT“-Anweisung gefüllt wird. Die zweite „SELECT“-Anweisung ähnelt sehr der Abfrage, die beim „Raw“-Modus und beim „Auto“-Modus verwendet wurde. Der Unterschied liegt nur in den beiden ersten Spalten, die neu hinzugekommen sind. Die Tagnummer lautet für jeden Datensatz 2. Da es sich nun um Sätze der zweiten Hierarchieebene handelt, muss in die „Parent“-Zelle der Wert der übergeordneten Ebene, das heißt 1, geschrieben werden. Die „UNION ALL“-Anweisung wird nach dem Abteilungsnamen und dem Nachname sortiert. Am Ende der gesamten Anweisung wird der „Explicit“-Modus angegeben. SELECT 1 NULL Abteilung.abt_name NULL FROM Abteilung as Tag, as Parent, as [Abteilung!1!abt_name], as [Mitarbeiter!2!Nachname] UNION ALL SELECT 2, 1, Abteilung.abt_name, Mitarbeiter.Nachname FROM Abteilung, Mitarbeiter WHERE Abteilung.abt_nr = Mitarbeiter.Abteilungs_nr ORDER BY [Abteilung!1!abt_name], [Mitarbeiter!2!Nachname] FOR XML EXPLICIT 444 Datenaustausch Das Ergebnis dieser Abfrage wird in der Abbildung gezeigt. Damit die Abfrage im Browser ausgeführt werden kann, muss das virtuelle Stammverzeichnis „Firma“ existieren. Bild 11.13: Die Klausel „FOR XML“ mit dem „Explizit“-Modus Einschränkungen für die „FOR XML“-Klausel Die Verwendung der „FOR XML“-Klausel unterliegt mehreren Einschränkungen. Einige wichtige sind nachfolgend aufgelistet: • Sie kann nicht in untergeordneten „SELECT“-Anweisungen benutzt werden. • Sie kann nicht zusammen mit der Klausel „COMPUTE BY“ eingesetzt werden. • Der „Auto“-Modus wird nicht zusammen mit Aggregatfunktionen und der Klausel „GROUP BY“ unterstützt. • Sie kann nicht in einer Sicht oder einer benutzerdefinierten Funktion, die ein Rowset zurückliefert, zum Einsatz kommen. • Sie kann nicht zusammen mit Cursorn benutzt werden. 11.5.3 XML-Daten in einer Abfrage auswerten Wenn Sie Daten, die im XML-Format vorliegen, in einer Abfrage verwenden wollen, können Sie dazu die neue Transact-SQL-Funktion „OPENXML“ einsetzen. Diese Funktion liefert ähnlich wie eine Tabelle oder eine Sicht eine zweidimensionale Darstellung von Daten, das MS SQL Server und XML 445 heißt, ein Rowset als Ergebnis zurück. Aus diesem Grund wird die Funktion auch als Rowsetprovider bezeichnet. In „SELECT“- und „SELECT INTO“-Anweisungen kann die Funktion „OPENXML“ überall dort stehen, wo sonst Tabellen oder Sichten genannt werden. Die von einem XML-Dokument über die Funktion „OPENXML“ bereitgestellten Datensätze können für die Weiterverarbeitung auch über die „INSERT“-Anweisung in Tabellen der Datenbank gespeichert werden. Hinweis: Da die Funktion „OPENXML“ viele Elemente der XPath-Sprache einsetzt, ist es sehr sinnvoll, auch Wissen in dieser Sprache zu besitzen, wenn Sie mit „OPENXML“ arbeiten. Eine interne Darstellung des XML-Dokuments erstellen Damit in Abfragen die Funktion „OPENXML“ eingesetzt werden kann, muss im ersten Schritt über die gespeicherte Systemprozedur „sp_xml_preparedocument“ eine interne Darstellung des XML-Dokuments angefertigt werden. Dazu analysiert der MSXML-Parser („Msxml2.dll“) den übergegebenen XML-Text und baut intern eine Struktur verschiedener Knoten auf. Bei den Knoten handelt es sich vor allem um Elemente, Attribute und Kommentare. Die Prozedur „sp_xml_preparedocument“ gibt einen Verweis, ein Handle, auf diese interne Struktur zurück, den Sie dann an die Funktion „OPENXML“ weiterreichen. Im nächsten Beispiel wird das Handle in die Variable „iHandleDoc“ gespeichert. Im folgenden Beispiel werden einige Daten zu den beiden Bundesländern Süd- und Westaustralien in einem XML-Dokument gespeichert. Jedes Bundesland besitzt Informationen zu einem bestimmten Gebiet. Jedes Gebiet ist wiederum in Gebietsdetails untergliedert, die verschiedene Orte auflisten und angeben, ob dieser Ort auch über Einkaufsmöglichkeiten verfügt. Der XML-Text wird über die „Set“-Anweisung der Variablen „@XMLDoc“ zugewiesen. DECLARE @iHandleDoc int DECLARE @XMLDoc varchar(1000) SET @XMLDoc =' <ROOT> <Bundesland BL_NR="SA" BL_Name="Suedaustralien"> <Gebiet BL_NR="SA" G_Name="Flinders Range" G_Klima="Trocken"> <Gebietsdetail GebietsID="1" Ort="Hawker" Shop="Ja"/> <Gebietsdetail GebietsID="1" Ort="Blinman" Shop="Nein"/> </Gebiet> </Bundesland> <Bundesland BL_NR="WA" BL_Name="Westaustralien"> <Gebiet BL_NR="WA" G_Name="Hamersley Range" G_Klima="Heiss"> <Gebietsdetail GebietsID="3" Ort="Wittenoom" Shop="Nein"/> <Gebietsdetail GebietsID="3" Ort="Tom Price" Shop="Ja"/> </Gebiet> </Bundesland> </ROOT>' EXEC sp_xml_preparedocument @iHandleDoc OUTPUT, @XMLDoc 446 Datenaustausch Die Funktion „OPENXML“ einsetzen Nach der internen Aufbereitung des XML-Texts kann die Funktion „OPENXML“ zum Beispiel in einer „SELECT“-Anweisung verwendet werden. Die Funktion besitzt die folgende Syntax: OPENXML(idoc int [in], rowpattern nvarchar[in], [flags byte[in]]) [WITH (SchemaDeclaration | TableName)] • „idoc“ : Das Handle auf die interne Darstellung des XML-Dokuments. • „rowpattern“: Ein XPath-Ausdruck, der die Knoten identifiziert, die als Zeilen verarbeitet werden sollen. • „flags“: Bestimmt optional die Zuordnung, die zwischen den XML-Daten und dem Rowset zur Verwendung kommen soll. • „SchemaDeclaration“: Optionale Deklaration des Schemas oder Name der Tabelle, die das gewünschte Schema besitzt. Der Wert im Argument „flag“ bestimmt die Art der Zuordnung. Lautet der Wert 1, handelt es sich um die attributzentrierte Zuordnung. Dies bedeutet, dass die Attribute im XMLDokument den Spalten im Rowset zugeordnet werden. Diese anzuzeigenden Spalten werden beim Einsatz einer Schema-Deklaration mit ihrem Namen und dem Datentyp genannt. Wenn Sie für den Parameter „flag“ den Wert 2 eintragen, legen Sie die elementzentrierte Zuordnung fest. Durch die Zahl 3 im Argument „flag“ werden beide Zuordnungsarten erlaubt. In der nachfolgenden „SELECT“-Anweisung werden die Nummern und Namen der Bundesländer abgefragt. Als erster Parameter wird die Variable „@iHandleDoc“ übergeben, die der Rückgabewert der gespeicherten Systemprozedur „„sp_xml_preparedocument“ war. Im XPath-Ausdruck ist der Knoten „Bundesland“ spezifiziert, der eine Hierarchiestufe unter dem „Root“-Knoten liegt. Es muss dabei immer der komplette Lokalisierungspfad genannt werden. SELECT * FROM OPENXML (@iHandleDoc, '/ROOT/Bundesland',1) WITH (BL_NR varchar(5), BL_Name varchar(25)) Sowohl die Definition und die interne Aufbereitung des XML-Dokuments als auch die „SELECT”-Anweisung kann im SQL Server Query Analyzer ausprobiert werden. Als Ergebnis werden, wie Sie in der Abbildung sehen, die beiden Bundesländer „Südaustralien“ und „Westaustralien“ zurückgeliefert. Dieses Beispiel finden Sie auch auf der CD unter „OPENXML.sql“ gespeichert. MS SQL Server und XML 447 Bild 11.14: Die Funktion „OPENXML“ einsetzen Um alle Orte auszugeben, müssen bei der Funktion „OPENXML“ nur ein anderer XPathAusdruck und eine andere Spalte angegeben werden: SELECT * FROM OPENXML (@iHandleDoc, '/ROOT/Bundesland/Gebiet/Gebietsdetail',1) WITH (Ort varchar(25)) Falls Sie beim Beispiel zur Anzeige der Nummern und Namen der Bundesländer nicht die attribut- sondern die elementzentrierte Zuordnung verwenden, indem Sie für das Argument „flag“ den Wert 2 übergeben, wird nur Null im Ergebnis dargestellt. Dies liegt daran, dass die <Bundesland>-Elemente keine Teilelemente besitzen. Bei den beiden Einträgen „BL_NR“ und „BL_Name“ handelt es sich nämlich nicht um Elemente, sondern um Attribute. Damit bei der elementzentrierten Zuordnung dasselbe Ergebnis wie bei der attributzentrierten Zuordnung geliefert wird, muss das XML-Dokument etwas anders aufgebaut werden. Im folgenden XML-Text sind daher aus den bisherigen Attributen „BL_NR“ und „BL_Name“ Teilelemente vom Element „Bundesland“ geworden. <ROOT> <Bundesland> <BL_NR>SA</BL_NR> <BL_Name>Suedaustralien</BL_Name> <Gebiet BL_NR="SA" G_Name="Flinders Range" G_Klima="Trocken"> <Gebietsdetail GebietsID="1" Ort="Hawker" Shop="Ja"/> <Gebietsdetail GebietsID="1" Ort="Blinman" Shop="Nein"/> </Gebiet> </Bundesland> <Bundesland> 448 Datenaustausch <BL_NR>WA</BL_NR> <BL_Name>Westaustralien</BL_Name> <Gebiet BL_NR="WA" G_Name="Hamersley Range" G_Klima="Heiss"> <Gebietsdetail GebietsID="3" Ort="Wittenoom" Shop="Nein"/> <Gebietsdetail GebietsID="3" Ort="Tom Price" Shop="Ja"/> </Gebiet> </Bundesland> </ROOT>' Die interne Darstellung des XML-Dokuments löschen Wenn die interne Darstellung des XML-Dokuments nicht mehr benötigt wird, sollte sie mit der gespeicherten Systemprozedur „sp_xml_removedocument“ wieder aus dem Speicher entfernt werden. Das Handle kann danach nicht mehr verwendet werden. Es wird auch ungültig, wenn die Verbindung zum MS SQL Server getrennt wird. EXEC sp_xml_removedocument @iHandleDoc 11.5.4 Die Abfragesprache XPath Die Sprache XPath kann sehr gut mit der Abfragesprache SQL verglichen werden, nur mit dem Unterschied, dass XPath für XML-Dokumente und nicht für relationale Tabellen entwickelt wurde. Mit XPath können somit Daten aus einem XML-Dokument ermittelt werden. Genau gesagt handelt es sich bei XPath um eine Abfragesprache für XML, die es erlaubt, verschiedene Knoten in einem XML-Baum unter Berücksichtigung bestimmter Kriterien auszulesen. XPath-Abfragen werden vor allem in URLs, in ADO-API und in XML-Vorlagen eingesetzt. XPath steht als Abkürzung für „XML Path Language“ und wird auch als Graphnavigationssprache bezeichnet, da die Navigation durch die hierarchische Struktur eines XMLDokuments möglich ist. Diese Sprache besteht aus einer Pfad-basierten Syntax, die verwendet wird, um Untermengen aus XML-Datenbäumen abfragen zu können. Ein Ausdruck beschreibt in XPath meistens eine Knotenmenge in einem XML-Baum. Knoten können dabei auf vielfältige Arten angesprochen werden, zum Beispiel durch ihren Typ, ihren Namen oder ihre Beziehung. Die Abfragesprache XPath ist eine wichtige Schicht in der gesamten XML-Technologie. Sie können sich vorstellen, dass XPath zwischen der untersten Ebene XML und den oberen Ebenen liegt, die aus XSLT und XML-Schema gebildet werden. XPath erlaubt Entwicklern, Untermengen von Knoten und Beziehungen zwischen Knoten zu beschreiben, ohne Rücksicht auf die später verwendete Programmiersprache nehmen zu müssen. Der darunter liegende XML-Prozessor übernimmt die Arbeit der internen Aufbereitung. Heutzutage unterstützen bereits zahlreiche XML-Prozessoren die Sprache XPath. Als Beispiele sollen an dieser Stelle der MSXML-Parser der Version 3.0 von Microsoft, der Oracle Java DOM-Parser und der Apache’s Xerces-Parser genannt werden.