• +49-(0)721-402485-12
Your experts for XML, XQuery and XML Databases

Tracing of references

In principle, elements from various XML documents or within a XML document may be put into relation in two ways. The join (known from the relational model) works value-based, whereby a relationship of two elements is defined via a relation on the manifestations. Usually, the equality of values is required, but also other (mathematical) relations are applied. The second variant is to use relationships deposited in the schema via attributes of the ID or IDREF type. In XQuery, the resolution of links or references is supported by the two functions fn:id() and fn:idref().

SignatureDescription
fn:id(
$arg as xs:string*)
as element()*
realises a tracing of references and returns a sequence of elements which are referenced by one or several IDREF values passed on as parameters
fn:idref(
$arg as xs:string*)
as node()* *
realises the inverse resolution of references and returns a sequence of attribute nodes having an IDREF value which contains at least one ID value passed on as parameter

Table: Functions for the processing of ID and IDREF values

Both functions accept a sequence of character strings which are interpreted as elements of the xs:IDREFS or the xs:ID type or, if unrealisable, ignored. In the case of the fn:id() function, the result consists of the elements from the XML document of the respective context node. Whereby the element values must be an attribute of the ID type and at least correspond to one IDREF value passed on. The comparison is made on the level of the Unicode Codepoints without taking into account a sorting order.

If no element can be found as target of a link, the fn:id() function returns the empty sequence. A special feature for invalid, but well-formed XML documents is that, in case several ID values with the same value exist, the first target element with regard to the document order is selected. With the help of the fn:id() function, the example of the assignment of a managing nurse to each ward can be formulated as follows:

for $s in fn:doc("Hochwaldklinik.xml")//Ward,
let $p := fn:id($s/@Manager)
return
<Ward>
{$s/Name}
<Manager>
{$p//FirstName, $p//LastName}
</Manager>
</Ward>

By means of the result of the fn:id() function, the $p variable is applied on the link of the managing personnel for each ward.
The fn:idref() function has the inverse semantics to the fn:id() function, so that as parameter a list of ID values is accepted and the attribute nodes are returned which refer to these values within the current document. The same rules apply as for the fn:id() function with regard to the comparison and the behaviour of empty result sets.

Since an ID/IDREF relation is always of the relation type 1:N, several identical IDREF values may refer to the same target. As a special feature, a duplicate elimination occurs accordingly before the return of the ID values. The formulation of the query with usage of the fn:idref() function requires an additional filtering step on ward elements, because a nurse can be referenced from several places.

for $p in fn:doc("Hochwaldklinik.xml")//Nurse 
let $s := (for $x in fn:idref($p/@ID)
where $x instance of element(Ward, *)
return $x)
return
<Ward>
{$s/Name}
<Manager>
{$p//FirstName, $p//LastName}
</Manager>
</Ward>

At this point, it should be explicitly noted that the attribute nodes and not the elements are returned with the referenced attributes by the fn:idref() function. The elements can be obtained by navigating along the parent:: axis:

fn:idref()/..

The advantage in this behaviour is that the source of the reference, i.e. the referencing attribute, can be extracted for an element with several attributes referencing to information of the same type. For example:

<Ward Manager="nurse_02" Substitute="nurse_04">
...
</Ward>

In this XML fragment, a ward does not only show a reference to an entry in the nursing staff for the manager, but also for the substitute. In this case, the fn:idref() function returns the Manager or the Substitute attribute, which could no longer be distinguished when returning the Ward element.

Tracing of XLink links

However, both functions for tracing references always refer to the document of the current context node. Therefore, a tracing of external links in the form of a XLink requires a further intermediate step. Firstly, the target document must be referenced with the help of the fn:doc() function (with that the context must be set), so that then, in a second step, the target elements searched for can be searched with the help of the fn:id() function. In the example scenario, XLink links can be found for patients; thereby the respective attending doctor is assigned to each patient. The following example adds to each patient the complete name of his attending doctor:

for $p in fn:collection("Patient")//In-Patient 

(: reading out of the XLink link :)
let $href := $p/Doctor/@xlink:href

(: splitting up the XLink link into document/element portion :)
let $docValue := fn:substring-before($href, "#")
let $x := fn:substring-after($href, "#xpointer(id(""")
let $idValue := fn:substring-before($x, """)")

(: resolving the reference :)
let $a := fn:doc($docValue)/fn:id($idValue)

return
<PatientList>
<Patient>
<PatientName>{ $p/Name }</PatientName>
<DoctorName>{ $a//Name }</DoctorName>
</Patient>
</PatientList>

The resolving of external links is even more comprehensive. In a first step, the value is split up into the two components for the document and the actual ID value with the help of functions for the processing of character strings and subsequently, the target element is bound to the $a variable.

Since this form of tracing XLink values often occurs in the following, a xqb:follow-xlink() function is preconditioned (additionally provided with error handling). In that case, the example above is simplified to the following FLWOR expression:

for $p in fn:collection("Patient")//In-Patient 
return
<PatientList>
<Patient>
<PatientName>{ $p/Name }</PatientName>
<DoctorName>
{ xqb:follow-xlink($p/Doctor/@xlink:href)//Name }
</DoctorName>
</Patient>
</PatientList>

 

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

<< backnext >>