• +49-(0)721-402485-12
Ihre Experten für XML, XQuery und XML-Datenbanken

Arithmetische Ausdrücke

Der Abschnitt über arithmetische Ausdrücke ist dahingehend zentral, dass in nahezu jeder Anfrage eine Skalaroperation zur Ermittlung abgeleiteter Werte oder auch zur Einschränkung von Ergebnismengen enthalten ist. Die Anfragesprache XQuery stellt hierfür jedoch nur eine kleine Menge an arithmetischer Funktionalität als integralen Bestandteil des Sprachumfangs zur Verfügung. Die Menge der arithmetischen Operatoren beschränkt sich dabei auf die Skalaroperatoren für Addition, Subtraktion, Multiplikation, Division und Restwertbildung. Weiter gehende Operatoren werden über Funktionen realisiert, die im sich anschließenden Kapitel aufgearbeitet und strukturiert dargestellt werden. Das nachstehend gezeigte Fragment der XQuery-Grammatik illustriert die Menge der zur Verfügung stehenden arithmetischen Ausdrücke:

AdditiveExpr::=MultiplicativeExpr ( (+ | -) MultiplicativeExpr )*
MultiplicativeExpr::=UnaryExpr ( (* | div | idiv | mod) UnaryExpr )*
UnaryExpr::=(- | +)* UnionExpr

Da ein Summationsausdruck aus zwei Multiplikationsausdrücken geformt wird, wird die "Punkt-vor-Strich"-Regel eingehalten. Vor einem Subtraktionsoperator muss ein Leerzeichen stehen, da das Operatorenzeichen sonst als Teil eines Bezeichners interpretiert werden würde. Für die Division werden in XQuery zwei unterschiedliche Operatoren mit jeweils spezifischer Semantik bereitgestellt.

Der div-Operator realisiert dabei die Division mit Nachkommastellen und liefert den Datentyp der beiden numerischen Operanden nach einer entsprechenden Datentypanpassung. Falls beide Operanden den Datentyp xs:integer aufweisen, liefert die Operation einen Wert vom Datentyp xs:decimal. Der idiv-Operator hingegen liefert das Ergebnis der ganzzahligen Division als Wert des Datentyps xs:integer und erwartet, dass beide Operanden ebenfalls vom Typ xs:integer sind.

Das folgende Beispiel berechnet die mittlere Anzahl verbrauchter Artikel für jede durchgeführte Operation pro Patient sowohl exakt als auch mit ganzzahliger Division und Restwertbildung.

<Behandlungsstatistik>
{
for $p in fn:collection("Patienten")/element(*,Patient_T)
let $t := fn:sum(for $x in $p//Operation
return $x/Ende - $x/Beginn)
let $a := fn:count($p//Operation/*/verbrauchter_Artikel)
let $b := fn:count($p//Operation)
return (
<Patient>{ $p/Name/* }</Patient>,
<Anzahl_div>{ $a div $b }</Anzahl_div>,
<Anzahl>
<Anzahl_idiv>{ $a idiv $b }</Anzahl_idiv>
<Anzahl_mod>{ $a mod $b }</Anzahl_mod>
</Anzahl>,
<Operationsdauer>{ $t }</Operationsdauer>)
}
</Behandlungsstatistik>

Dabei wird für jeden Patienten ein Eintrag für die Behandlungsstatistik generiert. Die Variable $a enthält dabei die Zahl der Artikel, die in allen Operationen des jeweiligen Patienten verwendet worden sind. Die Variable $b zählt alle Operationen des konkreten Patienten.

Zusätzlich wird in der obigen Anfrage die Gesamtdauer der Operationen des Patienten ermittelt, indem in einem ersten Schritt die Dauer einer Operation mit Hilfe des Subtraktionsoperators zwischen dem Ende- und Startzeitpunkt eines Eingriffs ermittelt wird. Diese Zeiten werden dann mit der Aggregationsfunktion fn:sum() zu einem Gesamtergebnis zusammenaddiert. Das Ergebnis besitzt dabei den Datentyp xs:dayTimeDuration.

Im Allgemeinen erfolgt die Auswertung der arithmetischen Ausdrücke, indem zunächst die Operandenausdrücke ausgewertet werden und anschließend überprüft wird, ob einer der Operanden eine Sequenz mit mehr als einem Element ist. In diesem Fall wird ein Laufzeitfehler generiert. Ist einer der Operanden eine leere Sequenz, so ist das Ergebnis auch eine leere Sequenz.

Im zweiten Schritt wird auf Typverträglichkeit überprüft bzw. der Typ der Operanden implizit an xs:double (bzw. xs:integer für idiv-Operator) angepasst, falls ein Operand den Typ xs:untypedAtomic aufweist. Im letzten Schritt wird der Operator ausgewertet. Die Präzedenz folgt den allgemein gültigen Regeln: Unäre Operatoren binden stärker als binäre Operatoren und multiplikative Ausdrücke werden vorrangig vor additiven Ausdrücken ausgewertet. Die Vorrangregelung kann durch Klammersetzung entsprechend explizit angepasst werden.

Folgende Besonderheit ist an dieser Stelle zu erwähnen. Der Ausdruck A-B ist kein arithmetischer Ausdruck, sondern ein regulärer Bezeichner. Erst ein zusätzliches Leerzeichen (A -B) sorgt dafür, dass das Zeichen - intern durch den Operator ersetzt und der Ausdruck als op:numeric-subtract(A, B) interpretiert wird.

Anzumerken ist noch die Behandlung von Über- bzw. Unterläufen. XQuery-Implementierungen müssen sich dabei konform zum entsprechenden IEEE-Standard 754-1985 [IEEE754] verhalten, wobei eine Vielzahl von Freiheitsgraden möglich ist. Bei einem Überlauf von Operationen mit Parametern vom Typ xs:float bzw. xs:double kann entweder ein Fehler verursacht werden oder INF beziehungsweise -INF oder die größte positive bzw. negative Zahl zurückgeliefert werden. Bei einem Unterlauf wird entweder 0.0E0 oder +/-2**Ex mit x als dem kleinstmöglichen Exponenten für Werte aus dem Wertebereich von xs:float bzw. xs:double zurückgegeben.

Für Operatoren mit Parametern vom Datentyp xs:decimal ist bei einem Überlauf ein Fehler, bei einem Unterlauf die Rückgabe des Wertes 0.0 vorgeschrieben. Bei xs:integer-Operatoren kann die Implementierung in beiden Fällen entweder immer einen Fehler oder – falls ein implementierungsabhängiger Mechanismus zum Einstellen des Verhaltens gegeben ist – gemäß der Vorgabe von ISO 10967 [ISO10967] den Wert modulo der größten darzustellenden Zahl als Ergebnis liefern.

Der Divisionsoperator liefert des Weiteren einen Sonderfall bei einer Division durch 0, wobei bei xs:decimal- bzw. xs:integer-Operanden ein entsprechender Fehler vom Laufzeitsystem verursacht wird. Bei einer Division mit xs:float- bzw. xs:double-Operanden wird gemäß der Spezifikation IEEE 754-1985 [IEEE754] der größte bzw. kleinste darstellbare Wert INF/-INF als Ergebnis zurückgeliefert, falls der Divisor den Wert 0 aufweist.

 

Quelle: "XQuery – Grundlagen und fortgeschrittene Methoden", dpunkt-Verlag, Heidelberg (2004)

<< zurückvor >>