A Slightly More Complicated XML Document in Need of Links

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