Prototyping One-to-many Links with XSLT
March 5, 2003
While reading Micah Dubinko's SkunkLink proposal, I noticed his nested a links and thought they were a nice, simple way to represent one-to-many links. Before telling people "this is how XHTML should represent one-to-many links," I thought it would be better to get a working prototype running. How could I turn nested a elements into working pop-up menus? With an XSLT stylesheet, of course. Because Internet Explorer and Mozilla can dynamically apply a stylesheet to an XML document when you ask them to display that document, it makes a particularly nice demo: you bring up the document that has nested a elements, and pop-up menus appear when you click on them.
|Figure 1: Converting link architecture to prototype with XSLT|
Pop-up menus are the most obvious way to render one-to-many links in a browser. If Internet Explorer and Mozilla had used similar pop-up menus to implement the applicable XLink extended links, XLink would be much more popular today, and one-to-many links would be a common part of every web developer's vocabulary.
If you want it to work on a wide variety of browser-release/platform combinations, you will end up tearing a lot of hair out.
A Sample Linking Architecture
The basic unit of this sample linking architecture is a multilink element, which I embed as needed in an XHTML file. The following shows the markup for a sample paragraph that includes one of these links:
<p>I have written multi-part columns on topics such as <multilink id="l001" type="columns"> <title>XML.com columns on controlling whitespace</title> <indicator>controlling whitespace</indicator> <linkend title="Controlling Whitespace, Part 1" URI="http://www.xml.com/pub/a/2001/11/07/whitespace.html"/> <linkend title="Controlling Whitespace, Part 2" URI="http://www.xml.com/pub/a/2001/12/05/whitespace.html"/> <linkend title="Controlling Whitespace, Part 3" URI="http://www.xml.com/pub/a/2002/01/02/whitespace.html"/> </multilink>.</p>
The multilink element consists of a title describing the link as a whole, an indicator element to hold text (or perhaps a reference to a picture) used to identify the presence of a link in the rendered document, and one or more linkend elements. Each linkend element, which is empty, has a title attribute to identify the linked resource and a URI attribute to show the resource's location. The multilink element has two attributes of its own: an id attribute for a unique ID and a type attribute to assign the link a type from a choice created for the purposes of the demo article. (It's really a link destination type, and not a link type; the values describe the linked resource, not the link connecting the resources. Either way, it can provide an aid to navigation.)
Don't take this "linking architecture" too seriously. I don't really think that a link end title should be an attribute of linkend. I also think that connections to individual link ends should be typed as well as the links themselves (see XLink's arcrole attribute) because different link ends can play different roles within a link. The multilink architecture shown here is a quick stab at representing multi-ended links with some useful metadata that isn't tied to a particular rendering medium. Now, let's see about rendering it.
Getting it to Work
window.l001 = new Menu(); l001.addMenuItem("Controlling Whitespace, Part 1", "location='http://www.xml.com/pub/a/2001/11/07/whitespace.html'"); l001.addMenuItem("Controlling Whitespace, Part 2", "location='http://www.xml.com/pub/a/2001/12/05/whitespace.html'"); l001.addMenuItem("Controlling Whitespace, Part 3", "location='http://www.xml.com/pub/a/2002/01/02/whitespace.html'"); l001.disableDrag = true; l001.fontSize = 12; l001.menuItemHeight = 30; l001.menuItemIndent = 5;
Each pop-up menu needs a name, so I used the value of the multilink element's id attribute to create the name: "l001". The addMenuItem method that adds a choice to the menu gets called three times above; several menu properties are set directly to tweak the menu's appearance.
The markup necessary to call the defined menu is as simple as this:
(This excerpt leaves a few lines out to make the important parts of the structure clearer.)
These two nested xsl:for-each elements are the heart of this mapping of a linking architecture to the UI code that shows how the architecture might be implemented. By finding all the link markup in the document and mapping the information there to the code required for the user interface widgets that you use, similarly nested xsl:for-each elements could implement other one-to-many link architectures to take advantage of the same Netscape DevEdge library or a different one. Whether the information you pull out of your linking elements are in their subelements or attributes (or, for that matter, processing instructions) depends on the linking architecture being demonstrated. (For example, compare this article's multilink/linkend links with the nested a elements that I used the first time I tried this.) What you do with this information depends on the features available in the UI that you use to demonstrate your architecture.
The third template rule is brief enough to show in its entirety here:
When the XSLT processor finds a multilink element during its normal traversal of the source tree (as opposed to finding one with the xsl:for-each loop used in the first template rule), it adds an HTML a element to the result tree. When clicked, this a element displays the menu defined earlier for this link. It also adds the menu's type (in my example document, a value of either "columns," "specs," or "postings") as a class attribute so that a CSS stylesheet can assign it a specific color based on that class. The last attribute added is the a element's title, which stores the multilink element's title value so that a mouseover action will display that title in a little pop-up rectangle.
The fourth and final template rule is a standard one in many XSLT stylesheets. It copies everything not caught by other template rules to the result tree verbatim. Because this stylesheet assumes that everything in the document apart from the multilink elements will be XHTML, this template rule ensures that any semantics of the source document unrelated to multilink will have the desired effect in the browser.
Telling someone to point their browser at an XML document that demonstrates your linking architecture with a slick UI will be great, but be sure to perform some intermediate tests before relying on the XSLT processors built into the browsers. Test your sample document and stylesheet with a command-line XSLT processor such as Xalan or Saxon. Use one or both of these to create an HTML disk file from your source XML and your stylesheet, and then see if the HTML file does everything you expect when displayed in a browser.
Also in Transforming XML
Remember that your prototype is supposed to demonstrate what could happen with your linking architecture, not what should happen. A good architecture lends itself to multiple UIs. Different demos like the one described here for the same linking architecture would be a great way to demonstrate the architecture's value. Take the different pieces of information in the architecture and the different features of the UI being used and mix and match them. Or skip the UI for one demo: write something that harvests the links into a database and then does something interesting with that.