A Stylesheet That Uses the id Function
page 85
•
We need to process any
seealso
elements, as well. These elements are handled similarly to the
xref
elements, the main difference being that the
refids
attribute of the
seealso
element can refer to more than one glossary entry.
Figure 5-1. HTML document with generated cross-references
Heres the template that takes care of our first task, generating the HTML
title
and the
h1
:
xsl:template match=glossary html
head title
xsl:textGlossary Listing: xsl:text xsl:value-of select=glentry[1]term
xsl:text - xsl:text xsl:value-of select=glentry[last]term
title head
body h1
xsl:textGlossary Listing: xsl:text xsl:value-of select=glentry[1]term
xsl:text - xsl:text xsl:value-of select=glentry[last]term
h1 xsl:apply-templates select=glentry
body html
xsl:template
We generate the
title
and
h1
using the XPath expressions
glentry[1]term
for the first
term
in the document, and using
glentry[last]term
for the last term. Our next step is to process all the
glentry
elements. Well generate an HTML paragraph for each one, and then well generate a named anchor point, using the
id
attribute as the name of the anchor. Heres the template:
xsl:template match=glentry p
b a name={id}
xsl:value-of select=term xsl:text: xsl:text
b xsl:apply-templates select=defn
page 86 p
xsl:template
In this template, were using an attribute value template to generate the
name
attribute of the HTML
a
element. The XPath expression
id
retrieves the
id
attribute of the
glentry
element were currently processing. We use this attribute to generate a named anchor. We then write the term itself in bold and apply the template for the
defn
element. In our output document, each glossary entry contains a paragraph with the highlighted term and its
definition. The
name
attribute of this HTML
a
element is generated with an attribute value template. See
Section 3.3 for more information.
Our next step is to process the cross-reference. Heres the template for the
xref
element:
xsl:template match=xref a href={refid}
xsl:choose xsl:when test=idrefidxreftext
xsl:value-of select=idrefidxreftext xsl:when
xsl:otherwise xsl:value-of select=idrefid
xsl:otherwise xsl:choose
a xsl:template
We create the
a
element in two steps:
•
Create the
href
attribute. It must refer to the correctly named anchor in the HTML document.
•
Create the text of the link. This text is the word or phrase that appears in the browser; clicking on the link should take the user to the referenced term.
For the first step, we know that the
href
attribute must contain a hash mark followed by
the name of the anchor point. Because we generated all the named anchors from the
id
attributes of the various
glentry
elements, we know the name of the anchor point is the same as the
id
. Now all thats left is for us to retrieve the text. This retrieval is the most complicated part of
the process relatively speaking, anyway. Remember that we want to use the
xreftext
attribute of the
term
element, if there is one, and use the text of the
term
element, otherwise. To implement an if-then-else statement, we use the
xsl:choose
element. In the previous sample, we used a
test
expression of
idrefidxreftext
to see if the
xreftext
attribute exists. Remember, an empty node-set is considered false. If the attribute doesnt exist, the node-set will be empty and the
xsl:otherwise
element will be evaluated. If the
test
is true, we use
idrefidxreftext
to retrieve the cross-reference text. The first part of the XPath expression
idrefid
returns the node that has an
ID
that matches the value
refid
; the second part
xreftext
retrieves the
xreftext
attribute of that node. We insert the text of the
xreftext
attribute inside the
a
element. Finally, we handle any
seealso
elements. The difference here is that the
refids
attribute can reference any number of glossary terms, so well use the
id
function differently.
page 87
Heres the template for
seealso
:
xsl:template match=seealso b
xsl:textSee also: xsl:text b
xsl:for-each select=idrefids a href={id}
xsl:choose xsl:when test=xreftext
xsl:value-of select=xreftext xsl:when
xsl:otherwise xsl:value-of select=.
xsl:otherwise xsl:choose
a xsl:if test=notposition=last
xsl:text, xsl:text xsl:if
xsl:for-each xsl:text. xsl:text
xsl:template
There are a couple of important differences here. First, we call the
id
function in an
xsl:for-each
element. Calling the
id
function with an attribute of type
IDREFS
returns a node-set; each node in the node-set is the match for one of the
ID
s in the attribute. The second difference is that referencing the correctly named anchor is more difficult. When
we processed the
xref
element, we knew that the correct anchor name was the value of the
refid
attribute. When processing
seealso
, the
refids
attribute doesnt do us any good because it may contain any number of
ID
s. All is not lost, however. What we did previously was use the
id
attribute of each node returned by the
id
function—a minor inconvenience, but another difference in processing an attribute of type
IDREFS
instead of
IDREF
. The final difference is that we want to add commas after all items except the last. The
xsl:if
element shown previously does just this. If the
position
of the current item is the last, we dont output the comma and space defined here with the
xsl:text
element. We formatted all references here as a sentence; as an exercise, feel free to process the items in a
more sophisticated way. For example, you could generate an HTML list from the
IDREFS
, or maybe format things differently if the
refids
attribute only contains a single
ID
. Weve done several useful things with the
id
function. Weve been able to use attributes of type
ID
to discover the links between related pieces of information, and weve converted the XML into HTML links, renderable in an ordinary household browser. If this is the only kind
of linking and referencing you need to do, thats great. Unfortunately, there are times when we need to do more, and on those occasions, the
id
function doesnt quite cut it. Well mention the limitations of the
id
function briefly, then well discuss XSLT functions that let us overcome them.