An extended link connects any number of resources and can live apart from all of them, so a third party can relate documents it cannot edit. A locator child points to a remote resource, a resource child is local content, and an arc connects one xlink:label to another, with xlink:arcrole naming the relationship. BookNest records "also bought" and an editor's tip without touching the catalog:
<related xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="extended">
<item xlink:type="locator" xlink:href="booknest-catalog.xml#b3" xlink:label="salt"/>
<item xlink:type="locator" xlink:href="booknest-catalog.xml#b6" xlink:label="glass"/>
<review xlink:type="resource" xlink:label="tip">Grow your own saffron crocus.</review>
<go xlink:type="arc" xlink:from="salt" xlink:to="glass"
xlink:arcrole="urn:booknest:also-bought"/>
<go xlink:type="arc" xlink:from="tip" xlink:to="salt"
xlink:arcrole="urn:booknest:comments-on"/>
</related>No general XLink processor survives, so a short XQuery traverses the arcs, run with xquery -s:related.xml -q:traverse.xq:
declare namespace xl = "http://www.w3.org/1999/xlink";
declare function local:end($link as element(), $label as xs:string) as xs:string {
let $e := $link/*[@xl:label = $label]
return if ($e/@xl:type = "locator")
then let $ref := tokenize($e/@xl:href, "#")
return doc($ref[1])//book[@id = $ref[2]]/title/string()
else "note: " || $e
};
for $link in /*[@xl:type = "extended"], $arc in $link/*[@xl:type = "arc"]
return string-join((local:end($link, $arc/@xl:from),
substring-after($arc/@xl:arcrole, "booknest:"), local:end($link, $arc/@xl:to)), " -> ")Output
"Salt and Saffron -> also-bought -> Gardens in Glass" "note: Grow your own saffron crocus. -> comments-on -> Salt and Saffron"
XBRL works the same way: a filing holds facts, and separate linkbases of extended links attach labels, calculations and presentation order to them (XBRL in Regulatory Filings).