Das XQuery-Datenmodell Gliederung • • • • • • • • Sequenzen Atomare Werte Knoten Knoteneigenschaften Sequenztypen und Knotenzugriffsfunktion Typabfrage Gleichheit von Sequenzen Zusammenfassung Das XQuery-Datenmodell • Das Datenmodell ist eine interne Darstellung eines XML Dokumentes. Zentraler Konstrukt ist eine Sequenz mit einer beliebigen Anzahl von Einträgen (atomare Werte oder Knoten), die eine Position haben. Struktur einer Sequenz • Eine Sequenz besteht aus keinem, einem oder mehreren Einträgen („items“) atomarer Wert oder Knoten • Die einzelnen Einträge werden aneinander gereiht durch Komma getrennt. • Eine Klammerung ist oft nicht notwendig verdeutlicht aber die Sequenzbildung • Eine leere Sequenz wird durch () dargestellt, sie ist aber von „Nichts“ zu unterscheiden • Auch ein einzelner Wert ist eine Sequenz • Sequenzen können nicht ineinander verschachtelt sein • Eine Sequenz ist geordnet und hat keine Mengeneigenschaften Duplikate Beispiele identischer Sequenzen • (1,2,1) und (1,(2,1)) liefert eine Sequenz aus drei Zahlen • (1, (),<B/>) und (1, <B/>) liefert eine Sequenz aus Zahl und Knoten • (<A/>) und <A/> liefert eine Sequenz mit nur einem Eintrag • () und ( (), () ) liefert die leere Sequenz Funktionen und Operationen auf Sequenzen • Da jeder Ausdruck in XQuery eine Sequenz ergibt, sind alle Funktionen in XQuery Funktionen auf Sequenzen • Man unterscheidet 2 Gruppen, die sich mit der Struktur von Sequenzen befassen: Kardinalität von Sequenzen und Veränderung von Sequenzen - Bei der Syntaxdarstellung werden die Parameter, die Sequenzen darstellen, mit $seq benannt - Die Notation item()* steht für einen allgemeinen Sequenztyp Kardinalität von Sequenzen Signatur Beschreibung fn:zero-or-one ($seq as item() *) as item() ? Eingabesequenz höchstens einen Eintrag, sonst Fehler fn:one-or-more ($seq as item() *) as item() + Eingabesequenz mindestens einen Eintrag, sonst Fehler fn:exactly-one ($seq as item() *) as item() Eingabesequenz genau einen Eintrag, sonst Fehler fn:empty ($arg as item() *) as xs:boolean True Eingabesequenz leer, sonst false fn:exists ($arg as item() *) as xs:boolean True Eingabesequenz nicht leer, sonst Fehler fn:count ($seq as item() *) as xs:integer Anzahl der Einträge einer Sequenz Veränderung von Sequenzen • Mit diesem Operator kann man auch einzelne Einträge an eine Sequenz anfügen: let $seq := (1,2,3) return ($seq,4) liefert (1,2,3,4) • Mit der Funktion fn:insert-before() kann man auch an andere Stellen der Sequenz Einträge einfügen. Das Löschen von Einträgen geht mit der Funktion fn:remove() • Die Reihenfolge der Einträge in einer Sequenz kann mit fn:reverse() umgedreht werden • Mit fn:subsequence() kann man einen Ausschnitt aus einer Sequenz bilden, indem Startposition und Anzahl der Elemente angegeben werden. • Die Funktion fn:unordered() gibt den Verzicht auf eine bestimmte Reihenfolge wieder Beispiele • let $seq := („E1“,“E2“,“E3“,“E4“,E5“) return fn:insert-before (fn:remove ($seq, 3), 3, „Neu“) Ergebnis: („E1“,“E2“,“Neu“,“E4“,“E5“) - let $seq := (6,5,4,3,2,1,0) return subsequence( ($seq, fn:reverse ($seq)), fn:count ($seq) div 2, fn:count ($seq)) Ergebnis: (3,2,1,0,0,1,2) Veränderungen von SequenzenFunktionen Signatur Beschreibung fn:insert-before ($seq as item()*, $position as xs:integer,$seqneu as item()*) as item()* Neue Sequenz Einträge werden aus der Sequenz $seqneu an Position $position in die Sequenz $seq eingeschoben fn:remove ($seq as item()*, $position as xs:integer) as item()* Neue Sequenz der Eintrag in $seq wird an Position $position entfernt fn:reverse ($seq as item()*) as item()* Neue Sequenz mit allen Einträgen aus $seq in umgekehrter Reihenfolge fn:subsequence ($seq as item()*, $start as xs:double[,$length as xs:double] ) as item()* Neue Sequenz beginnend mit dem Eintrag an Position round ($start) in $seq, Rest von $seq wenn $length fehlt fn:unordered ($seq as item()*) as item ()* Sequenz enthält alle Einträge aus $seq, Reihenfolge unbestimmt Atomare Werte • Atomare Werte sind Instanzen eines einfachen Typs bzw. von XML Schema, z.B. Zeichenketten wie „Emma Müller“ oder Zahlen, z.B. 1.0. • Werte von den Typen durch Vereinigung oder Listenbildung sind keine atomaren Werte. Konstruktoren • Konstruktoren sind dafür da, in einem XQuery-Ausdruck einen Wert eines bestimmten Typs anzugeben, z.B. als Vergleichswert. • xs:float (1) bezeichnet einen Wert des Datentyps xs:float. Literale für Zeichenketten • Zeichenketten, die in einfache oder doppelte Anführungszeichen stehen, gelten als Werte vom Typ xs:string, z.B.: `Dies ist ein Literal vom Typ xs:string` „Solche Literale sind in““ oder `eingeschlossen“ • Die Anführungszeichen kann man auch im Literal selbst verwenden, wenn man sie verdoppelt. Operationen und Funktionen auf Sequenzen atomarer Werte • Eine Sequenz aus Werten vom Typ xs:integer kann mit dem to-Operator erzeugt werden: 3 to 7 die Sequenz (3,4,5,6,7) • Die Funktion fn:index-of() kann die Positionen innerhalb der Sequenz liefern, an denen ein atomarer Wert steht, der gleich dem Suchausdruck ist. Wird der Ausdruck nicht gefunden, so ergibt sich eine leere Sequenz. Der erste Eintrag einer Sequenz steht auf 1 nicht auf 0! Z.B: fn:index-of( (1,0,0,1), 1) (1,4) • Die Funktion fn:distinct-values() eliminiert Duplikate in Sequenzen. Das Ergebnis enthält alle verschiedene Werte, wobei die Reihenfolge abhängig ist von der XQuery-Implementierung. Funktionen auf Sequenzeinträgen Signatur Beschreibung Op:to ($firstval as xs:integer, Sequenz ganzzahliger Werte, die $lastval as xs:integer) as xs:integer* zwischen den beiden Werten der Parameter liegen fn:index-of Liefert alle Positionen, an denen ein Eintrag steht, der gleich dem gesuchten Wert ist. fn:distinct-values Liefert alle verschiedenen Werte aus der Eingabesequenz Knoten Elementknoten • Ein Elementknoten repräsentiert ein Element aus XML 1.0. • Der textuelle Wert eines Elementknotens ergibt sich aus der Verkettung aller Textknoten, die diesem Knoten folgen • Wenn das Element keinen komplexen Inhalt hat (nicht nur Kindelemente), hat das Element einen getypten Wert. • Beispiel: der getypte Wert hat den Typ xs:integer XML Schema: einfacher Typ xs:integer! Hat das Element den Typ xdt:untypedAny (unbest.komplexer Typ) ist der getypte Wert vom Typ xdt:untypedAtomic (unbest.atomarer Typ). Erzeugung eines Elementknotens • Der direkte Elementkonstruktor: benutzt die vertraute XML-Notation, z.B. <Arzt ID=„Arzt_01“>Hans Müller</Arzt> • Referenzen auf vordefinierte Entitäten (z.B. &lt;) und Zeichenreferenzen (z.B. &#x20;) in Attributwerten und Elementinhalten sind erlaubt, sie werden aber bei der Konstruktion aufgelöst: <Fähigkeit>Altenbetreuung &amp; Altenpflege</Fähigkeit> • Der berechnete Elementkonstruktor muss eingesetzt werden, wenn auch der Name eines Elementes berechnet werden soll • „element“ „{„ Ausdruck_der_den_Namen_berechnet „}“ oder Ausdruck_der_den_Inhalt_berechnet z.B.: element Labortest { attribute ID {„Labortest_040782“}, element Nummer {1}, <Name>Röntgen</Name> element Datum {„2002-05-10“}, } Gemeinsame Regeln für beide Konstruktorarten • Das Präfix muss definiert sein, entweder im XQuery-Prolog oder im Element selbst. • Das Element wird automatisch gegen die bekannten Schemadefinitionen validiert und bekommt ggf. einen Typ zugewiesen. Dokumentknoten • Einen Dokumentknoten repräsentiert ein XMLDokument. • Der textuelle Wert eines Dokumentknotens ergibt sich aus der Verkettung der textuellen Werte aller Textknoten, die dem DK folgen. • Ein DK kann in XQuery mit einem berechneten Konstruktor erzeugt werden, z.B. document {<Arzt>Emil Müller</Arzt>} • Die Knoten, die als Kinder dieses DKs angefügt werden, verlieren jegliche Typinfo und ihnen werden die Typen xs:anyType (Elementknoten) und xs:anySimpleType (Attributknoten) zugewiesen. Attributknoten • Attributknoten entsprechen den Attributen von XML- Elementen. • Der textuelle Wert ergibt sich aus dem Attributwert, gewandelt nach xs:string. • Einen Attributknoten kann man über einen berechneten Konstruktor erzeugen, bei dem auf das Schlüsselwort „attribute“ der Name des Attributs und sein Wert folgen, z.B. attribute {$a} {6*7} Kommentarknoten • Ein Kommentarknoten entspricht einem Kommentar in einem XML- Dokument. • Der textuelle Wert besteht aus dem Inhalt des Kommentars und dem getypten Wert (Wert vom Typ xs:string). • Direkter Konstruktor: <!- -Dies ist ein Kommentar - -> • Berechneter Konstruktor: comment {„Dies ist ein Kommentar“} Textknoten • Ein Textknoten ist der einfache Inhalt eines Elementes, unabhängig von seinem Typ. • Direkter Konstruktor: <![CData[Dies ist der Inhalt des Textknotens]]> • Berechneter Konstruktor: text {„Dies ist der Inhalt des Textknotens“} Knoteneigenschaften Dokumentreihenfolge • Die Dokumentordnung ist eine Ordnung der Knoten in der Dokumentreihenfolge: • Der Elternknoten wird vor seinen Kindern besucht. Der Namensraumknoten eines Elements werden vor den Attributknoten desselben Elementes besucht. Die Attributknoten werden vor den Kindern eines Elementknotens besucht und die Geschwisterknoten werden in der gleichen Reihenfolge besucht wie im XML- Dokument • Eliminierung identischer Knoten durch Entfernung von Duplikaten Funktionen auf Knoten • Auf den Namen eines Knotens kann man mit den XQuery- Funktionen fn:node-name() und fn:name() zugreifen. • Wenn der Knoten keinen Namen hat wird eine leere Zeichenkette geliefert, sonst der Name • Bei Attributen und Elementen kann der Name aus einem Namensraum stammen • fn:node-name() Name als expandierten QName kein Namensraumpräfix • fn:name() String in der syntaktischen Form eines QName Namensraumpräfix gebraucht • Oft sinnvoll auf den lokalen Namen und der URI separat zuzugreifen: fn:local-name() und fn:namespace-uri(), z.B. <A xmlns= „http://x“/> local-name:A, namespaceuri:http://x • Die in einem Knoten zugeordnete Wurzel des Knotenbaumes wird mit der Funktion fn:root() adressiert, z.B. fn:root (<Arzt/>) • Textueller Wert eines Knotens fn:string • Zugriff auf den getypten Wert mittels fn:data(), z.B.: fn:string (<Name> <Vorname>Daniela</Vorname> <Nachname>Baumann</Nachname> </Name>) • fn:data(<Geburtstagsdatum>1982-0723</Geburtstagsdatum>) • Zur Behandlung numerischer Daten benutzt man fn:number(). Diese Funktion erzeugt aus einem Knoten einen Wert des Typs xs:double meldet einen Fehler, wenn das Argument eine leere Sequenz ist oder nicht von xs:double stammt. • Z.B.: Es gilt: fn:number (<A><B>1</B><C>2</C><A/>) =12.0 fn:number (<A><B>1.0</B><C>2.0</C></A>) Sequenztypdefinitionen: Häufigkeitsangaben Symbol Bedeutung (keines) Sequenz mit genau einem Eintrag ? Sequenz mit höchstens einem Eintrag + Sequenz mit mindestens einem Eintrag empty() Leere Sequenz * Sequenz mit unbeschränkter Anzahl von Einträgen Eintragstypen • Der allgemeinste Eintragstyp item() lässt sowohl atomare Werte als auch Knoten zu • Als atomare Typen können alle in XML Schema definierten einfachen Typen, wie z.B.: xs:integer+ mein Namensraum:meine Schuhgröße? XQuery gibt nicht nur den Typ an, sondern auch jeden davon mit durch Erweiterung oder Restriktion abgeleiteten Typ Knotentypen Knotentyp Bedeutung node() document-node() Beliebiger Knoten Ein Dokumentknoten document-node(element(…)) Ein Dokumentknoten, wobei das Dokument als Wurzelelement ein Element hat text() Ein Textknoten comment() Ein Kommentarknoten processing-instruction() Ein Verarbeitungsanweisungskn processing-instruction(Ziel) oten Knotentyp element(), element(*) Ein beliebiger Elementknoten element(Name) Ein bestimmtes Element element(Name,Typ) Ein Element mit bestimmtem Namen und Typ attribute(), attribute(*) Ein beliebiges Attribut attribute(Name) ein bestimmtes Attribut attribute(Name,Typ) Ein Attribut mit bestimmtem Namen und Typ • Werden für ein Element Name und Typ angegeben, werden alle Elemente akzeptiert, die diesen Namen haben, z.B.: element (Angestellte, Angestellte_T) • Der Typ des Elementes kann auch beliebig sein, z.B.: element (Krankenwagenfahrer, *) • Ein Element mit leerem Inhalt und dem Attribut xsi:nil=„true“ wird nur akzeptiert, wenn das Schlüsselwort nillable hinzugefügt wird: <Gehalt xsi:nil=„true“/> element (*, xs:integer nillable) • element (Krankenwagenfahrer) führt zu einem Fehler, da dieses Element nicht definiert wurde • Element (Angestellte) akzeptiert ein Arzt- Element, da er zu seiner Ersetzungsgruppe gehört • XQuery erlaubt auch die Angabe eines Kontextpfades, z.B. element (Operation/Beginn) • Falls es eine Typdefinition ist: element (type(Person_T)/E-Mail) Operationen auf Sequenzen aus Knoten • Sequenzen von Knoten kann man miteinander kombinieren, indem man den Durchschnitt, die Vereinigung oder die Differenz bildet • Sequenzen werden hier temporär als Menge betrachtet • Die Ergebnisse der Sequenzoperationen union, intersect und except sind immer nach der Dokumentordnung sortiert. Beispiel • Let $doc := document {<Wurzel> ERGEBNIS: <A>1</A> <A-Sequenz> <A>1</A> <A>3</A <B>2</B> ></A-Sequenz> <A>3</A> <B-Sequenz> <B>4</B> <B>2</B <B>4</B> ></B-Sequenz> </Wurzel>} Let $a := $doc//A Let $b := fn:reverse($doc//B) Return (<A-Sequenz>{$a}</A-Sequenz>, <B-Sequenz>{$b}</B-Sequenz>, <Vereinigung>{$a | $b}</Vereinigung>, <Differenz>{$b excerpt $a}</Differenz>, <Durchschnitt>{$b intersect $b}</Durchschnitt>) Typabfrage • XQuery stellt zur Abfrage des Typs eines Sequenzwertes die Ausdrücke instance of und typeswitch zur Verfügung. • Instance of liefert den Wert true, wenn der Typ des ersten Operanden mit dem zu überprüfenden Datentyp übereinstimmt, z.B.: let $a :=xs:integer(4711) where $a instance of xs:integer and $a instance of xs:decimal and $a instance of item() return <Text>Dieser Text wird erscheinen</Text> • Die Typüberprüfung ist nicht nur für atomare Typen, sondern für alle Sequenztypen möglich: <Text>bla bla</Text> instance of element (*,xs:string) • Ein typeswitch- Ausdruck entspricht der bekannten switch- Anweisung, aber es entscheidet hier nicht der Wert sondern der Typ des Auswahlausdrucks. Ein typeswitch- Ausdruck besteht aus einer zu überprüfenden Ausprägung eines Sequenztyps (Angestellter für die Variable $a) und einer Liste von Fällen, die zu überprüfen sind. • Falls keine Typübereinstimmung erzielt werden kann, wird der Ausdruck in der default-Klausel ausgewertet und als Rückgabewert verwendet • Hängt der Rückgabewert in einer case- oder defaultKlausel von der zu untersuchenden Sequenz ab, so kann darauf zurückgegriffen werden, indem eine zusätzliche Variable angegeben wird. Beispiel • typeswitch ($a) case element (*, Arzt_T) return 25 case element (*, Pfleger_T) return 15 case element (*, Techniker_T) return 20 case element (*, Sekretärin_T) return 10 default return 0 Überstunden in Abhängigkeit von der Berufsgruppe. Überstunden werden bei Ärzten mit 25, bei Pfleger nur mit 15 entlohnt. Die Variable ist aus der Ersetzungsgruppe von Angestellten. Beispiel • typeswitch ($a) case $x as element (*, Arzt_T) return <Merkmal> $x/Spezialgebiet</Merkmal> Gleichheit von Sequenzen • Es ist möglich zwei Sequenzen auf Gleichheit zu prüfen mittels fn:deep-equal(). • Damit Sequenzen gleich sind müssen sie dieselbe Anzahl von Einträgen haben und die Einträge müssen an derselben Position jeder Sequenz paarweise gleich sein. • Eine leere Sequenz ist gleich einer leeren Sequenz • Sind beide Einträge atomare Werte, ist die Gleichheit über eq definiert Sortierordnung • Ist ein Eintrag ein atomarer Wert und der andere ein Knoten sind sie nicht gleich • Sind beide ein Knoten ist die Gleichheit rekursiv definiert • Die Art der Knoten muss gleich sein • Wenn die Knoten Namen haben, müssen die Namen gleich sein • Wenn es sich um Attributknoten handelt, müssen Name und getypter Wert gleich sein • Bei Text,-Namensraum- und Kommentarknoten muss der textuelle Wert gleich sein • Bei Knoten für Verarbeitungsanweisungen müssen Name und textueller Wert gleich sein • Bei Elementknoten müssen Attributknoten gleich sein • Wenn beide Elementknoten einen einfachen Typ haben, muss der getypte Wert gleich sein • Wenn ein Elementknoten einen einfachen Typ hat und der andere nicht sind sie nicht gleich • Wenn beide Elementknoten einen komplexen gemischten Inhalt haben, sind sie gleich, wenn ihre Kindknoten paarweise gleich sind Zusammenfassung • XQuery definiert ein eigenes Datenmodell • Das zentrale Konstrukt ist die Sequenz: Eine Sequenz kann aus atomaren Werten und Knoten bestehen • Dann habe ich die atomaren Werte erläutert, i.Z. mit Konstruktoren und Literale • Dann kommt das zweite große Komplex, die Knoten, mit den Knotenarten und Funktionen, die auf Knoten arbeiten • Dann die Typabfrage mit instance of und typeswitch • Und als letztes das Konzept der Gleichheit von Sequenzen, wobei die Tatsache, dass Knoten als Einträge einer Sequenz dazu führt, dass die Gleichheit rekursiv definiert werden muss! Quellen • Bild: www.tutego.de/images/seminare/logos/xm l.png • W.Lehner,H.Schöning:XQuery:Grundlagen und fortgeschrittene Methoden:2004. ENDE • GESCHAFFT!!!!