|
Comelio-Blog > MS SQL Server > XPath XPath
Man benötigt für die Navigation innerhalb eines XML-Dokuments eine möglichst
kurze Ausdruckssprache. Dies ist sowohl in XML Schema wie auch in XSLT / XSL-FO
oder eben im MS SQL Server die Navigations- und Abfragesprache XPath.
|
 | Kontakt
|
XPath
Man benötigt für die Navigation innerhalb eines XML-Dokuments eine
möglichst kurze Ausdruckssprache. Dies ist sowohl in XML Schema wie auch
in XSLT / XSL-FO oder eben im MS SQL Server die Navigations- und Abfragesprache
XPath. Sie besitzt keine XML-Form, damit sie möglichst kurze Ausdrücke
hervorbringt, welche allerdings bei steigenden Anforderungen auch sehr umfangreich
werden können.
Die offiziellen Dokumente finden Sie unter XML Path Language (XPath), Version
1.0, W3C Recommendation 16 November 1999 (http://www.w3.org/TR/xpath) und XML
Path Language (XPath) 2.0, W3C Candidate Recommendation 3, November 2005(http://www.w3.org/TR/xpath20/).

Ein XPath-Ausdruck findet sieben verschiedene Knotenarten, für die es
jeweils eine eigene Syntax gibt:
- Wurzelknoten (engl. root nodes)
- Elementknoten (engl. element nodes)
- Textknoten (engl. text nodes)
- Attributknoten (engl. attribute nodes)
- Namensraumknoten (engl. namespace nodes)
- Prozessoranweisungen (engl. processing instruction nodes)
- Kommentare (engl. comment nodes)
Knoten wie Elemente, Attribute und Namensräume werden über so genannte
Achsen angesteuert, die in Dokumentrichtung (westliche Leserichtung, von oben
nach unten) oder entgegen gesetzt zur Dokumentrichtung (von unten nach oben)
Knoten finden. Sie ähneln einem Familienstammbaum und decken den gesamten
Baum ab, der von einem XML-Dokument aufgespannt wird.
Vorwärts |
Rückwärts |
child (Kind)
descendant (Nachfolger)
attribute (Attribut)
self (Ich)
descendant-or-self (Nachfolger und ich)
following-sibling (Folgende Geschwister)
following (Folgende)
namespace (Namensraum) |
parent (Eltern)
ancestor (Vorfahren)
preceding-sibling (Vorhergehende Geschwister)
preceding (Vorhergehende)
ancestor-or-self (Vorfahren und ich)
|
Die nachfolgenden Abbildungen sollen zusammen mit den Beispielen die Verwendung
der verschiedenen Achsen demonstrieren. Die Knoten werden noch ohne Prädikate,
d.h. ohne Bedingungen ausgewählt. Als Beispieldokument verwenden sie das
in diesem Kapitel erzeugte Dokument products2.xml.
Folgende Ausdrücke gelten vom Wurzelknoten:
- Rufe alle Product-Elemente ab. Hier kann man die Kurzform //Product verwenden,
die sämtliche Product-Elemente überall im Dokument findet. Die Form
/Product-List/Product lässt sich auch einsetzen, um nur Product-Elemente
innerhalb von Product-List zu finden. Eine Langform mit ausgeschriebenem Achsennamen
(bei child nicht notwendig): /child::Product-List/child::Product
- Zeige die Kinder von Prices: //Product/Prices/* oder auch in verlängerter
Form //Product/Prices/child::*. Zeige die Kinder von Prices und Details: //Prices
| //Details, wobei hier ein ODER zum Einsatz kommt, was zur gleichzeitigen
Auswahl führt.
- Zeige das Attribut P-Nr: //Product/@P-Nr. Zeige alle Attribute von Product:
//Product/@*.
Folgende Ausdrücke gelten vom Wurzelelement Product-List
- Zeige die Kinder bzw. die Product-Elemente an. Dies lässt sich über
jeden einzelnen Teilausdruck von * | Product | child::* | child::Product erreichen.
- Zeige alle Product-Elemente und ihre Kinder und Kindeskinder in Dokumentrichtung
an: descendant::*.
Folgende Ausdrücke gelten von einem Product-Element:
- Zeige das Name-Element an: Name oder child::Name.
- Zeige das Color-Kind an, das innerhalb von Details liegt. Dies lässt
sich mit descendant::Color oder mit Details/Color erreichen.
- Wähle sich selbst aus: . . Wähle das eigene Attribut: @P-Nr.
Wähle den Eltern-Knoten: parent::* oder mit ausgeschriebenem Namen: parent::Product-List.
Wähle alle Vorfahren aus: ancestor::*. Wähle unter den Vorfahren
nur das Wurzelelement: ancestor::Product-List.
- Wähle die nachfolgenden Geschwister: following-sibling::Product. Wähle
die vorherigen Geschwister: preceding-sibling::Product. Wähle die Size-Elemente
der nachfolgenden Geschwister aus: following-sibling::Product/Details/Size.

Die einfache Auswahl von sämtlichen Knoten einer Achse ist nicht so interessant,
wie die Verwendung von Prädikaten, welche quasi die WHERE-Klausel eines
XPath-Ausdrucks angeben. Ein solcher setzt sich aus drei Komponenten zusammen,
die als Einheit bzw. als Lokalisierungsschritt bezeichnet werden:
- Eine Achse, welche die Beziehung zwischen dem gerade ausgewählten
und verarbeiteten Kontextknoten und den Knoten ausdrückt, die über
den Lokalisierungspfad auszuwählen sind.
- Einen Knotentest, welcher den Knotentyp und den expandierten Namen
der Knoten angibt, die durch den Lokalisierungspfad auszuwählen sind.
- Kein oder mehrere Prädikate, welche beliebige Ausdrücke
verwenden, um genauere Eigenschaften anzugeben, die für die Knoten zutreffen
sollen, welche durch den Lokalisierungspfad auszuwählen sind.
Wie in SQL sind auch die verschiedenen Operatoren für Vergleiche, Berechnungen
und Logik verfügbar, wobei in XSLT wie in HTML die entsprechenden Entitäten
zum Einsatz kommen müssen. Als Ergebnis erhält man SQL-ähnliche
Abfragemöglichkeiten, die keine XML-Dokumente zurückliefern, sondern
Ergebnismengen, die bspw. mit XSLT verarbeitet werden können oder die auch
in SQL verwendet werden können.
Vergleich |
Bedeutung |
Kalkül |
Bedeutung |
Logik |
Bedeutung |
| = |
Gleichheit |
+ |
Addition |
and |
Und |
| != |
Ungleichheit |
- |
Subtraktion |
or |
Oder |
| <, < |
kleiner |
* |
Multiplikation |
not |
Nicht |
| >; > |
größer |
div |
Division |
|
|
| <=, <= |
kleiner gleich |
mod |
Modulo |
|
|
| >=, >= |
größer gleich |
|
|
|
|
Folgende Beispiele gelten vom Wurzelknoten aus:
- Wähle das Product-Element mit der angegebenen Nummer im P-Nr-Attribut
aus: //Product[@P-Nr = 'BK-R19B-52']
- Wähle alle Produkte mit einem Listenpreis größer 100 aus:
//Product[Prices/List > '100'] oder //Product[descendant::List > '100'].
- Wähle alle Produkte mit Listenpreis größer 100 und Größe
52 aus: //Product[descendant::List > '100' and descendant::Size = '52']
- Wähle die Color-Elemente mit Wert Black und von ihnen das Großeltern-Element
Product aus: //Product/Details[Color = 'Black']/ancestor::Product
Schließlich gibt es noch eine Bibliothek an Funktionen, mit denen bspw.
basale Rechen- und Zeichenkettenmanipulationen vorgenommen werden können.
In der jeweiligen Version 2.0 gibt es ungleich mehr Funktionen, die hier allerdings
keinen Platz finden können. Die Knotenmengen-Funktionen ermitteln allgemeine
Informationen über Knoten oder erlauben den Zugriff auf Knoten über
diese Informationen
- position() ermittelt die aktuelle Position.
- last() liefert den letzten Knoten einer Knotenmenge.
- count(Knotenmenge) zählt die Knoten in einer Knotenmenge.
- name(Knotenmenge) ermöglicht die direkte Auswahl von Knoten anhand
ihres Namens mit Namensraumpräfix.
- local-name(Knotenmenge) ermöglicht die direkte Auswahl von Knoten anhand
ihres Namens ohne Namensraumpräfix.
- namespace-uri(Knotenmenge) ermittelt den URI-Wert für einen Namensraum.
- id(Objekt) ermittelt die Knotenmengen mit der angegebenen ID
Die Zeichenketten-Funktionen ermöglichen ebenfalls basale Manipulation
von Zeichenketten für die Ausgabe in XSLT oder die Suche in XPath-Prädikaten.
- starts-with(zk1, zk2) liefert true, wenn Zeichenkette 1 mit der Zeichenkette
2 beginnt.
- contains(zk1, zk2) liefert liefert true, wenn Zeichenkette 1 in Zeichenkette
2 auftritt.
- substring-before(zk1, zk2) ermittelt die Zeichen einer Zeichenkette 1 vor
der Position, die in Zeichenkette 2 angegeben wurde: substring-before("12345",
"3") liefert 12.
- substring-after(zk1, zk2) ermittelt die Zeichen einer Zeichenkette 1 nach
der Position, die in Zeichenkette 2 angegeben wurde: substring-after("12345",
"3") also die Zahl 45.
- substring(zk1, zk2, länge) ermittelt die Zeichen einer Zeichenkette
1 vor der Position, die in Zeichenkette 2 angegeben wurde, für die angegebene
Länge: substring("123456789", "3", "2")
liefert 34.
- string-length(zk) ermittelt die Länge einer Zeichenkette.
- string(Objekt) transformiert ein Objekt in eine Zeichenkette.
- concat(zk1, zk2, ...) verknüpft die eingehenden Zeichenketten.
Die logischen Funktionen liefern Wahrheitswerte oder kehren diese um.
- true() liefert den Wert wahr.
- false() liefert den Wert falsch.
- not(Objekt) liefert den Wert wahr, wenn das Objekt falsch ist.
- boolean(Objekt) transformiert ein Objekt in einen logischen Wert, wobei
nicht leere Knotenmengen und Zeichenketten sowie Zahlen größer
0 den Wert wahr ergeben.
- lang(zk) liefert den Wert wahr, wenn der xml:lang-Wert (Standardattribut
für ISO-Sprachkürzel wie de, en, fr usw.) mit der in der Zeichenkette
angegebenen Sprache übereinstimmt.
Die numerischen Funktionen führen basale Rechenoperationen durch, wobei
allerdings insbesondere das Runden nur mit Version 2.0 wie in anderen Sprachen
mit Dezimalstellenangabe funktioniert.
- number(Objekt) transformiert ein Objekt in eine Zahl.
- sum(Knotenmenge) berechnet die Summe der zu Zahlen transformierten Werte
der Knotenmenge.
- floor(Zahl) liefert die vorher liegende Ganzzahl.
- ceiling(Zahl) liefert die nächstgrößere Ganzzahl.
- round(Zahl) liefert den gerundeten Wert zur nächsten Ganzzahl.
Folgende Beispiele gehen vom Wurzelknoten aus:
- Wähle das erste Product-Element: //Product[1], alle Product-Element
nach dem vierten: //Product[position() > 4], das letzte Product-Element:
//Product[position() = last()] aus.
- Wieviele Product-Element mit Größe 52 gibt es? count(//Product[descendant::Size
= '52'])
- Summiere die Preise der schwarzen Produkte: sum(//Product[descendant::Color
= 'Black']/Prices/List/text()). Leider muss man zusätzlich noch text()
hinzufügen, um den nicht als Dezimalzahl erkannten Preis auszuwählen,
da er vier statt zwei Stellen aufweist.
- Welche Product-Elemente besitzen das Wort Road im Namen? Zeige diesen Namen
an: //Product[substring-before(Name, 'Road')]/Name oder //Product[contains(Name,
'Road')]/Name. Welche Produkte beginnen mit Road und enthalten ihn nicht nur:
//Product[substring(Name, 1, 4) = 'Road'].
- Welche Summe ergibt sich, wenn man die Differenz zwischen Kosten und den
Listenpreis rechnet: sum(//Product/descendant::List/text()) - sum(//Product/descendant::Standard/text()).
XQuery
Auf Basis der XPath-Syntax gibt es eine weitere Möglichkeit, XML-Daten
zu befragen, wobei nicht nur die XPath-Ergebnismengen entstehen, sondern darüber
hinaus ganze XML-Dokumente als Antwort erstellt werden können. In diesem
Zusammenhang kann XQuery auch als teilweiser Ersatz für die Verarbeitung
mit XSLT gesehen werden, zumal die Syn-tax wesentlich kompakter ist als die
Erzeugung des gleichen Resultats mit XSLT. Während bei XPath 1.0 zwar ebenfalls
ein großes theoretisches Fundament existiert, so ist es bei XPath 2.0
und XQuery 1.0 umso umfangreicher und aufschlussreicher. Dies kann in diesem
Abschnitt aus Platzgründen nicht einmal ansatzweise dargestellt werden.
Stattdessen sollen die für den Programmierer praktischen Bereiche aus dem
Dokument XQuery 1.0: An XML Query Language, W3C Candidate Recommendation 3 November
2005 (http://www.w3.org/TR/xquery/) kurz dargestellt werden.
Grundsyntax
Das Akronym FLOWR soll sich „flower“ sprechen und greift die Schlüsselwörter
for, let, where, order by und return auf, mit deren Hilfe SQL-ähnliche
Abfragen erstellt werden können, die neben den Aspekten Auswahl, Einschränkung
und Sortierung auch die Ausgabe in XML und damit eine Art der Umwandlung berühren.
Mit den beiden Schlüsselwörtern for und let wird jeweils eine Tupel-Sequenz
von gebundenen Variablen erstellt, die Tupel-Strom (engl. tuple sequence) genannt
wird. Sie lässt sich weiter einschränken, sortieren und schließlich
in XML formatiert ausgeben.
Schlüsselwort |
Bedeutung |
| for |
Enthält einen Ausdruck (Bindesequenz, engl. binding sequence), der
einen Knotenssatz zurückliefert, über den mit Hilfe wenigstens
einer gebundenen Variable iteriert werden kann. |
| let |
Enthält wenigstens eine Variable, deren jeweiliger Wert ohne Iteration
mit der Binde-Sequenz verbunden ist. |
| order by |
Sortierung mit ascending (Standardwert) oder descending |
| where |
Einschränkung unter Angabe eines XPath-Ausdrucks |
| return |
Erstellung der Rückgabesequenz |
Das nächste Beispiel soll einen allgemeinen Eindruck von der XQuery-Syntax
vermitteln. Der besondere Unterschied zwischen XPath und XQuery besteht darin,
dass nicht nur eine Knotenmenge ausgewählt und diese dann zurückgeliefert
wird, sondern dass dabei auch noch die Konstruktion einer Ergebnis-XML-Datei
stattfindet, deren Strukturen ebenfalls im Rahmen der Abfrage angegeben werden
können. In dieser Hinsicht konkurriert XQuery dann mit XSLT, welches ebenfalls
in der Lage wäre, die Ausgaben der Beispiele in diesem Abschnitt zu erzeugen.
Allerdings wäre die Syntax nicht so kompakt, weil XSLT ein XML-Dokument
darstellt und XQuery dagegen nicht. Dies macht möglicherweise die Erarbeitung
der Syntax für XSLT-Umsteiger schwieriger.
Im nächsten Beispiel erstellt man zunächst ein Products-Element als
Wurzelelement für das Ergebnis. Innerhalb von for referenziert man dann
die zu verarbeitenden Elemente, welche der Reihe nach abgerufen werden sollen.
In diesem Fall sind es alle Product-Elemente. Mit Hilfe von let lassen sich
Variablen erstellen, wobei in diesem Fall der je-weilige Produktname in einer
Variable gespeichert wird. In where gibt man wie in SQL eine Bedingung an, wobei
in diesem Fall dann überprüft wird, dass nur Produkte blauer Farbe
abgerufen werden. Schließlich ist auch noch mit order by eine Sortierung
wie in SQL möglich.
Neben der Angabe des Wurzelelements liefert return die Möglichkeit das
gewünschte Ausgabeformat zu erstellen. Im einfachsten Fall kann man hier
direkt XML-Vorgaben treffen. Dynamische Werte gibt man innerhalb von geschweiften
Klammern an, wobei hier und auch an anderen Stellen innerhalb von XQuery wieder
XPath-Ausdrücke sowie XPath-Funktionen zum Einsatz kommen.
xquery version "1.0";
<Products>
{
for $products in /Product-List/Product
let $product := $products/Name
where $products/Details/Color = 'Blue'
order by $products/Name
return
<Product P-Nr="{$product/parent::Product/@P-Nr}">
<Name >{$product/text()}</Name>
<Price>{$product/parent::Product/Prices/
List/text()}</Price>
</Product>
}
</Products>
Man erhält als Ergebnis eine XML-Datei (und nicht nur einen einfachen
Wert oder eine bereits vorhandene Knotenmenge). Dies zeigt sehr schön,
dass eine XQuery-Abfrage neben einer Abfrage auch eine Umwandlung bedeutet,
denn das erzeugte Antwort-XML ist völlig anders aufgebaut als die ursprünglichen
Daten.
Die nachfolgende Tabelle fasst die verschiedenen Konstruktoren zusammen. Dabei
stehen in den allgemeinen Syntaxangaben die Abkürzungen QName für
den qualifizierten XML-Namen mit Namensraumpräfix, NCName für den
unqualifizierten Namen ohne Namensraumpräfix, ContentExpr für Inhalt(sausdruck)
und Expr für einen beliebigen, sinnvollen (XPath-)Ausdruck. Insbesondere
der Inhalt für Elemente kann sehr umfangreich sein, da hier ja auch Verschachtelungen
angelegt werden können.
Konstruktor |
Syntax |
Beschreibung |
| element |
element (QName | ({ Expr })) { ContentExpr? } |
Erzeugt ein Element mit dem in QName angegeben oder aus dem Expr ermittelten
Namen und optionalem Inhalt. |
| attribute |
attribute (QName | ({ Expr })) { Expr? } |
Erzeugt ein Attribut mit dem in QName angegeben oder aus dem Expr ermittelten
Namen und optionalem Inhalt. |
| document |
document { Expr } |
Erzeugt ein XML-Wurzelelement und enthält den XML-Inhalt. |
| text |
text { Expr } |
Erzeugt einen Textknoten mit dem angegebenen Inhalt. |
processing-
instruction |
processing-instruction (NCName | ({ Expr })) { Expr? } |
Erzeugt eine Prozessoran-weisung mit dem in NCName angegebenen oder aus
dem Expr ermittelten Namen und den in Expr angegebenen Inhalt. |
| comment |
comment { Expr } |
Erzeugt einen Kommentarknoten mit dem angegebenen Inhalt. |
Die berechneten Konstruktoren können im nächsten Beispiel begutachtet
werden. Das Dokument erstellt nach einem Kommentar und einer Prozessoranweisung,
die eine XSLT-Datei referenziert schließlich das Wurzelelement, wobei
in diesem fall nicht wie zuvor XML-Syntax zum Einsatz kommt, sondern ebenfalls
ein berechneter Konstruktor. Die FLOWR-Syntax bleibt erhalten, sodass nur die
Ausgabe innerhalb von return die neu vorgestellten Elemente zeigt. Inhaltlich
stellt dieses Beispiel schon eine auch in XSLT relativ anspruchsvolle Ausgabe
in Form einer Gruppierung dar. Diese gelingt über die nur in XPath und
XQuery 2.0 vorhandene und sehr nützliche distinct-values()-Funktion. Sie
ruft alle Farben ohne Duplikate ab, sodass hier Gruppen in XML gebildet werden
können. Innerhalb eines Color-Elements sollen die Produkte dieser Farbe
enthalten sein.
Ob die berechneten Konstruktoren die Lesbarkeit fördern, ist zunächst
eine Geschmackssache. Sie erscheinen in ähnlicher Weise bspw. auch in
der Kurzsyntax von RelaxNG, einer Konkurrenztechnologie zu XML Schema. Die Gruppierung
wäre jedenfalls auch mit der zuvor verwendeten Syntax denkbar gewesen.
xquery version "1.0";
comment { "ProductSummary, 18.01.2002" },
processing-instruction xml-stylesheet { "type='text/xsl' href='transformation.xslt'"
},
element Product-Summary {
for $colors in distinct-values(//Color)
order by $colors descending
return
element Color {
attribute Name { $colors } ,
element Product-List {
for $product in //Product[Details/Color = $colors ]
let $name := $product/Name/text(),
$price := $product/Prices/List/text()
return
element Product {
element Name { $name },
element Price { $price }
}
}
}
}
Fallunterscheidungen
In XQuery lässt sich eine Fallunterscheidung nutzen, die auch in XPath
2.0 zum Einsatz kommt. Dort ist zusätzlich auch der Einsatz von for möglich.
Die allgemeine Syntax lautet if ( Expr ) then ExprSingle else ExprSingle, an
der bereits die grundlegende Struktur if-then-else gut zu erkennen ist.
Noch einmal werden die Produkte auf die Farben getestet, wobei dieses Mal alle
Produkte der Reihe nach von oben nach unten verarbeitet werden. Es findet also
keine Filterung oder Gruppierung statt, sondern jeweils eine Untersuchung, ob
das Produkt blau ist oder nicht. Ist es blau, gibt es eine Ausgabe in Form eines
Elements; im gegenteiligen Fall nur einen Kommentar.
xquery version "1.0";
<Blue-Products>
{
for $bp in //Product
return
if ($bp/Details/Color = 'Blue')
then
<BlueProduct>
{ $bp/Name/text() }
</BlueProduct>
else <!-- Product different color-->
}
</Blue-Products>
Die Ausgabe ist nicht sonderlich interessant, zeigt aber die Funktionsweise
der Iteration und die erfolgreiche Verwendung der Fallunterscheidungen.
<Blue-Products>
<!-- Product different color-->
<BlueProduct>Touring-3000 Blue, 50</BlueProduct>
<BlueProduct>Touring-3000 Blue, 44</BlueProduct>
<!-- Product different color-->
<!-- Product different color-->
</Blue-Products>
Auf der einen Seite kann man sich sehr gut vorstellen, dass die Syntax von
XPath und XQuery noch viel mehr leisten kann als hier vorgestellt wurde. Für
den T-SQL-Programmierer, der mit XML beginnt und im MS SQL Server seine ersten
Gehversuche macht, sollten die hier beschriebenen Techniken schon für viele
Ziele ausreichen. Es ist auch nicht immer möglich, alle Syntax-Elemente
sinnvoll innerhalb einer Datenbank anzu-wenden, da hier auch noch ganz andere
Möglichkeiten und Alternativen in T-SQL (Filter, Zusammensetzen des XML
über Zeichenketten etc.) genutzt werden können, die zu Lösungen
in den umrissenen XML-Technologien einen durchaus gangbaren Umweg darstellen.
Lediglich eine Information und Einschränkung ist wichtig: Der MS SQL Server
2005 unterstützt XQuery und damit auch die neue Funktionsbibliothek. Es
wurde in diesem Kapitel nur die Bibliothek von Version 1.0 vorgestellt, die
für einfache Zwecke gute Dienste leistet, aber aufgrund ihrer Beschränkung
nur in Umwegen auch eine schnelle und einfache Lösung liefert. Die Bibliothek
von 2.0 ist allerdings so viel umfangreicher, dass eine Darstellung dieses
ohnehin schon sehr lange Kapitel endgültig sprengen würde. Hier genügt
allerdings auch ein Blick in die Dokumentation des W3C, wie sie oben angegeben
wurde, welche eine einfache Auflistung von Funktionsnamen und Parametern enthält.
Zeichenkettenverarbeitung, Duplikatausblendung, Zeitberechnungen sowie typische
Aggregatfunktionen sind hier genauso wie in SQL versammelt und warten nur darauf,
entdeckt zu werden.
Relationale Spalten und Variablen adressieren
Die Funktion sql:column() ermöglicht es, auf relationale Spalten aus XQuery-Ausdrücken
heraus zuzugreifen. Damit kann man gleichzeitig in einer XQuery-Abfrage auf
XML-Spalten/Variablen wie auch auf relationale Spalten zugreifen, um bspw. ein
gemeinsames Dokument zu erstellen. In der nachfolgenden Abfrage erstellt man
die schon zuvor benutzte XML-Variable mit den Produktinformationen. Die Anweisung
ist hier noch einmal abgedruckt, da sie für die nächsten Beispiele
gemeinsam gilt und schon längere Zeit nicht mehr erfolgt ist. Das Ergebnis
dieser Abfrage zerlegt man dann relational, als würde man wieder direkt
auf eine Tabelle wie Product zugreifen, um nun aber dennoch eine XQuery-Anweisung
auf diese relationalen Spalten auszuführen. Dadurch lässt sich dann
wiederum ein XML-Dokument als Ergebnis konstruieren.
-- XML-Variable erstellen
DECLARE @productXML xml, @idoc int
-- XML abrufen
SET @productXML = (
SELECT ProductNumber AS "P-Nr",
Name AS "Name",
...
FROM Production.Product
FOR XML PATH('Product'), ROOT('Product-List'))
-- Standardzerlegung für alle Zeilen
EXEC sp_xml_preparedocument @idoc OUTPUT, @productXML
SELECT @productXML.query('
element ProductInfo {
element ProductId { sql:column("ProductNumber") },
element ProductName { sql:column("Name") },
...
} ') as Result
FROM OPENXML(@idoc, '/Product-List/Product',2)
WITH (ProductNumber nvarchar(25) 'P-Nr',
Name nvarchar(50) 'Name',
...)
Man erhält als Ergebnis für jede aus der XML-Struktur relational
umgewandelte Zeile wiederum ein XML-Dokument zurück.
<ProductInfo>
<ProductId>BK-R19B-48</ProductId>
<ProductName>Road-750 Black, 48</ProductName>
<ProductStandardCost>343.6496</ProductStandardCost>
<ProductListPrice>539.99</ProductListPrice>
<ProductSize>48</ProductSize>
<ProductColor>Black</ProductColor>
</ProductInfo>
Die Funktion sql:variable() bietet die Möglichkeit, auf vorab deklarierte
T-SQL-Variablen zuzugreifen, wobei lediglich der Name der Variable inklusive
@-Zeichen als Zeichenkette übergeben werden muss. Dies eignet sich dann
für dynamische Filter bspw. in XPath-Ausdrücken. Das nachfolgende
Beispiel zeigt den Standardfall, in dem innerhalb der where-Klausel eines XQuery-Ausdrucks
ein Filter in XPath-Notation verwendet wird. Um nun aus der zuvor erstellten
XML-Variable nur noch die schwarzen Produkte abzurufen, kann man innerhalb des
XPath-Ausdrucks auf die zuvor erstellte Variable @Color zugreifen.
DECLARE @Color [varchar](20)
SET @Color='Black'
SELECT @productXML.query('<Product-List> {
for $A in /Product-List/Product
where $A [Details/Color = sql:variable("@Color")]
return $A}
</Product-List>')
Aggregatfunktionen verwenden
Auch wenn die Funktionen von XPath 1.0 schon vorgestellt wurden, soll noch
einmal kurz darauf hingewiesen werden, dass diese Funktionen und die Funktionen
von XPath 2.0 und XQuery 2.0 ebenfalls im MS SQL Server genutzt werden können.
Durch sie steht ein unglaublicher Sprachreichtum zur Verfügung, der neben
Zeichenkettenbearbeitung, Berechnungen sowie XML-Bearbeitungen und –Manipulationen
eigentlich immer eine Lösung bieten sollte. Für die sicherlich besonders
häufig gebrauchten Aggregatfunktionen zeigt das nächste Beispiel,
wie einfach diese Funktion in einer XQuery-Abfrage eingefügt werden können
und diverse Berechnungen durchführen. Interessant ist insbesondere, wie
einfach eine „Unterabfrage“, die hier nur nicht so heißen
braucht, da die Korrelation gar nicht sichtbar ist, ausgeführt werden kann,
um die Produkte mit dem kleinsten/größten Preis ausfindig zu machen.
Es ist lediglich eine Aggregatfunktion auf der rechten Seite eines Filters notwendig,
welche den benötigten Wert abruft.
SELECT @productXML.query('<Aggregate>
<Mittelwert>{avg(/Product-List/Product/Prices/Standard)
}</Mittelwert>
<Summe>{sum(/Product-List/Product/Prices/Standard)}</Summe>
<Anzahl>Produkte:{count(/Product-List/Product)}</Anzahl>
<Produkteliste-Minimum>{
for $products in /Product-List/Product
where $products/Prices/Standard = min(//Standard)
return $products }</Produkteliste-Minimum>
<Produktliste-Maximum>{
for $products in /Product-List/Product
where $products/Prices/Standard = max(//Standard)
return $products}</Produktliste-Maximum></Aggregate>
')
Man erhält ein relative langes XML-Dokument, da eine große Anzahl
an Produkten einen Preis von 0 besitzen und daher diese Liste innerhalb der
XML-Struktur sehr umfangreich ist.
<Aggregate>
<Mittelwert>258.602961309524</Mittelwert>
<Summe>130335.8925</Summe>
<Anzahl>Produkte:504</Anzahl>
<Produkteliste-Minimum>
<Product>
<P-Nr>RC-0291</P-Nr>
<Name>Rear Derailleur Cage</Name>
<Prices>
<Standard>0.0000</Standard>
<List>0.0000</List>
...
Comelio GmbH MS SQL Server: XPath - MS SQL Server T-SQL XML Webservices Programmierung Bücher Anleitung Tutorial Skulschus Wiederstein Kozik Intelligence .NET SQL Business Reporting Analysis Bücher T-SQL Microsoft MS Webservices Server Services XML -Comelio GmbH MS SQL Server: XPath - MS SQL Server T-SQL XML Webservices Programmierung Bücher Anleitung Tutorial Skulschus Wiederstein Kozik Intelligence .NET SQL Business Reporting Analysis Bücher T-SQL Microsoft MS Webservices Server Services XML -Comelio GmbH MS SQL Server: XPath - MS SQL Server T-SQL XML Webservices Programmierung Bücher Anleitung Tutorial Skulschus Wiederstein Kozik Intelligence .NET SQL Business Reporting Analysis Bücher T-SQL Microsoft MS Webservices Server Services XML -Comelio GmbH MS SQL Server: XPath - MS SQL Server T-SQL XML Webservices Programmierung Bücher Anleitung Tutorial Skulschus Wiederstein Kozik Intelligence .NET SQL Business Reporting Analysis Bücher T-SQL Microsoft MS Webservices Server Services XML -Comelio GmbH MS SQL Server: XPath - MS SQL Server T-SQL XML Webservices Programmierung Bücher Anleitung Tutorial Skulschus Wiederstein Kozik Intelligence .NET SQL Business Reporting Analysis Bücher T-SQL Microsoft MS Webservices Server Services XML -Comelio GmbH MS SQL Server: XPath - MS SQL Server T-SQL XML Webservices Programmierung Bücher Anleitung Tutorial Skulschus Wiederstein Kozik Intelligence .NET SQL Business Reporting Analysis Bücher T-SQL Microsoft MS Webservices Server Services XML -Comelio GmbH MS SQL Server: XPath - MS SQL Server T-SQL XML Webservices Programmierung Bücher Anleitung Tutorial Skulschus Wiederstein Kozik Intelligence .NET SQL Business Reporting Analysis Bücher T-SQL Microsoft MS Webservices Server Services XML -Comelio GmbH MS SQL Server: XPath - MS SQL Server T-SQL XML Webservices Programmierung Bücher Anleitung Tutorial Skulschus Wiederstein Kozik Intelligence .NET SQL Business Reporting Analysis Bücher T-SQL Microsoft MS Webservices Server Services XML -Comelio GmbH MS SQL Server: XPath - MS SQL Server T-SQL XML Webservices Programmierung Bücher Anleitung Tutorial Skulschus Wiederstein Kozik Intelligence .NET SQL Business Reporting Analysis Bücher T-SQL Microsoft MS Webservices Server Services XML - |