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

Rekursive benutzerdefinierte Funktionen

Das Prinzip der benutzerdefinierten Funktionen kann in vielfältiger Hinsicht die Fomulierung von komplexen Sachverhalten einfacher und übersichtlicher gestalten. Dies wird insbesondere dadurch erreicht, dass sowohl direkte als auch indirekte Rekursion erlaubt ist: Innerhalb einer Funktion können somit ein oder mehrere Aufrufe der aktuellen Funktion (mit variierenden Parameterbelegungen) stehen.

Als Beispiel dient an dieser Stelle die Nachbildung der Kernfunktion fn:max() als benutzerdefinierte Funktion zur Ermittlung des wertemäßig größten Elementes innerhalb einer Sequenz.

declare function local:mymax(
$values as xdt:anyAtomicType*)
as xdt:anyAtomicType
{
if (every $v in $values satisfies $values[1] ge $v)
then $values[1]
else local:mymax(fn:subsequence($values, 2))
};

Der konditionale Ausdruck überprüft dabei in jedem Rekursionsschritt, ob das Element an erster Position innerhalb der Sequenz größer als alle nachfolgenden Werte ist. Falls dies zutrifft, so ist der maximale Wert gefunden und wird als Rückgabewert an den Aufrufer zurückgegeben. Andernfalls wird rekursiv in der verbleibenden Sequenz (ab Position 2) das Maximum ermittelt.

Rekursion ist insbesondere dann von Interesse, wenn in einem hierarchisch angeordneten XML-Dokument Analysevorgänge, z. B. Suchvorgänge, zu realisieren sind. Folgende benutzerdefinierte Funktion bestimmt die maximale Pfadlänge, ausgehend von einem Knoten, der als Parameter übergeben wird.

declare function local:maxpath(
$e as node())
as xs:integer
{
if (fn:empty($e/*))
then 0
else 1 + fn:max(for $c in $e/*
return local:maxpath($c) )
};

Die Pfadlänge ist dabei wieder rekursiv definiert, indem ein Knoten ohne weitere Kinder keinen Beitrag zu einer Pfadlänge liefert. Andernfalls wird zunächst im Rahmen eines FLWOR-Ausdrucks rekursiv für jedes Kindelement des aktuellen Kontextknotens die Pfadlänge bestimmt. Aus der Sequenz der Ergebniswerte des FLWOR-Ausdrucks wird dann mit der fn:max()-Funktion der größte Wert ausgewählt und nach einer Inkrementierung zur Berücksichtigung der aktuellen Generation das Ergebnis an den aufrufenden Kontext übergeben. Die folgende Abbildung illustriert die Berechnung der Dokumententiefe und der Auswahl der lokal größten Pfadlänge in jeder Rekursionsstufe.

Illustration zur rekursiven Ermittlung der Pfadlängen

Abb.: Illustration zur rekursiven Ermittulung der Pfadlängen

Als letztes Beispiel einer rekursiven benutzerdefinierten Funktion wird das Prinzip der Erreichbarkeit in XML-Dokumenten aufgearbeitet . Ausgehend von einem Knoten sollen alle direkt darunter liegenden oder per Referenz erreichbaren Knoten als Rückgabewert zurückgeliefert werden:

declare function local:erreichbareElemente(
$e as element()*)
as element()*
{let $x :=
(for $el in $e
return
local:erreichbareElemente(local:verbundeneElemente($el)))
return $e union $x
};
declare function local:verbundeneElemente(
$e as element())
as element()*
{let $x := (for $el in $e/@*
where fn:data($el) instance of xs:id
return fn:id($el))
return $e/* union $x
};

Die Funktion local:erreichbareElemente() liefert als Rückgabewert das aktuelle Ausgangselement und alle Elemente, die mit dem aktuellen Ausgangselement (direkt oder indirekt) verbunden sind.

Zwei Elemente können dadurch verbunden sein, dass sie entweder in einem Vater-Kind-Verhältnis stehen oder per Referenz aufeinander verweisen. Analog liefert die Funktion local:verbundeneElemente() alle direkten Kinder und alle Elemente, die sich durch Auflösung der Referenz hinsichtlich aller Attribute des aktuellen Elementes erreichen lassen.

 

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

<< zurückvor >>