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

Konditionale Ausdrücke

Konditionale Ausdrücke eröffnen die Möglichkeit einer Fallunterscheidung innerhalb einer XQuery-Anfrage. Da ein konditionaler Ausdruck eine Spezialform eines "normalen" XQuery-Ausdrucks ist, kann eine dadurch spezifizierte Fallunterscheidung überall dort auftreten, wo ein Ausdruck erlaubt ist. Wie das entsprechende Grammatikfragment zeigt, besteht ein konditionaler Ausdruck aus einem Testausdruck, dessen effektiver boolescher Wert darüber entscheidet, ob das Ergebnis der then- bzw. der else-Klausel als Ergebnis zurückgeliefert wird.

IfExpr ::= if ( Expr ) then ExprSingle else ExprSingle

Der Testausdruck spielt aus Sicht der Anwendung zwei unterschiedliche Rollen. Zum einen werden Vergleichsausdrücke formuliert, um werteabhängig die Auswertung des then- bzw. else-Teils zu steuern. Der folgende konditionale Ausdruck berechnet beispielsweise die 10-prozentige Zuzahlung zu Medikamenten in der Apotheke in Abhängigkeit vom Preis mit einer unteren Schranke von € 5 bzw. einer oberen Schranke von € 10:

Zum anderen werden konditionale Ausdrücke eingesetzt, um das Fehlen von Knoten bzw. Attributen bei einer Auswertung zu kompensieren. Dazu gilt, dass, falls der Testausdruck aus einer Sequenz besteht, implizit auf Existenz eines Elementes geprüft wird, wobei der effektive boolesche Wert einer leeren Sequenz false ist. Fehlt beispielsweise in dem laufenden Anwendungsszenario die Preisangabe bei einem Medikament, so wird grundsätzlich zu Gunsten der Krankenkasse die höchste Zuzahlung des Patienten fällig:

if ( $m/Preis ) then ... (: obige Zuzahlungsberechnung :)
else 10.0

Der implizite Test auf die Existenz eines Elementes bzw. eines Attributes kann auch explizit durch Rückgriff auf die Funktion fn:exists() beschrieben werden:

if ( fn:exists($m/Preis) ) then ... (: obige Zuzahlungsberechnung :)
else 10.0

Im Unterschied zu konditionalen Ausdrücken in anderen Datenbankanfrage- bzw. Programmiersprachen kann der else-Teil nicht wegfallen, sondern muss mit angegeben werden. Falls es aus Sicht der Anwendung jedoch keine Alternative geben soll, kann dies beispielsweise durch die Rückgabe eines NaN-Wertes simuliert werden. Folgender konditionaler Ausdruck rechnet den Medikamentenpreis – sofern er denn existiert – in US-Dollar um:

if ( $m/Preis ) then $m/Preis * 1.21
else xs:double("NaN")

Bei Zeichenketten ist bei einer entsprechenden Reaktion an Stelle von NaN eine leere Zeichenkette zurückzugeben, um die erzwungene Existenz einer else-Klausel zu kompensieren:

if ($p//Adresse/Telefon) then fn:concat("+49", $p//Adresse/Telefon)
else ""

Anwendung konditionaler Ausdrücke

In der Praxis treten konditionale Ausdrücke meist ausschließlich in where- bzw. return-Klauseln von FLWOR-Ausdrücken auf. Folgendes Beispiel ermittelt alle Patienten, bei denen innerhalb eines Vorgangs Medikamente verabreicht wurden, die Kosten in Höhe von mehr als €1000 verursacht haben. Die Kosten ergeben sich dabei aus dem Preis des Medikamentes und – falls vorhanden – der Anzahl der verabreichten Exemplare.

let $p := fn:collection("Patienten")
//Patient_stationär[@ID="pat_res_010001"]
for $o in $p//Operation//verbrauchter_Artikel
for $a in fn:doc("Verbrauchsartikel.xml")
//Artikel[@ID = $o/@Artikel_id]
let $k := if ($o/@Menge) then $a/Einzelpreis * $o/@Menge
else $a/Einzelpreis
where $k > 1000
return
<Medikamentenverbrauch>
{ $p/Name, $a/Bezeichnung, $k }
</Medikamentenverbrauch>

Der konditionale Ausdruck wird in diesem Fall für jeden Vorgang innerhalb der Operation und jeden dabei verbrauchten Artikel zur Berechnung der Gesamtkosten ausgewertet. In vielen Fällen wird ein konditionaler Ausdruck nur einmalig in der return-Klausel zur Generierung des Ergebnisdokumentes verwendet und direkt eingebettet, so dass sich bei Wegfall der where-Bedingung das obige Beispiel wie folgt beschreiben lässt:

let $p := fn:collection("Patienten")
//Patient_stationär[@ID="pat_res_010001"]
for $o in $p//Operation//verbrauchter_Artikel
for $a in fn:doc("Verbrauchsartikel.xml")
//Artikel[@ID = $o/@Artikel_id]
return
<Medikamentenverbrauch>
{ $p/Name, $a/Bezeichnung,
if ($o/@Menge) then $a/Einzelpreis * $o/@Menge
else $a/Einzelpreis
}
</Medikamentenverbrauch>

Eine Schachtelung wird wiederum deutlich, wenn die Gesamtkosten pro Operation berechnet werden sollen. Dabei müssen die Kosten pro verbrauchten Artikel innerhalb einer Operation aufsummiert werden:

let $p := fn:collection("Patienten")
//Patient_stationär[@ID="pat_res_010001"]
for $o in $p//Operation
return
<Behandlungsinformation>
{ $p/Name }
<Datum>{ xs:date($o/Beginn) }</Datum>
<Kosten>
{ fn:sum(for $x in $o//verbrauchter_Artikel
for $a in fn:doc("Verbrauchsartikel.xml")//Artikel
where $a/@ID = $x/@Artikel_id
return
if ($x/@Menge) then $a/Einzelpreis * $x/@Menge
else $a/Einzelpreis )
}
</Kosten>
</Behandlungsinformation>

Behandlung von Laufzeitfehlern

Die Auswertung konditionaler Ausdrücke weist – in Analogie zur Auswertung logischer Ausdrücke – eine Besonderheit bei der Behandlung von Laufzeitfehlern auf. Wird der Testausdruck zu true evaluiert, so wird der Alternativzweig nicht ausgewertet und eventuell auftretende Laufzeitfehler nicht beachtet. Gleiches gilt für die Auswertung der then-Klausel, falls der Testausdruck zu false ausgewertet wird.

 

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

<< zurückvor >>