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

Verfolgung von Referenzen

Elemente aus unterschiedlichen XML-Dokumenten bzw. innerhalb eines XML-Dokumentes können im Prinzip auf zwei Wegen miteinander in Beziehung gesetzt werden. Der (aus dem Relationenmodell) bekannte Verbund arbeitet wertebasiert, wobei eine Beziehung von zwei Elementen über eine Relation auf den Ausprägungen definiert ist. Üblicherweise wird dabei die Wertegleichheit vorausgesetzt, wobei auch andere (mathematische) Relationen zum Einsatz kommen. Die zweite Variante besteht darin, im Schema hinterlegte Beziehungen über Attribute vom Typ ID bzw. IDREF zu nutzen. Die Auflösung von Verweisen bzw. Referenzen wird in XQuery durch die beiden Funktionen fn:id() und fn:idref() unterstützt.

SignaturBeschreibung
fn:id(
$arg as xs:string*)
as element()*
realisiert eine Verfolgung von Referenzen und
liefert eine Sequenz von Elementen zurück, die
durch einen oder mehrere als Parameter über-
gebene IDREF-Werte referenziert werden
fn:idref(
$arg as xs:string*)
as node()* *
realisiert die inverse Auflösung von Referenzen
und liefert eine Sequenz von Attributknoten
zurück, die einen IDREF-Wert besitzen, der
mindestens einen als Parameter übergebenen
ID-Wert enthält

Tab. Funktionen zur Verarbeitung von ID und IDREF-Werten

Beide Funktionen akzeptieren eine Sequenz von Zeichenketten, die jeweils als Elemente vom Typ xs:IDREFS bzw. xs:ID interpretiert bzw. falls nicht realisierbar, ignoriert werden. Im Fall der Funktion fn:id() besteht das Ergebnis aus den Elementen aus dem XML-Dokument des jeweiligen Kontextknotens, deren Wert eines Attributes vom Typ ID mindestens einem übergebenen IDREF-Wert entsprechen. Der Vergleich erfolgt dabei auf Ebene der Unicode-Codepoints ohne Berücksichtigung einer Sortierordnung.

Falls kein Element als Ziel eines Verweises aufgefunden wird, liefert die Funktion fn:id() die leere Sequenz zurück. Als Besonderheit gilt für nicht gültige, aber wohlgeformte XML-Dokumente, dass, falls mehrere ID-Werte mit dem gleichen Wert existieren, das erste Zielelement bzgl. der Dokumentordnung gewählt wird. Mit Hilfe der Funktion fn:id() lässt sich das Beispiel der Zuordnung eines leitenden Pflegers zu jeder Station wie folgt formulieren:

for $s in fn:doc("Hochwaldklinik.xml")//Station,
let $p := fn:id($s/@Leitung)
return
<Station>
{$s/Name}
<Leitung>
{$p//Vorname, $p//Nachname}
</Leitung>
</Station>

Die Variable $p wird durch das Ergebnis der Funktion fn:id() auf den Verweis des leitenden Personals für jede Station angewandt.
Die Funktion fn:idref() besitzt die zur Funktion fn:id() inverse Semantik, so dass als Parameter eine Liste von ID-Werten akzeptiert wird und die Attributknoten zurückgeliefert werden, die innerhalb des aktuellen Dokumentes auf diese Werte verweisen. Bei dem Vergleich und dem Verhalten bei leeren Ergebnismengen gelten die gleichen Regeln wie bei der Funktion fn:id().

Da eine ID/IDREF-Beziehung stets vom Beziehungstyp 1:N ist, können mehrere gleiche IDREF-Werte auf das gleiche Ziel verweisen. Als Besonderheit erfolgt entsprechend vor Rückgabe der ID-Werte eine Duplikateliminierung. Die Formulierung der Anfrage mit Verwendung der Funktion fn:idref() erfordert einen zusätzlichen Filterschritt auf Stationselemente, da ein Pfleger von mehreren Stellen aus referenziert werden kann.

for $p in fn:doc("Hochwaldklinik.xml")//Pfleger
let $s := (for $x in fn:idref($p/@ID)
where $x instance of element(Station, *)
return $x)
return
<Station>
{$s/Name}
<Leitung>
{$p//Vorname, $p//Nachname}
</Leitung>
</Station>

An dieser Stelle soll nochmals explizit darauf hingewiesen werden, dass die Attributknoten und nicht die Elemente mit den referenzierenden Attributen von der Funktion fn:idref() zurückgeliefert werden. Die Elemente erhält man durch Navigation entlang der parent::-Achse:

fn:idref()/..

Der Vorteil bei diesem Verhalten liegt darin, dass bei einem Element mit mehreren referenzierenden Attributen auf Informationen vom gleichen Typ der Ursprung der Referenz, d. h. das referenzierende Attribut, extrahiert werden kann. Zum Beispiel:

<Station Leitung="schwester_02" Vertretung="schwester_04">
...
</Station>

In diesem XML-Fragment weist eine Station nicht nur eine Referenz auf einen Eintrag im Pflegepersonal für die Leitung, sondern auch für die Vertretung auf. Eine Anwendung der Funktion fn:idref() liefert dann entweder das Attribut Leitung oder Vertretung, was bei einer Rückgabe des Elementes Station nicht mehr unterscheidbar wäre.

Verfolgung von XLink-Verweisen

Beide Funktionen zum Verfolgen von Referenzen beziehen sich jedoch stets auf das Dokument des aktuellen Kontextknotens. Eine Verfolgung externer Referenzen in Form eines XLink erfordert somit einen weiteren Zwischenschritt, indem zuerst das Zieldokument mit Hilfe der Funktion fn:doc() referenziert (und damit der Kontext gesetzt) werden muss, so dass dann in einem zweiten Schritt die gesuchten Zielelemente mit Hilfe der Funktion fn:id() gesucht werden können. Im Beispielszenario treten XLink-Verweise bei Patienten auf; jedem Patienten ist dabei der betreuende Arzt zugeordnet. Folgendes Beispiel fügt jedem Patienten den vollständigen Namen seines betreuenden Arztes hinzu.

for $p in fn:collection("Patient")//Patient_stationär

(: Auslesen des XLink-Verweises :)
let $href := $p/Arzt/@xlink:href

(: Zerlegen des XLink-Verweises in Dokument-/Elementanteil :)
let $docValue := fn:substring-before($href, "#")
let $x := fn:substring-after($href, "#xpointer(id(""")
let $idValue := fn:substring-before($x, """)")

(: Auflösen der Referenz :)
let $a := fn:doc($docValue)/fn:id($idValue)

return
<Patientenliste>
<Patient>
<Patientenname>{ $p/Name }</Patientenname>
<Arztname>{ $a//Name }</Arztname>
</Patient>
</Patientenliste>

Das Auflösen externer Referenzen gestaltet sich dabei umfangreicher, indem in einem ersten Schritt der Wert mit Hilfe von Funktionen zur Bearbeitung von Zeichenketten in die beiden Bestandteile für das Dokument und den eigentlichen ID-Wert zerlegt wird und daran anschließend das Zielelement an die Variable $a gebunden wird.

Da diese Form der Verfolgung von XLink-Werten im folgenden Verlauf häufig auftritt, wird (zusätzlich versehen mit Fehlerbehandlungen) eine Funktion xqb:follow-xlink() vorausgesetzt. Das obige Beispiel vereinfacht sich dann zu folgendem FLWOR-Ausdruck:

for $p in fn:collection("Patient")//Patient_stationär
return
<Patientenliste>
<Patient>
<Patientenname>{ $p/Name }</Patientenname>
<Arztname>
{ xqb:follow-xlink($p/Arzt/@xlink:href)//Name }
</Arztname>
</Patient>
</Patientenliste>

 

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

<< zurückvor >>