Building XLink Applications with XSLT

Bob DuCharme
LexisNexis Data Architecture, Editorial Systems and Content Engineering Brooklyn New York USA bob@snee.com http://www.snee.com/bob

XSLT , which became a W3C Recommendation in November of 1999 , is an XML-based language for transforming XML documents into other kinds of XML or non-XML documents. XLink, which became a W3C Recommendation in June of 2001 , "allows elements to be inserted into XML documents in order to create and describe links between resources," according to the XLink Recommendation's abstract. This Recommendation describes "links" as a broader, more powerful concept than the HTML a href links that have provided most web page designers' experience with links; it defines an XLink link as "an explicit relationship between resources or portions of resources."

By providing for the description of the roles and relationships of the two or more resources taking part in an XLink link, instead of merely underlining some text to show where to click when jumping to another web page, XLink markup lets an XML document describe resource relationships without necessarily assigning implementation details to the link. Just as SGML and then XML let documents describe document elements in terms of their purpose (for example, jobTitle or cookingTime) instead of assigning fonts and other presentation details to the source data, XLink provides a way to include semantic link information without implementation details so that an XLink application can add implementation details appropriate to a given output media. The same link in the same document can be converted to the hottest new user interface widget in Netscape Navigator 8, it can be converted to a sidebar in a hard copy print version of the same document, and it can be converted to an a href link in an HTML document targeted at all possible browsers.

What exactly is an XLink application? The XLink Recommendation describes it as "any software module that interprets well-formed XML documents containing XLink elements and attributes, or XML information sets containing information items and properties corresponding to XLink elements and attributes." XSLT provides an excellent way to create such an application. The template rules in an XSLT stylesheet, which typically describe what to add to a result document when an XSLT processor finds elements or attributes meeting certain conditions in a source document, make it easy to look for various types of XLink markup and to then add markup to a result document that is appropriate to the intended output medium. Browsers and applications that understand XLink will be great, but they won't be necessary to take advantage of XLink. Just as XML is often used in systems that don't send XML to the client browser, XLink can still be useful in systems that don't require XLink-aware browsers. Systems can use XLink to manage information relationships and then ship whatever markup is appropriate to the client.

XLink Markup

You can turn any element into an XLink link or link component by adding a type attribute from the XLink namespace (http://www.w3.org/1999/xlink; for the remainder of this article, we'll assume that the namespace prefix xlink refers to this namespace) with a value of "simple," "extended," "locator," "arc," "resource," or "title." There are two basic kinds of links:

Because this is not an XLink tutorial, details about the use of its specialized elements and attributes will not be supplied here, but will be mentioned when necessary to describe the examples of XSLT template rules that process XLink elements.

An XSLT stylesheet serving as a general-purpose XLink processor must recognize XLink markup and treat XLink settings consistently for its output target regardless of how the markup was applied. For example, in the case of simple XLink links, the stylesheet should make the same use of the XLink information provided in the following two elements:

<recipe:ingredient 
  amount="2"
  units="cups" 
  xlink:type="simple"
  xlink:href="http://www.groceries.com/flour"
  xlink:actuate="onRequest"
  xlink:show="new"
  xlink:title="Buying Flour">
flour</recipe:ingredient>

<!-- Following example adapted from section 4 of XLink Rec -->

<my:crossReference
  xmlns:my="http://example.com/"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xlink:type="simple"
  xlink:href="students.xml"
  xlink:title="Student List"
  xlink:show="new"
  xlink:actuate="onRequest">
Current List of Students
</my:crossReference>

Although the two elements come from different namespaces and have different content and several different attributes, their xlink:href attributes and their common values for their actuate and show attributes means that the should get the same treatment.

Template Rules and Stylesheet Structure

An XSLT template rule, represented by an xsl:template element (assume all xsl namespace prefixes refer to the http://www.w3.org/1999/XSL/Transform namespace), is the basic building block of an XSLT stylesheet. The content of the xsl:template element is a template showing what the XSLT processor should add to the result tree when a certain condition is met. There are two categories of conditions that can trigger this addition:

Sophisticated stylesheets typically mix these two approaches, with match condition template rules used to address the structure of the source document and named template rules used to store instructions to be shared by multiple templates. For XLink development, XSLT named templates are an ideal place to store template instructions for XLink-related behavior.

XSLT's xsl:include and xs:import elements make it easier to modularize your stylesheets so that shared code can be separated out into its own stylesheet and then used by other stylesheets—in other words, they let you "include" instructions from another stylesheet much like an #include preprocessor directive in the C programming language lets a program incorporate C code from another file. The difference between the two XSLT elements is that stylesheet code included with xsl:include can be overridden by instructions in the including stylesheet, which is not possible with code imported with xsl:import.

Matching on Attribute and Namespace Values

Before looking at an example that uses named templates and xsl:import to cover a broad range of XLink possibilities, let's look at a brief example of another XSLT technique for taking advantage of a specification like XLink that uses attributes to add special semantics to otherwise arbitrary elements. In the match conditions used in template rules to implement the "push" technique mentioned earlier, the conditions usually mention element names. A match condition of "title" means "apply this template rule to all title elements"; a match condition of "chapter/title" means "apply this template rule to all title elements that have chapter elements as parents." Other template rules with more specific match conditions can override these; for example, if template rules with both of these "title" conditions were in the same stylesheet, the latter would be applied instead of the former for elements meeting that condition.

Many stylesheet developers don't understand how easy it is to create a match condition specifying that a template rule should be applied to all elements, regardless of their name, that have a particular attribute from a particular namespace—in the case of XLink, all elements that have the type element from the http://www.w3.org/1999/xlink namespace. For example, the following stylesheet's first template rule will be applied to any element that has a type attribute from the XLink namespace with a value of "simple" and an href attribute from the same namespace. When it finds one, the template rule will add an HTML version of the a element to the result tree that uses that href attribute value for the attribute of the same name (but not the same namespace!) in the result tree.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xlink="http://www.w3.org/1999/xlink"
                exclude-result-prefixes="xlink"           
                version="1.0">
  <xsl:output method="html"/>

  <xsl:template match="*[@xlink:type = 'simple' and @xlink:href]">
    <a href="{@xlink:href}"><xsl:apply-templates/></a>
  </xsl:template>

  <xsl:template match="recipe">
    <html><body>
      <xsl:apply-templates/>
    </body></html>
  </xsl:template>

</xsl:stylesheet>

This stylesheet will turn this source document

<recipe xmlns:xlink="http://www.w3.org/1999/xlink">
  <author xlink:href="http:/www.jcookie.com"
          xlink:type="simple">Joe "Cookie" Jones</author>
  <ingredients>
    <ingredient xlink:href="http:/www.snee.com/food/flour.html"
                xlink:type="simple">flour</ingredient>
    <ingredient xlink:href="http:/www.snee.com/food/sugar.html"
                xlink:type="simple">sugar</ingredient>
  </ingredients>
  <steps/>
</recipe>

into this HTML document:

<html>
   <body>
      <a href="http:/www.jcookie.com">Joe "Cookie" Jones</a>
      
      <a href="http:/www.snee.com/food/flour.html">flour</a>
      <a href="http:/www.snee.com/food/sugar.html">sugar</a>
      
      
      
   </body>
</html>

It's not a complex HTML document, but it does demonstrate an XSLT stylesheet's ability to implement a given set of XLink semantics regardless of the elements they are applied to: the stylesheet's first template rule converted both the author and ingredient elements in the source document to HTML a elements because of their XLink markup.

Let's look at a more powerful, general-purpose example.

sxlink2html.xsl and xltest.xsl

The following example demonstrates how an XSLT stylesheet can handle the combinations of the key settings of XLink's show and actuate attributes. The show attribute can have one of five values:

The actuate attribute tells the processor when to perform the activity named in the show attribute. A value of "onLoad" essentially tells the processor to perform the activity as soon as it sees the link. "onRequest" tells it to perform the activity when the user requests it by clicking some hyperlink text or image, or perhaps by some other input mechanism. As with the show values, an actuate value of "other" tells the processor to look to other markup for clues about when to perform the activity, and a value of "none" tells it that no such instructions are present.

The sxlink2html.xsl stylesheet skips the "other" and "none" settings for both attributes, and handles all the other combinations (all but onRequest/embed), and the xltest.xsl stylesheet demonstrates the use of sxlink2html.xsl for a document showing information on the use of curses in Shakespeare. The sxlink2html.xsl stylesheet only references elements and attributes from the XLink namespace to make it a general-purpose XLink processor—that is, so that it works with any document that uses XLink markup. Other stylesheets completely different from xltest.xsl could import or include sxlink2html.xsl to take advantage of how it converts XLink markup into the appropriate HTML markup. For certain actuate/show combinations, it also adds some JavaScript to get fancier with the result web page's presentation of the link implementation.

The "s" in "sxlink2html.html" stands for "simple"; for extended XLink links, the structure of the XSLT template rules used to look for the extended link XLink markup and then act on it would use all the same techniques. (The difficult part, when implementing extended XLink links with HTML+JavaScript, would not be knowing which markup to convert, which XSLT makes easy; it would be deciding on what to convert it to, given the limitations of the HTML+JavaScript combination.)

The sxlink2html.xsl stylesheet has two named templates. The "SimpleLinkOnLoad" one has an xsl:choose element to handle the three key values of the show attribute when the actuate attribute has a value of "onLoad." The "SimpleLinkOnRequest" named template has an xsl:choose element to handle the same three show attribute values when the actuate attribute has a value of "onRequest." A stylesheet using these named templates (in our example, xltest.xsl) must explicitly call the first template when it finds any element with an xlink:type value of "simple" and an xlink:actuate value of "onLoad," and it must call the other when it finds an element with an xlink:type value of "simple" and an xlink:actuate value of "onRequest." The logic within these named templates takes care of the rest.

In addition to taking appropriate actions based on the values of the xlink:type, xlink:actuate, xlink:show, and xlink:href attributes, the templates demonstrate possible implementations for the xlink:title and xlink:role attributes as well.

The xlink:title attribute, in the words of the spec, is supposed to "describe the meaning of a link or resource in a human-readable fashion." For simple XLink elements with an xlink:actuate value of "onRequest," which all get turned into an HTML a element, the xlink:title attribute value is used to add a title attribute to the HTML a element in the result tree. With recent releases of Internet Explorer and Netscape, this shows up as a little yellow rectangle that pops up when your mouse passes over the link text—a very nice way to hint to the user about what will happen if the link is followed. (For a link that has an xsl:actuate value of "onLoad," there's not much point in telling users anything about the consequences of following the link, because it's already been followed by the time they see it. If you disagree, feel free to change the template—that's what it's there for.)

The xlink:role attribute, which describes the role of a link or resource using a URI, does not contain information for "human consumption" but to signal information about the link to the processor. The SimpleLinkOnRequest template rule checks whether a link has an xlink:role value of "http://www.snee.com/roles/pay," which for the purposes of this example will be understood to mean that the resource costs money to be accessed, and sets the link text to appear in green when a mouse pointer passes over it.

How you take advantage of xlink:title or xlink:role attributes, or any of the XLink attributes not covered in this paper, is up to you, but the sample shows how easy it is for an XLink stylesheet to find these values and to then act on their information.

The following shows the sxlink2html.xsl and xltest.xsl stylesheets. (You can download these files, along with the sample input and output that demonstrates their use, from http://www.snee.com/xml.)

<!-- sxlink2html.xsl: a collection of named templates to call 
     for converting XLink simple links to HTML. 
-->

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xlink="http://www.w3.org/1999/xlink"
                version="1.0">

  <xsl:output method="html"/>

  <!-- Named templates to call from any        -->
  <!-- template that finds xlink:type="simple" -->        

  <xsl:template name="SimpleLinkOnLoad">

    <xsl:choose>

    <xsl:when test="@xlink:show='embed'">
      <!-- Read the external document in immediately. -->
      <xsl:apply-templates select="document(@xlink:href)"/>
    </xsl:when>

    <xsl:when test="@xlink:show='new'">
      <!-- Display href document in separate -->
      <!-- window right away ("onLoad").     -->
      <script language="JavaScript">
        <xsl:comment>
        open("<xsl:value-of select='@xlink:href'/>",
             "_blank","toolbar=no,scrollbars=no,resizable=1");
        </xsl:comment>
      </script>
    </xsl:when>

    <xsl:when test="@xlink:show='replace'">
      <!-- These are supposed to go inside the HTML HEAD element,  -->
      <!-- but in the BODY, it still works for IE5 and Netscape 6. -->
      <META HTTP-EQUIV="Refresh" 
        CONTENT="0; URL={@xlink:href}"/>
    </xsl:when>

    </xsl:choose>

    <xsl:apply-templates/>

  </xsl:template>


  <xsl:template name="SimpleLinkOnRequest">

    <xsl:element name="a">

      <!-- An onRequest simple link is all about which        -->
      <!-- attributes to add to a traditional HTML a element. -->

      <xsl:attribute name="href">
        <xsl:value-of select="@xlink:href"/>
      </xsl:attribute>

      <xsl:choose>

        <xsl:when test="@xlink:show='embed'">
          <!-- Can't implement on client side -->
          <!-- using HTML+JavaScript.         -->
          <!-- 5 out of 6 ain't bad!          -->
        </xsl:when>

        <xsl:when test="@xlink:show='new'">
          <!-- Display target document in a new widow. -->
          <xsl:attribute name="target">_blank</xsl:attribute>
        </xsl:when>

        <!-- Following not necessary, because replacing 
             document with target document on clicking 
             of link is default behavior of HTML A element.
        <xsl:when test="@xlink:show='replace'">
        </xsl:when>
        -->
      </xsl:choose>

      <xsl:if test="@xlink:title">
        <!-- In current IE and Navigator, a element's  -->
        <!-- title value pops up for onMouseOver.      -->
        <xsl:attribute name="title">
          <xsl:value-of select="@xlink:title"/>
        </xsl:attribute>
      </xsl:if>

      <!-- 5.5 of XLink spec: The value of the role or     -->
      <!-- arcrole attribute must be a URI reference...the -->
      <!-- URI reference identifies some resource that     -->
      <!-- describes the intended property.                -->

      <xsl:if test="@xlink:role='http://www.snee.com/roles/pay'">
        <!-- To show that this link costs, turn text to -->
        <!-- green for onMouseOver then back to blue.   -->
        <xsl:attribute name="onMouseOver">
         <xsl:text>style.color="green"</xsl:text>
        </xsl:attribute>
        <xsl:attribute name="onMouseOut">
         <xsl:text>style.color="blue"</xsl:text>
        </xsl:attribute>
      </xsl:if>

    <xsl:apply-templates/>

    </xsl:element>

  </xsl:template>

</xsl:stylesheet>

The xltest.xsl stylesheet has two template rules that call the two named templates from sxlink2html.xsl. One wraps its result in p tags, and the other doesn't. Both check whether the context node element has an xlink:type attribute value of "simple," and if so, calls either the SimpleLinkOnLoad or SimpleLinkOnRequest named template depending on the value of the xlink:actuate attribute.

<!-- xltest.xsl: convert XLink simple links to HTML -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xlink="http://www.w3.org/1999/xlink"
                version="1.0">

  <!-- Demonstrate the use of XLink         -->
  <!-- implementation in sxlink2html.xsl by -->
  <!-- reading xltest.xml and dummytoc.xml. -->

  <xsl:import href="sxlink2html.xsl"/>

    <xsl:template match="dictionary | xref | tocMarker">

      <xsl:if test="@xlink:type = 'simple'">
        <xsl:if test="@xlink:actuate='onLoad'">
          <xsl:call-template name="SimpleLinkOnLoad"/>
        </xsl:if>
        <xsl:if test="@xlink:actuate='onRequest'">
          <xsl:call-template name="SimpleLinkOnRequest"/>
        </xsl:if>
      </xsl:if>
    </xsl:template>

    <!-- Just like template rule above, -->
    <!-- but wraps output in p element. -->
    <xsl:template match="toc | author">
    <p>
      <xsl:if test="@xlink:type = 'simple'">
        <xsl:if test="@xlink:actuate='onLoad'">
          <xsl:call-template name="SimpleLinkOnLoad"/>
        </xsl:if>
        <xsl:if test="@xlink:actuate='onRequest'">
          <xsl:call-template name="SimpleLinkOnRequest"/>
        </xsl:if>
      </xsl:if>
    </p>
  </xsl:template>


  <xsl:template match="xlinktest">
    <html><body>
      <xsl:apply-templates/>
    </body></html>
  </xsl:template>


  <xsl:template match="title">
    <h1><xsl:apply-templates/></h1>
  </xsl:template>


  <xsl:template match="par">
    <p><xsl:apply-templates/></p>
  </xsl:template>

</xsl:stylesheet>

Conclusion

How you implement the XLink instructions for your own output medium is up to your own creativity and your knowledge of your medium's range of user interface tricks. In my sample application, I used a little JavaScript and some features available in recent Navigator and Internet Explorer releases to show how easy it is for an XSLT stylesheet to look for XLink markup in an XML document and to then act on it. By separating out the key logic for processing the XLink markup into named templates stored in a separate stylesheet, that stylesheet can be imported into a wide variety of other stylesheets converting XML documents for use in the same medium, regardless of the document types taking advantage of XLink features in those documents.

XLINK 01 Steve DeRose, Eve Maler, and David Orchard, editors. XML Linking Language (XLink) Version 1.0. World Wide Web Consortium, 2001. (See http://www.w3.org/TR/xlink/.) XSLT 99 James Clark, editor. XSL Transformations (XSLT) 1.0. World Wide Web Consortium, 1999. (See http://www.w3.org/TR/xslt/>.)