XQuery - "SQL für XML"

Werbung
XQuery - "SQL für XML"
"The best way to explain XQuery is to say
that XQuery is to XML what SQL is to database tables."
•
•
•
•
•
•
•
•
•
•
•
•
•
Was ist XQuery? ...
Datentypen & Typumwandlung (Type Casting)
Operatoren
Arithmetik
Konstruktoren
FLWOR Ausdrücke
Verbundoperationen (Joins)
Gruppierungen
If-then-else-Anweisung
Quantoren
Namensräume
Vordefinierte Funktionen
Benutzerdefinierte Funktionen
Was ist XQuery? …
‐ Anfragesprache für XML ‐ XQuery ist das, was SQL für Datenbanken ist ‐ XQuery baut auf XPath Ausdrücken auf ‐ wird von allen größeren Datenbanksystemen unterstützt ‐ ist ein W3C Standard Voraussetzungen sind Kenntnisse von: •
•
•
•
XML XPath 2.0 XML Namespaces XML Schema Kommentare in XQuery‐Anfragen werden in runder Klammer mit Doppelpunkt geschachtelt: (: Dies ist ein XQuery-Kommentar :) Eine XQuery Anfrage ist ein Ausdruck, der eine Sequenz von atomaren Werten oder XML‐Fragmenten liest und auch zurückgibt. ‐ String‐Werte werden wie in anderen Sprachen auch in einfache Hochkomma 'string' oder doppelte Hochkomma "string" geschrieben ‐ wie bei XML muss auf Groß‐ und Kleinschreibung geachtet werden! Alle Schlüsselwörter werden klein geschrieben XQuery ist eine funktionale Sprache, d.h. sie besteht aus Ausdrücken. Dabei kann ein Ausdruck folgende Form haben: •
•
•
•
•
•
•
Pfadausdrücke Element‐Konstruktoren FLWOR‐Ausdrücke Listen‐Ausdrücke fallbedingte Ausdrücke quantifizierte Ausdrücke Datentyp‐Ausdrücke Ausdrücke sind beliebig ineinander schachtelbar und werden dabei relativ zu einem Kontext ausgewertet (Namensraum, Kontext‐Position, Kontext‐Knoten/Wert etc.). Anfragenstruktur: Eine Anfrage besteht aus einem fakultativen Anfragen‐Prolog und einem Anfragen‐Körper. Der Prolog wird nur benötigt, wenn der Körper von Namensräumen, Schemas oder Funktionen abhängt. In ihm werden die Deklarationen definiert, die die Umgebung für den Anfrage‐Körper bilden. Der Anfrage‐Körper besteht aus dem Ausdruck, der den Wert der Anfrage repräsentiert. Datenmodell: Die "Sequenz" bildet das zentrale Konstrukt und besteht aus einer Aneinanderreihung von atomaren Werten oder Knoten mit beliebiger Anzahl von Einträgen, wobei keine Schachtelung erlaubt ist. Sequenzen sind geordnet und die Sequenzeinträge sind damit hinsichtlich ihrer Position unterscheidbar; Duplikate sind möglich. Somit lassen sich einzelne Einträge einer Sequenz auf folgende Weise abrufen: let $sequenz := ("a","b","c")
return <buchstabe>{ $sequenz[2] }</buchstabe>
Ausgabe: <buchstabe>b</buchstabe>
Der Ausdruck: (1, "x", (), (<a/>, 4), "s") ist äquivalent zu:(1, "x", <a/>, 4, "s") Eine Sequenz mit einem Eintrag ist äquivalent zum Eintrag selbst, d.h. (5) ist äquivalent zu 5. Die einfachste Anfrage in XQuery ist ein XPath 2.0 Ausdruck! doc("buchliste.xml")//buch/titel[contains(.,"XQuery")]
XQuery 1.0 & XSLT 2.0 XSLT 20 und XQuery 1.0 wurden von zwei Arbeitsgruppen in enger Zusammenarbeit entwickelt, so dass sie in ihrer Funktionalität zu einem hohen Grad überlappen. Sie haben viele gemeinsame Konzepte, wie das zugrunde liegende Datenmodell, beide enthalten XPath 2.0 komplett als Untersprache, ... Beide Sprachen richten sich an unterschiedliche Bedürfnisse, die in unterschiedlichen Nutzergemeinschaften existieren. Daher konzentrieren sich viele nur auf eine der beiden Sprachen und vernachlässigen die andere. Einige Aufgaben können beide Sprachen sehr gut erfüllen, für andere ist jedoch die eine Sprache der anderen vorzuziehen. Daher ist die Kenntnis in beiden Sprachen wichtig, um abschätzen zu können, welche sich für ein gegebenes Problem besser eignet. Der Fakt, dass sie sich im Konzept sehr ähneln, heißt, dass man die andere dadurch auch leichter verstehen kann. Welche Sprache einem persönlich besser gefällt, muss jeder selbst entscheiden, da schwer entscheidbar ist, welche für einen selbst besser geeignet ist. Eine Kombination beider Sprachen ist bisher nicht vorhanden oder wenn doch nur in dem jeweils darauf spezialisierten Produkt. Somit muss man sich entscheiden, ob meine eine XML‐Datei nur mit XQuery, nur mit XSLT oder aber erst die eine Sprache verwendet und die andere nochmals auf das erzeugte Ergebnisdokument. Datentypen & Typumwandlung (Type Casting)
XQuery unterstützt alle vordefinierten Datentypen vom XML-Schema (Namensraumpräfix: xs).
Darüber hinaus wird die Menge der Datentypen durch "unspezifische Typen" erweitert. Diese finden
Verwendung, wenn keine eindeutige Zuordnung möglich ist.
Konstante Werte können als
•
•
•
Literale Kontruktor‐Funktionen Cast geschrieben werden. Literale String Literale werden von doppelten oder einfachen Hochkommas begrenzt. Steht ein
String in doppelten Hochkommas, kann er einfach Hochkommas enthalten; zwei
benachbarte doppelte Hochkommas werden als ein doppeltes Hochkomma interpretiert.
Dies gilt analog für einfache Hochkommas.
Bsp.:
"ein String"
'ein String'
"Dies ist ein 'String'!"
'Dies ist ein "String"!'
"ein "" oder ' grenzt ein String ab"
'ein " oder '' grenzt ein String ab'
--> string-literal.xq
--------------------------------------------------------------------------declare boundary-space preserve;
<text>{
for $i in ("ein String", 'ein String', "Dies ist ein 'String'!", 'Dies ist ein
"String"!')
return <string>{ $i }</string>
}</text>
----- Ergebnis ----<text>
<string>ein String</string>
<string>ein String</string>
<string>Dies ist ein 'String'!</string>
<string>Dies ist ein "String"!</string>
</text>
---------------------------------------------------------------------------
Desweiteren gibt es 3 Arten numerischer Literale: Jede Zahl kann optional ein Vorzeichen (+/‐) haben. •
•
•
xs:integer ‐ besteht nur aus Ziffern Bsp.: 4, -6, +3, ... xs:decimal ‐ besteht nur aus Ziffern und einem Dezimalpunkt Bsp.: 1.23, -1.23, ... xs:double ‐ besteht nur aus Ziffern, einem optionalen Dezimalpunkt und einem e oder E Bsp.: 1.2E3, -1.2E3, ... Konstruktor­Funktion Bsp.: xs:integer("12"), xs:gYear("2007"), ... Cast Bsp.: "12" cast as xs:integer, "2007" cast as xs:gYear, ... Beispiele für Casting (: Casting
von xs:gYear nach xs:integer nicht möglich, aber über
xs:gYear --> xs:string --> xs:integer
gleiches gilt für die Gegenrichtung
:)
<casting>
<gYear_to_integer>{
let $x := "2003" cast as xs:gYear
let $y := $x cast as xs:string
let $z := $y cast as xs:integer
return $z
}</gYear_to_integer>
<string_to_boolean>{
for $x in ("true","false")
return <bool>{$x cast as xs:boolean}</bool>
}</string_to_boolean>
<integer_to_boolean>{
for $x in (0,1)
return <bool>{$x cast as xs:boolean}</bool>
}</integer_to_boolean>
</casting>
Operatoren
•
•
•
•
•
•
•
•
skalare Vergleichsoperatoren: eq, ne, lt, le, gt, ge allgemeine Vergleichsoperatoren: =, !=, <, <=, >, >= Knoten Vergleichsoperatoren: is, isnot ‐ vergleicht die Identität zweier Knoten Reihenfolge‐Operatoren: $knoten1 << $knoten2 bzw. $knoten2 >> $knoten1 Negator: not Logische Operatoren: and, or Komma‐Operator: , ‐ verknüpft zwei Werte um eine Sequenz zu formen (2, 5),(8) ==> (2, 5, 8) to‐Operator: to ‐ gibt eine Sequenz zurück, die aus allen Integern zwischen dem linken und dem rechten Operanden (inklusive) besteht (2 to 4) ==> (2, 3, 4) Beispiele Beim Vergleich zweier Sequenzen mit allgemeinen Verlgeichsoperatoren erhält man true, sobald auch nur ein Paar(a,b) diese Bedingung erfüllt, wobei a ein Eintrag der ersten Sequenz und b ein Eintrag der zweiten Sequenz ist. Es wird somit ein existenzieller Vergleich durchgeführt. let $a := (1,2,3), $b := (3,4,5), $c := (4,5,6)
return
<res>
<a_eq_b> { $a = $b } </a_eq_b>
<a_ne_b> { $a != $b } </a_ne_b>
<a_gt_b> { $a > $b } </a_gt_b>
<a_lt_b> { $a < $b } </a_lt_b>
<a_eq_c> { $a = $c } </a_eq_c>
<a_ne_c> { $a != $c } </a_ne_c>
<a_gt_c> { $a > $c } </a_gt_c>
<a_lt_c> { $a < $c } </a_lt_c>
</res>
<res>
<a_eq_b>
<a_ne_b>
<a_gt_b>
<a_lt_b>
<a_eq_c>
<a_ne_c>
<a_gt_c>
<a_lt_c>
</res>
true </a_eq_b>
true </a_ne_b>
false </a_gt_b>
true </a_lt_b>
false </a_eq_c>
true </a_ne_c>
false </a_gt_c>
true </a_lt_c>
Mit skalaren Vergleichsoperatoren lassen sich Werte vergleichen. Nutzt man diese zum Vergleichen von Sequenzen tritt ein Fehler auf! Vergleich zweier Knoten: let $a
$b
$c
$d
let $x
return
<a>
<!-<aa>
<ab>
<ac>
<ad>
<!-<aa>
<ab>
<ac>
<ad>
</a>
:=
:=
:=
:=
:=
(<a>XQuery</a>),
(<a>XQuery</a>),
(<b>XQuery</b>),
(<a>XML</a>)
($a, $a, $b, $c, $d)
Identitätsvergleich -->
{ $x[1] is $x[2] } </aa>
{ $x[1] is $x[3] } </ab>
{ $x[1] is $x[4] } </ac>
{ $x[1] is $x[5] } </ad>
Wertevergleich -->
{ $x[1] = $x[2] } </aa>
{ $x[1] = $x[3] } </ab>
{ $x[1] = $x[4] } </ac>
{ $x[1] = $x[5] } </ad>
<a>
<!-<aa>
<ab>
<ac>
<ad>
<!-<aa>
<ab>
<ac>
<ad>
</a>
Identitätsvergleich -->
true </aa>
false </ab>
false </ac>
false </ad>
Wertevergleich -->
true </aa>
true </ab>
true </ac>
false </ad>
Es ist eindeutig erkennbar, dass mit ‘is‘ bzw. ‘is not‘ ein Identitätsvergleich zweier Knoten durchgeführt wird, wobei die allgemeinen Operatoren nur die Werte vergleichen! Arithmetik
•
Übliche Operationen: o
o
o
o
o
•
Aggregatfunktionen: o
o
o
o
o
•
Addition: + Subtraktion: - Multiplikation: * Division: div Modulo: mod
Summe: sum Durchschnitt: avg Anzahl: count Maximum: max Minimum: min
Operationen auf Sequenzen: o
o
o
Vereinigung: union Durchschnitt: intersect Differenz: except Beispiele <aggregate>
<plus>{ 5 + 2 }</plus>
<minus>{ 5 - 2 }</minus>
<mal>{ 5 * 2 }</mal>
<div>{ 5 div 2 }</div>
<mod>{ 5 mod 2 }</mod>
</aggregate>
<aggregate>
<plus>7</plus>
<minus>3</minus>
<mal>10</mal>
<div>2.5</div>
<mod>1</mod>
</aggregate>
let $x := (9,7,3,6,7,3,21,11,8,3,6,15)
return <aggregate>
<sum>{ fn:sum( $x ) }</sum>
<avg>{ fn:avg( $x ) }</avg>
<count>{ fn:count( $x ) }</count>
<max>{ fn:max( $x ) }</max>
<min>{ fn:min( $x ) }</min>
<aggregate>
<sum>99</sum>
<avg>8.25</avg>
<count>12</count>
<max>21</max>
<min>3</min>
</aggregate>
</aggregate>
let $a := <a/>,
$b := <b/>,
$c := <c/>
let $seq1 := ($a, $b),
$seq2 := ($a, $b),
$seq3 := ($b, $c)
return <res>
<seq1_union_seq2>{ $seq1 union $seq2
}</seq1_union_seq2>
<seq2_union_seq3>{ $seq2 union $seq3
}</seq2_union_seq3>
<seq1_intersect_seq2>{ $seq1 intersect $seq2
}</seq1_intersect_seq2>
<seq2_intersect_seq3>{ $seq2 intersect $seq3
}</seq2_intersect_seq3>
<seq1_except_seq2>{ $seq1 except $seq2
}</seq1_except_seq2>
<seq2_except_seq3>{ $seq2 except $seq3
}</seq2_except_seq3>
</res>
<res>
<seq1_union_seq2>
<b/>
<a/>
</seq1_union_seq2>
<seq2_union_seq3>
<c/>
<b/>
<a/>
</seq2_union_seq3>
<seq1_intersect_seq2>
<b/>
<a/>
</seq1_intersect_seq2>
<seq2_intersect_seq3>
<b/>
</seq2_intersect_seq3>
<seq1_except_seq2/>
<seq2_except_seq3>
<a/>
</seq2_except_seq3>
</res>
Konstruktoren
Elementkonstruktoren wie <Element>...</Element> stehen für sich selbst. Ausdrücke, die zwischen geschweiften Klammern stehen, werden ausgerechnet und das Ergebnis eingefügt. berechnete Elementkonstruktoren werden wie folgt notiert: element $ename { attribute $aname { $value }, $content }
$ename steht hierbei für den Elementnamen, $aname für den Names des Attributs, $value für den Attributwert und $content für den Elementinhalt. Beispiele element kunde
<kunde/>
element kunde {
attribute kunden_nr { 123 },
"Gerd Gans"
}
<kunde kunden_nr="123">Gerd Gans</kunde>
bzw. <kunde>{
attribute kunden_nr { 123 },
"Gerd Gans"
}</kunde>
<kunde kunden_nr="123">Gerd Gans</kunde>
element kunde {
attribute kunden_nr { 123 },
element vorname { "Gerd" },
element nachname { "Gans" },
element adresse {
element strasse { "Musterweg 3a" },
element ort {
attribute plz { 01234 },
"Musterdorf"
}
}
}
<kunde kunden_nr="123">
<vorname>Gerd</vorname>
<nachname>Gans</nachname>
<adresse>
<strasse>Musterweg 3a</strasse>
<ort plz="1234">Musterdorf</ort>
</adresse>
</kunde>
FLWOR-Ausdrücke
FLWOR-Ausdrücke bilden die Basis für Anfragen auf XML-Datenbanken.
Das Akronym FLWOR (gesprochen wie engl.: flower) steht für:
•
•
•
•
•
for: Iteration durch Eingabesequenz, Variablenbindung bei jedem Durchlauf
let: Variablendeklaration und Wertzuweisung (keine Iteration!)
where: Filter (mit for verwendet)
order by: Sortieren der Werte
return: Ergebniskonstruktion
Ein FLWOR-Ausdruck muss mindestens eine let- oder for-Klausel enthalten, sowie eine return-Klausel
for- und let-Klauseln können beliebig oft und in beliebiger Reihenfolge stehen. Bei der where-, order
by- und return-Klausel ist die Reihenfolge zu beachten!
FLWOR-Ausdrücke sind analog zu SELECT-FROM-WHERE in SQL.
for
- Iteration über eine/mehrere Sequenz/en von Werten, über die eine/mehrere Variable(n) aufgezählt
werden soll(en)
for $i in (1 to 3)
(: bzw.: for $i in (1,2,3) :)
return <tupel>{$i}</tupel>
Ausgabe:
<tupel>1</tupel>
<tupel>2</tupel>
<tupel>3</tupel>
Weitere Beispiele:
for $b in doc("buchliste.xml")/buchliste/buch
let $a := $b/autor
return <autor>{$a}</autor>
gibt alle Autoren zurück
Geschachtelte for-Klauseln
for $i in (2, 3), $j in (4, 5)
return <res>{$i*$j}</res>
Ausgabe:
<res>8</res>
<res>10</res>
<res>12</res>
<res>15</res>
let
- mit let kann man atomare Werte oder XML-Fragmente an eine Variable binden, z.B.
let $buch := doc("buchliste.xml")/buchliste/buch[1]/titel
let $zahl := 5, $folge := (1,2,3)
Zuweisungsoperator: ":="
Variablennamen beginnen mit "$"
let $i := (1 to 3) (: entspricht let $i := (1,2,3) :)
return <tupel>{ $i }</tupel>
Ausgabe:
<tupel>123</tupel>
where
Die where-Klausel dient zur Selektion und Filterung der Ergebnismenge.
order
by
Ein FLWOR-Ausdruck ohne 'order by'-Klausel gibt das Ergebnis in Dokumentenreihenfolge aus.
Wird eine order by-Klausel verwendet, kann das Ergebnis nach einem oder mehreren Werten
aufsteigend (ascending) bzw. absteigend (descending) geordnet werden.
Beispiel:
In der Datei gehaltsliste.xml werden die Namen, sowie das Gehalt des Personals gespeichert.
Die Daten sollen tabellarisch nach Namen aufsteigend und nach Gehalt absteigend sortiert werden!
<table><th>Name</th><th>Gehalt</th>{
for $i in doc("gehaltsliste.xml")//person
order by $i/nachname ascending, $i/vorname ascending, $i/gehalt cast as xs:decimal
descending
return <tr><td>{ $i/nachname/text() }, { $i/vorname/text() }</td><td>{
$i/gehalt/text() } EUR</td></tr>
}</table>
Besitzt wie in diesem Fall die Quelldatei ("gehaltsliste.xml") kein XML-Schema, muss eine
Typkonvertierung vorgenommen werden, falls numerisch sortiert werden soll!
Liefert das Sortierkriterium keine eindeutige Reihenfolge, so ist die Anordnung der Duplikate
implementierungsabhängig. Ein der order by-Klausel vorangestellender Zusatz stable erzwingt in
diesem Fall die Einhaltung der Dokumentenreihenfolge.
Existieren Eigenschaften nicht, nach denen sortiert wird, so kann mit dem Sortierungsmodifikator empty
greatest bzw. empty least die Einordnung dieser Einträge explizit gesteuert werden.
return
Die return-Klausel konstruiert das Ergebnis.
Verbundoperationen (Joins)
... durch Wertegleichheit Verbundprädikat in der where‐Klausel for $person in doc("personen.xml")//person
where $person//name = 'Karl Schmidt'
return $person
Verbundprädikat im Pfadausdruck doc("personen.xml")//person[.//name = 'Karl Schmidt'] ... durch Verfolgung von Referenzen Dieses Beispiel funktioniert nicht unter Oracle oder Altova XMLSpy! Gegeben sind für dieses Beispiel folgende Dokumente: join‐ref.xml mit zugehörigem Schema join.xsd Folgender XQuery-Ausdruck würde als Ergebnis eine Sequenz von Büchern mit Titel
und Autor wie rechts abgebildet liefern:
for $titel in doc("1.xml")//titel
let $autor := id($titel/@autor)
return <buch>{$titel,$autor}</buch>
<buch>
<titel>Harry Potter und der Stein der
Weisen</titel>
<autor>J. K. Rowling</autor>
</buch>
<buch>
<titel>Harry Potter und die Kammer des
Schreckens</titel>
<autor>J. K. Rowling</autor>
</buch>
<buch>
<titel>Der Herr der Ringe</titel>
<autor>J. R. R. Tolkien</autor>
</buch>
Da dies, wie erwähnt, leider noch nicht unterstützt wird, wird hier auf ein analoges Beispiel mittels XSLT verwiesen: <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="//titel">
<buch>
<titel>
<xsl:value-of select="."/>
</titel>
<autor>
<xsl:value-of select="id(@autor)"/>
</autor>
</buch>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Outer Join Ein Outer Join wird durch Schachtelung zweier FLWOR‐Ausdrücke ermöglicht. Beispiele Gegeben sind die Dokumente "personen.xml" mit einer eindeutigen Personennummer (pnr), dem Personennamen und der Stadt. Desweiteren gibt es eine Liste mit E‐Mailadressen ("personen‐email.xml") mit den Personennummern und E‐Mail‐Adressen. Es soll eine Liste mit Namen und E‐Mail‐Adressen ausgegeben werden, wobei es nicht zu jeder pnr in "personen.xml" auch eine pnr in "personen‐email.xml" gibt. Somit muss ein Outer‐Join erfolgen, der wie folgt aussieht: <res>{
for $person in doc("personen.xml")//person
return <person>{
$person/*, (
for $person2 in doc("personen-email.xml")//person
where $person/@pnr = $person2/@pnr
return $person2/email
)
}</person>
}</res>
<res>
<person>
<name>Karl Schmidt</name>
<email>[email protected]</email>
</person>
<person>
<name>Max Zander</name>
<email>[email protected]</email>
</person>
<person>
<name>Uwe König</name>
</person>
<person>
<name>Maria Abel</name>
<email>[email protected]</email>
</person>
<person>
<name>Albert Brecht</name>
</person>
</res>
Gruppierungen
In XQuery lassen sich ohne großen Aufwand leicht Gruppierungen durchführen. Oft hat man eine Datenquelle, die nach einem Kriterium gruppiert werden soll. In diesem Fall wird mit Hilfe der distinct-values‐Funtkion eine Liste unterschiedlicher werte gebildet und dann in der äußeren return‐Klausel über die Daten iteriert. Beispiele Gegeben ist das Dokument "personen.xml" mit einer eindeutigen Personennummer (pnr), dem Personennamen und der Stadt. Die Namen der Personen sollen nach den Städten gruppiert werden. <res>{
for $stadt in distinct-values(doc("personen.xml")//stadt)
return element { $stadt } { doc("personen.xml")//name[../stadt = $stadt] }
}</res>
(: alternativ mit FLWOR-Ausdruck
<res>{
for $stadt in distinct-values(doc("personen.xml")//stadt)
return element { $stadt } {
for $person in doc("personen.xml")//person
where $person/stadt = $stadt
return $person/name }
}</res> :)
<res>
<Leipzig>
<name>Karl Schmidt</name>
<name>Uwe König</name>
</Leipzig>
<München>
<name>Max Zander</name>
</München>
<Köln>
<name>Maria Abel</name>
<name>Albert Brecht</name>
</Köln>
</res>
If-then-else-Anweisung
Hierbei wird die gewohnte if‐then‐else‐Notation verwendet: if ( Bedingung )
then Ausdruck_1 else Ausdruck_2 Das else in der If‐then‐else‐Anweisung muss vorhanden sein. Wird es nicht benötigt, übergibt man einfach eine leere Sequenz! Beispiele <res>{
for $zahl in (3,8,2,5)
return if( $zahl mod 2 = 0 )
then <x>{ $zahl, " ist eine gerade Zahl." }</x>
else <x>{ $zahl, " ist eine ungerade Zahl." }</x>
}</res>
<res>
<x>3
<x>8
<x>2
<x>5
</res>
ist
ist
ist
ist
eine
eine
eine
eine
ungerade Zahl.</x>
gerade Zahl.</x>
gerade Zahl.</x>
ungerade Zahl.</x>
Quantoren
Um zu testen, ob eine Bedingung für einige Werte bzw. für alle Werte einer Sequenz zutrifft, werden quantifizierte Ausdrücke verwendet. Diese geben einen booleschen Wert zurück und werden folgendermaßen notiert: ("some"|"every") $var "in" Sequenz "satisfies" Bedingung Beispiele <res>{
for $zahlen in (<x><a>
<b>2</b>
<b>4</b>
<b>6</b>
</a><a>
<b>1</b>
<b>3</b>
<b>5</b>
</a><a>
<b>1</b>
<b>4</b>
<b>6</b>
</a></x>)//a
where some $zahl in $zahlen/b satisfies $zahl mod 2 = 0
return $zahlen
}</res>
<res>
<a>
<b>2</b>
<b>4</b>
<b>6</b>
</a>
<a>
<b>1</b>
<b>4</b>
<b>6</b>
</a>
</res>
<res>{
for $zahlen in (<x><a>
<b>2</b>
<b>4</b>
<b>6</b>
</a><a>
<b>1</b>
<b>3</b>
<b>5</b>
</a><a>
<b>1</b>
<b>4</b>
<b>6</b>
</a></x>)//a
where every $zahl in $zahlen/b satisfies $zahl mod 2 = 0
return $zahlen
}</res>
<res>
<a>
<b>2</b>
<b>4</b>
<b>6</b>
</a>
</res>
Namensräume
Zu einem Namensraum gehört ein Präfix und eine URI (Uniform Resource Identifier).
Er wird folgendermaßen deklariert:
declare namespace Präfix = URI;
XQuery hat mehrere vordefinierte Namensräume, die somit nicht deklariert werden müssen! Diese Namensräume können bis auf den xmlNamensraum überschrieben und neu deklariert werden!
•
xml = http://www.w3.org/XML/1998/namespace
•
xs = http://www.w3.org/2001/XMLSchema
•
xsi = http://www.w3.org/2001/XMLSchema-instance
•
fn = http://www.w3.org/2005/xpath-functions
•
local = http://www.w3.org/2005/xquery-local-functions
Vordefinierte Funktionen
In diesem Tutorial wird auf den Namespace 'fn' bei vordefinierten Funktionen verzichtet, da dieser bei XPath‐Ausdrücken nicht angegeben wird! Auf dieser Seite soll jedoch gezeigt werden, wie die ausführliche Schreibweise der Funktionen ist! Zeichenfunktionen Beispiele: <string_functions>
<concat>{
fn:concat("XQuery"," ","ist ","eine",()," umfangreiche ","Anfragesprache ","für ","XML.")
}</concat>
<string-join>{
fn:string-join(("XQuery","ist","eine","umfangreiche","Anfragesprache","für","XML.")," ")
}</string-join>
<string-length>{
fn:string-length("XQuery ist eine umfangreiche Anfragesprache für XML.")
}</string-length>
</string_functions>
Ergebnis: <string_functions>
<concat>XQuery ist eine umfangreiche Anfragesprache für XML.</concat>
<string-join>XQuery ist eine umfangreiche Anfragesprache für XML.</string-join>
<string-length>52</string-length>
</string_functions>
Benutzerdefinierte Funktionen
XQuery bietet neben den vordefinierten Funktionen auch die Möglichkeit benutzerdefinierte Funktionen anzulegen. Diese können sowohl im gleichen Ausdruck als auch in einer seperaten Bibliothek (Modul) sein. Im Gegensatz zu vordefinierten Funktionen, muss bei benutzerdefinierten Funktionen ein Namensraum angegeben werden! declare function prefix:function_name($parameter as datatype) as returnDatatype {
(: function code here ... :)
};
Benutzerdefinierte Funktionen beginnen mit declare function und müssen ein Präfix besitzen. Lokale Funktionen haben das Präfix local. Die Datentypen entsprechen den Datentypen des XML‐Schemas. Der Funktionskörper befindet sich in den geschweiften Klammern. Funktionen können rekursiv sein. Wenn kein Rückgabetyp festgelegt wird, ist der Defaultrückgabetyp AnyType. Beispiele declare function local:nachfolger( $n as xs:integer ) as xs:integer {
$n + 1
};
<nachfolger>Der Nachfolger von 4 ist { local:nachfolger(4) }</nachfolger>
declare function local:fakul( $n as xs:integer ) as xs:integer {
if ($n = 0)
then 1
else $n * local:fakul($n - 1)
};
<fakul>Fakultät von 5 ist { local:fakul(5) }</fakul>
Benutzerdefinierte Funktionen können auch in externen Dateien deklariert werden, in sogenannten Modulen. Funktionen, die in Modulen stehen, besitzen ebenfalls einen Namensraum, der sich von den vordefinierten Namensräumen unterscheiden sollte. Zusätzlich zu Funktionen, kann man lokal und in Modulen auch Variablen deklarieren! math_module.xq xquery version "1.0" encoding "UTF-8";
module namespace math="http://www.xquery-tutorial.de/math";
declare function math:vorgaenger( $n as xs:integer ) as xs:integer {
$n - 1
};
declare variable $math:x := 12;
using_math_module.xq xquery version "1.0" encoding "UTF-8";
import module namespace math="http://www.xquery-tutorial.de/math" at "math_module.xq";
<results>
<res>{
math:vorgaenger( 9 )
}</res>
<res>{
math:vorgaenger( $math:x )
}</res>
</results>
Herunterladen