page 90
In our modified document, weve added two new attributes to
defn
:
topic
and
language
. We also added the
acronym
attribute to the
term
element. Weve modified our DTD to add these attributes and enumerate their valid values:
--The word being defined-- ELEMENT term PCDATA
--The id is used for cross-referencing, and the xreftext is the text used by cross-references.--
ATTLIST term id ID REQUIRED
xreftext CDATA IMPLIED acronym yes|no no
--The definition of the term-- ELEMENT defn PCDATA | xref | seealso
--The topic defines the subject of the definition, the language code defines the language of this definition,
and the acronym is yes or no default is no.-- ATTLIST defn
topic Java|general|security general language en|de|es|it|jp en
The
topic
attribute defines the computing topic to which this definition applies, and the
language
attribute defines the language in which this definition is written. The
acronym
attribute defines whether or not this term is an acronym. Now that weve created a more flexible XML document, we can use the
key
function to do several useful things:
•
We can find all
defn
elements that are written in a particular language as long as its one of the five languages we defined.
•
We can find all
defn
elements that apply to a particular topic.
•
We can find all
term
elements that are acronyms. Thinking back to our earlier discussion, these are all things we cant do with the
id
function. If the
language
,
topic
, and
acronym
attributes were defined to be of type
ID
, only one definition could be written in English, only one definition could apply to the security
topic, and only one term could be an acronym. Clearly, thats an unacceptable limitation on our document.
5.2.3 Stylesheets That Use the key Function
Weve mentioned some useful things we can do with the
key
function, so now well build some stylesheets that use it. Our first stylesheet will list all definitions written in a particular
language. Well go through the various parts of the stylesheet, explaining all the things we had to add to make everything work. The first thing well do, of course, is define the
key
function:
xsl:key name=language-index match=defn use=language
Notice that the
match
attribute we used was the simple element name
defn
. This tells the XSLT processor to match all
defn
elements at all levels of the document. Because of the structure of our document, we could have written
match=glossaryglentrydefn
, as well. Although this XPath expression is more restrictive, it matches the same elements because all
defn
elements must appear inside
glentry
elements, which in turn appear inside the
glossary
element.
page 91
Next, we set up our stylesheet to determine what value of the
language
attribute were searching for. Well do this with a global
xsl:param
element:
xsl:param name=targetLanguage
Recall from our earlier discussion of the
xsl:param
element that any top-level
xsl:param
is a global parameter to the stylesheet and may be set or initialized from outside the stylesheet. The way to do this varies from one XSLT processor to another. Heres how its
done with Xalan. The command should be on one line.
java org.apache.xalan.xslt.Process -in moreterms.xml -xsl crossref2.xsl -param targetLanguage it
If you use Michael Kays Saxon processor, the syntax looks like this:
java com.icl.saxon.StyleSheet moreterms.xml crossref2.xsl targetLanguage=it
Now that weve defined our
key
function and defined a parameter to specify which language were looking for, we need to generate our output. Heres the modified template that
generates the HTML
title
and
h1
tags:
xsl:template match=glossary html
head title
xsl:textGlossary Listing: xsl:text xsl:value-of select=keylanguage-index,
targetLanguage[1]preceding-sibling::term xsl:text - xsl:text
xsl:value-of select=keylanguage-index, targetLanguage[last]preceding-sibling::term
title head
body h1
xsl:textGlossary Listing: xsl:text xsl:value-of select=keylanguage-index,
targetLanguage[1]ancestor::glentryterm xsl:text - xsl:text
xsl:value-of select=keylanguage-index, targetLanguage[last]ancestor::glentryterm
h1 xsl:for-each select=keylanguage-index, targetLanguage
xsl:apply-templates select=ancestor::glentry xsl:for-each
body html
xsl:template
There are a couple of significant changes here. When we were using the
id
function, it was easy to find the first and last terms in the document. Because were now trying to list only the
definitions that are written in a particular language, that wont work. Reading the XPath expressions in the
xsl:value-of
elements from left to right, we find the first and last
defn
elements returned by the
key
function, then use the
preceding-sibling
axis to reference the
term
element that preceded it. We could also have written our XPath expressions using the
ancestor
axis:
h1 xsl:textGlossary Listing: xsl:text
xsl:value-of select=keylanguage-index, targetLanguage[1]ancestor::glentryterm
xsl:text - xsl:text xsl:value-of select=keylanguage-index,
targetLanguage[last]ancestor::glentryterm h1