XLink and XPointer
The linking model for XML revolves around the complementary technologies of XLink and XPointer. XPointers provide the mechanism for identifying resource fragments, and XLink provides the mechanism for collecting these together into links.
Let's begin by looking at XPointer and its capabilities. XPointer provides a general way to select fragments of an XML document essentially by writing a set of expressions. An expression is evaluated with respect to the current context (which includes aspects such as bindings between variables and values, and a context element within the given XML document) and usually results in a set of locations (not surprisingly, referred to as a location set). An expression can be used to select children, siblings, nodes with given attributes, arbitrary text strings, and so on. For example, the XPointer
selects all p children elements of the first body element in the document.
As another example, the XPointer expression
selects all elements (that is, all descendants of the document root) that have an attribute called name with a value of book. In effect, the selection mechanisms can be concatenated to progressively identify a specific subset of nodes.
It is also worth briefly pointing out that XPointer is actually an application of the XPath standard. XPath was developed specifically to be a foundation for other standards such as XPointer. Another example application of XPath is as part of XSL Transformations (XSLT). In XSLT, XPath expressions allow the selection of specific nodes that can then be transformed into an alternative form (often for presentation).
Because XPath is intended to be relatively generic (to suit multiple applications), certain sections of documents cannot be specified using XPath expressions. For example, both of the XPointer fragments shown above are constructed from valid XPath expressions. However, XPath cannot select an arbitrary string that crosses several nodes. It is in areas such as this that XPointer has extended XPath. For example, the following expression defines the set of all occurrences of the string links and anchors within all para elements in the http://a.b/c/d.xml resource. This could not be achieved using just XPath expressions.
http://a.b/c/d.xml#xpointer(string-range(//para,'links and anchors'))
As a further example, the following URI defines a range that extends from the beginning of the element with an ID of sect-2.3 to the end of the element with an ID of sect-3.4:
Note that, in this case, this can include only parts of nodes (for example, part of a Chapter-2 element and part of a Chapter-3 element). Again, this would not be possible to identify with XPath.
Links and Arcs
It is also worth noting that, as shown in several of the above examples, XPointers are used with URIs to identify a particular resource and then a fragment of that resource (which must be an XML document). In the context of linking, this means that XPointers can be used to specify anchors, or arbitrary sections of resources that will participate in a link. In XML, however, they are referred to as locator elements rather than anchors. A locator element is more than just an XPointer, though. We can also specify the role that the resource will play and provide a title for the resource. For example, consider the following XLink fragment:
<siblings xlink:type="extended"> <child xlink:type="locator" xlink:href="people.xml#xpointer(id('anna'))" xlink:title="Anna"/> <child xlink:type="locator" xlink:href="people.xml#xpointer(id('bill'))" xlink:title="Bill"/> <child xlink:type="locator" xlink:href="people.xml#xpointer(id('carl'))" xlink:title="Carl"/> </siblings>
In this example, we define three locator elements, each of which uses an XPointer as part of the locator required to specify the remote resource that is participating in the link. We also give each locator element a title. However, we do not specify any traversal between these elements. There is no link "source," nor is there a link "destination." This is because XLink has separated the concept of associating resources from the concept of traversal among these resources.
When we do want to specify traversal information, this is done separately from the specification of the association through the use of an arc. For example:
<person xlink:type="extended"> <name xlink:type="locator" xlink:href="staff.xml#xpointer(string-range(/,'David Lowe'))" xlink:label="src"/> <details xlink:type="locator" xlink:href="David.xml" xlink:label="dest"/> <go xlink:type="arc" xlink:from="src" xlink:to="dest"/> </person>
In this case, we specify an association between two resources (defined by locators): The first resource is all occurrences of a given string (David Lowe) within one XML document, and the second is another XML document (about David Lowe). We then specify the traversal semantics using an arc from the first resource to the second resource. This effectively means that we now have separate mechanisms for specifying an association between resources (a link) and for specifying how we might traverse between these resources (an arc within that link).
Indeed, we can have a single link involving a number of resources, with multiple different traversal rules. Consider the following example, in which we have two arc specifications. Also note that the second arc specification actually creates three arcs because there are multiple destinations specified by the to label. We end up with one arc from a.xml (to b.xml) and three arcs from b.xml (to c.xml, d.xml, and e.xml).
<extendedlink xlink:type="extended"> <loc xlink:type="locator" xlink:href="a.xml" xlink:label="x"/> <loc xlink:type="locator" xlink:href="b.xml" xlink:label="y"/> <loc xlink:type="locator" xlink:href="c.xml" xlink:label="z"/> <loc xlink:type="locator" xlink:href="d.xml" xlink:label="z"/> <loc xlink:type="locator" xlink:href="e.xml" xlink:label="z"/> <go xlink:type="arc" xlink:from="x" xlink:to="y"/> <go xlink:type="arc" xlink:from="y" xlink:to="z"/> </extendedlink>
It is also worth noting that XLink can be used to specify the existence of a link without specifying rules for how that link will be used. XLink does support some attributes for defining behaviors, such as how and when an arc should be traversed, but these are optional; when present, their interpretation is left to the applications using the XML documents. For example, where multiple arcs emanate from one resource and that resource is "activated," the standard does not say how the application should respond. Possible alternatives include traversing all arcs, giving a user the choice of which arc to traverse, or using some internal logic to make the choice. This is illustrated by the above example: If the arc from b.xml is activated, it is unclear what the result should be.
One mechanism supported by XLink is the inclusion of arc roles. For example, consider the following:
<extendedlink xlink:type="extended"> <loc xlink:type="locator" xlink:href="a.xml" xlink:label="x"/> <loc xlink:type="locator" xlink:href="b.xml" xlink:label="y"/> <go xlink:type="arc" xlink:from="x" xlink:to="y" xlink:arcrole="http://q.r/s.dat"/> </extendedlink>
In this case, the arc has an arcrole attribute that provides a unique role identifier. This identifier might allow the application to obtain information that assists in determining the appropriate behavior when traversing the arc. However, this is beyond the XLink specification and is application-dependent.
Another interesting issue is that of adding links from read-only material. This is a rather unusual concept for people who are familiar with only the Web, where all links must be embedded into the source content. However, this is very restrictive. For example, we might want to be able to annotate material that doesn't belong to us with our own links, or the material might be stored on read-only media, or we might want to use different sets of links at different times (depending upon what we are trying to do). In each case, we don't want toor cannotadd links directly into the underlying content. Instead, we want to be able to specify links separately and somehow have them used. Using XLink, this is relatively straightforward. Consider the following fairly simple example:
<?xml version="1.0"?> <!DOCTYPE Dictionary SYSTEM "Dictionary.dtd"> <Dictionary> <Entry word="Anchor"> <Pronunciation>...</Pronunciation> <Definition>An identified region of a node that can be explicitly addressed and identified within the presentation of a node. </Definition> </Entry> <Entry word="Link"> <Pronunciation>...</Pronunciation> <Definition>A connection among multiple anchors (and nodes, where there is an implied anchor that encompasses the entire node) that represents an association between the concepts captured by the anchors. </Definition> </Entry> <!-- Further entries go here --> </Dictionary>
In this example, the document contains a series of words and definitions, but no links. We can then create a separate file (often called a linkbase) that contains links from words to the definitions of these words.
<?xml version="1.0"?> <!DOCTYPE XRefs SYSTEM "XRefs.dtd"> <XRefs> <Xref xlink:type="extended"> <word xlink:type="locator" xlink:href="#xpointer(string-range(//Definition,'anchor'))" xlink:label="src"/> <defn xlink:type="locator" xlink:href="Dict.xml#xpointer(//Entry[@word='Anchor'])" xlink:label="dest"/> <go xlink:type="arc" xlink:from="src" xlink:to="dest"/> </Xref> <!-- Further cross references go here --> </XRefs>
This linkbase file contains a series of XLinks, which link any occurrence of specific words in the definitions to the definition of those words. For example, the word anchor appearing in the definition of the word link would be the starting point for a link to the definition of anchor. In this case, the links are termed third-party links. This is because they are not embedded into any of the anchors that are participating in the link.
The problem then arises as to how we ensure that these link definitions are actually utilized. The simplest way is, where possible, to modify the source information so that it includes a reference to the linkbase. This is supported by XLink using a special form of extended link (it contains an arc from the content to the linkbase, with an arcrole attribute with a special value to indicate that the link destination is a linkbase). When the XML document is viewed or processed, the link to the linkbase is traversed and the linkbase is loaded. Even more complex, linkbases can include links to other linkbases, creating hierarchies of linkbases!
This solution is fine when we have access to the source information so that we can add a link to our linkbase, but one of the benefits of XML linking is that we can define third-party links for content that we do not have access to edit. So what do we do in this situation? One solution is to simply allow the user to specify directly within the browser (or whatever other tool we are using to view or process the documents) the linkbases that we want to use. This is analogous to the functionality supported in some Web browsers of specifying a particular style sheet to use for presentation of Web pages.
Another aspect supported by XLink but not supported by HTML linking is multiended links. (These have been shown in a number of the above examples but have not really been explained yet.) This type of link has a number of important applicationsessentially, wherever we have more than two resources participating in a relationship. However, there are several ways to create links of this type. First consider the following example (adapted from the XLink standard):
<family xlink:type="extended"> <loc xlink:type="locator" xlink:label="parent" xlink:href="Ann.xml"/> <loc xlink:type="locator" xlink:label="parent" xlink:href="Bob.xml"/> <loc xlink:type="locator" xlink:label="child" xlink:href="Gina.xml"/> <loc xlink:type="locator" xlink:label="child" xlink:href="Hank.xml"/> <loc xlink:type="locator" xlink:label="child" xlink:href="Irma.xml"/> <go xlink:type="arc" xlink:from="parent" xlink:to="child"/> </family>
In this example, we have five participating resources. We also have a single arc specification that results in six arcs (AnnGina, AnnHank, AnnIrma, BobGina, BobHank, BobIrma). In effect, we have three arcs from Ann.xml. If we initiate traversal of the arcs that originate from this resource, XLink does not specify what should happen, though a typical behavior might be to provide the user with a list of the possible destinations and allow that user to select the appropriate arc to traverse. It is also worth noting that XLink does not specify how to trigger a traversal. This is largely left to XLink applications (except for the standard behavior attributes).
XLink also supports a second form of multiended link, though it is a little more subtle than in the above example. Consider the following:
<family xlink:type="extended"> <loc xlink:type="locator" xlink:label="parents" xlink:href="Family.xml#xpointer(//Person[@type='parent'])"/> <loc xlink:type="locator" xlink:label="children" xlink:href="Family.xml#xpointer(//Person[@type='child'])"/> <go xlink:type="arc" xlink:from="parents" xlink:to="children"/> </family>
In this example, we have a single arc specification that results in just a single arc. So how can this be a multiended link? The key is in the XPointer. Essentially, the XPointer selects a location set, which, in the case of the parents locator, can potentially be a set of multiple noncontiguous elements. The same applies to the children locator. In effect, we have a single arc from one subresource to another subresource, but both subresources can potentially be location sets with more than one member.
Again, XLink does not specify how this situation, once specified in XLink, should be interpreted in terms of navigational behavior. In particular, the standard states:
Some possibilities for application behavior with noncontiguous ending resources might include highlighting of each location, producing a dialog box that allows the reader to choose among the locations as if there were separate arcs leading to each one, concatenating the content of all the locations for presentation, and so on. Application behavior with noncontiguous starting resources might include concatenation and rendering as a single unit, or creating one arc emanating from each contiguous portion.
Before we finish this section, it is also worth pointing out that XLink supports annotating arcs with additional semanticsspecifically, titles and roles. We can have two arcs between the same two resources, but with different purposes as indicated by their roles.
Another concept worth looking at is generic linking. A generic link is effectively a link that has a participating resource that is specified not by defining the actual resource, but by specifying a set of conditions that must be met for a resource to be included. This can be readily achieved using the functionality of XPointer. In particular, XPointer allows the selection of resource fragments based on criteria such as the following:
Elements of a given type
Elements that have a specific attribute with a given value
Text that matches a given string
Complex combinations of the above
In each case, the resulting location set can contain multiple locations. The result, when the XPointers are used in XLink, is a specification of a generic fragment identifier. This can be the source or the destination of possible arcs. If used as the source, we have the conventional generic link described previously. If used as the destination of an arc, we potentially have a link that traverses to an aggregation of all references to a particular concept or element. It is worth pointing out that this allows the specification of generic subresources (generic within a particular resource) but not really generic resources (because the URI cannot contain a generic component).
This type of XLink linking could be expected to be most common for producing universal cross-referencing, such as links from words to their definitions in dictionaries or glossaries.
Finally, one last aspect is not supported by HTML linking but is supported by XLink: typed links. Essentially, a typed link belongs to a particular set of links with common characteristics. The fact that it belongs to that set is typically indicated by the link having a particular attribute with a given value.
The ability to type links can make it much easier to navigate through a web of interlinked resources. For example, we can "switch" certain links on or off, or request certain types of links to be highlighted. For example, when initially learning a particular concept, we might want all glossary links to be visible so that we can readily obtain definitions of unfamiliar terms. As we begin to understand the topic, we might want to switch off the glossary links to reduce clutter. Apart from the visibility of links (or, rather, resources participating in the link), we might want to change the traversal behavior of certain link types: changing whether or not confirmation is required, where the destination is displayed, and so on.
It is also worth noting that because XLink separates the concepts of association (links) from traversal (arcs) we can also type these two elements independently. In other words, we can have various link types, but we can also support various arc types. So, a given link might contain multiple arcs (possibly even between the same resources) with different types.
So how do we actually do this typing in XLink? Although it is not explicitly designed for link typing, the standard provides several semantic attributes that effectively provide this support. In particular, both the title attribute and the role and arcrole attributes can be used to support link typing. The title attribute is typically used to describe the meaning of a link or resource in a human-readable form. The intended use of the title attribute is not constrained by the standard, but it is likely to used for purposes such as making titles available to visually impaired users, generating tables of links, or providing help text in the form of ToolTips before an arc is traversed. Although we could type links by defining specific titles to use for specific link types, this would be a somewhat cumbersome way of supporting typing and would likely interfere with other uses of the title attribute.
The role and arcrole attributes are more appropriate for link typing. The value of these attributes (according to the standard) must be a URI reference that identifies some resource that describes the intended property. Therefore, we could define a URI that is to be used by all links or arcs that belong to a particular type. Indeed, we could support links or arcs that belong to multiple types by having the role and arcrole URIs point to a resource that contains a list of the types for that link or arc. Consider the following example:
Family.xml: ... <loc xlink:type="locator" xlink:label="p1" xlink:href="Ann.xml"/> <loc xlink:type="locator" xlink:label="p2" xlink:href="Bob.xml"/> <loc xlink:type="locator" xlink:label="c1" xlink:href="Gina.xml"/> <loc xlink:type="locator" xlink:label="c2" xlink:href="Hank.xml"/> <loc xlink:type="locator" xlink:label="c3" xlink:href="Irma.xml"/> <go xlink:type="arc" xlink:from="p1" xlink:to="c1" arc-type: guardian
In this case, we have constructed a (somewhat arbitrary and trivial) format for the .arc files simply to illustrate the point. For astute readers, however, the above (simplistic) example might point toward a potential problem. The effective use of link typing requires the use of a common vocabulary for describing the link types. The XLink standard does not make any suggestions in this direction (indeed, this particular use of role and arcrole attributes is not discussed). We could potentially adapt a standard such as the Dublin Core, which provides a standard set of metadata, to specifying attributes of the link or arc. We would constrain the attributes that we could use, but not their values. More generically, we could utilize RDF, but we run into similar problems. RDF is more general than the Dublin Coredefining not a fixed set of attributes, but rather a mechanism for defining a metadata schemabut we would still need to develop a suitable schema. At present, these are issues that still must be resolved.