page 156 xsl:apply-templates select=wordlist mode=default
xsl:apply-templates select=wordlist mode=Spanish xsl:template
xsl:template match=wordlist mode=unsorted xsl:textWord list - unsorted:xsl:text
xsl:value-of select=newline xsl:for-each select=word
xsl:value-of select=. xsl:value-of select=newline
xsl:for-each xsl:value-of select=newline
xsl:template xsl:template match=wordlist mode=default
xsl:textWord list - sorted with default rules:xsl:text xsl:value-of select=newline
xsl:for-each select=word xsl:sort select=.
xsl:value-of select=. xsl:value-of select=newline
xsl:for-each xsl:value-of select=newline
xsl:template xsl:template match=wordlist mode=Spanish
xsl:textWord list - sorted with Spanish rules:xsl:text xsl:value-of select=newline
xsl:for-each select=word xsl:sort select=. lang=es
xsl:value-of select=. xsl:value-of select=newline
xsl:for-each xsl:value-of select=newline
xsl:template xsl:stylesheet
When we run the stylesheet against our document, it invokes the three templates with three different
mode
s. One template simply lists the
word
elements as they appear in the original document, the second sorts the
word
elements using the default sorting sequence, and the third sorts the
word
elements using the traditional rules of Spanish sorting. Refreshingly enough, the code that implements the sorting function is simple. Heres the entire listing:
package com.icl.saxon.sort; import java.text.ParseException;
import java.text.RuleBasedCollator; import java.util.Locale;
public class Compare_es extends TextComparer {
private static String smallnTilde = new String\u00F1; private static String capitalNTilde = new String\u00D1;
private static String traditionalSpanishRules = a,A b,B c,C +
ch, cH, Ch, CH + d,D e,E f,F +
g,G h,H i,I j,J k,K l,L + ll, lL, Ll, LL +
m,M n,N + + smallnTilde + , + capitalNTilde + +
o,O p,P q,Q r,R + s,S t,T u,U v,V w,W x,X +
y,Y z,Z; private static RuleBasedCollator rbc = null;
static {
try {
rbc = new RuleBasedCollatortraditionalSpanishRules;
page 157 }
catch ParseException pe {
System.err.printlnError creating RuleBasedCollator: + rbc; }
} public int compareObject a, Object b
{ if rbc = null
return rbc.compareStringa, Stringb; else
return 0; }
}
See the documentation for the
java.text.RuleBasedCollator
class for an explanation of the
traditionalSpanishRules
string. When Saxon sees an
xsl:sort
element with a
lang
attribute of
es
, it attempts to load a Java class named
com.icl.saxon.sort.Compare_es
. If that class can be loaded, Saxon calls that classs
compare
method as it sorts the
word
elements. When we run the stylesheet against our earlier example document, here are the results:
Word list - unsorted: campo
luna ciudad
llaves chihuahua
arroz limonada
Word list - sorted with default rules: arroz
campo chihuahua
ciudad limonada
llaves luna
Word list - sorted with Spanish rules: arroz
campo ciudad
chihuahua limonada
luna llaves
In the output, our Spanish sorting routine puts
chihuahua
after
ciudad
, and
llaves
after
luna
. With less than 20 lines of code, weve been able to add a new sorting function to our
stylesheet. Most of the work is done for us by the Saxon processor and the methods of the
java.text.RuleBasedCollator
class. The Saxon documentation has more information on extending Saxon with your own code. As
youll see in the examples in this chapter, most of the Java extensions youll need to write will be simple pieces of code that simply make Java library methods and classes available to the
XSLT processor.
page 158
8.3 More Examples
You can use XSLT extension mechanisms to push XSLT processing beyond text or markup generation and to read information from non-XML sources.
8.3.1 Generating JPEG Files from XML Content
When converting XML content into HTML files for a web site, there are times when you want to have complete control over the look of a piece of text. In this example, well use an
extension function to convert the text of an XML element into a JPEG graphic. Our code will load a JPEG background graphic, draw the text from the XML document on top of it, and
then write the graphic out to a new JPEG file. Well reuse the XML file from our first example to demonstrate the extension function.
Our stylesheet passes each
title
element to the extension function. When we invoke the extension, well also pass in the name of the background JPEG, the name of the output file
which well call title1.jpg, title2.jpg, etc., and various information about the font name, font size, and other parameters. Heres what our stylesheet looks like:
?xml version=1.0? xsl:stylesheet version=1.0 xmlns:xsl=http:www.w3.org1999XSLTransform
xmlns:jpeg=xalan:JPEGWriter extension-element-prefixes=jpeg
xsl:output method=html xsl:template match=
html head
title xsl:value-of select=booktitle
title head
body xsl:for-each select=bookchapter
xsl:choose xsl:when test=function-availablejpeg:createJPEG
xsl:value-of select=jpeg:createJPEGtitle, bg.jpg,
concattitle, position, .jpg, Swiss 721 Bold Condensed, BOLD, 22, 52, 35
img xsl:attribute name=src
xsl:value-of select=concattitle, position, .jpg xsl:attribute
img br
xsl:when xsl:otherwise
h1xsl:value-of select=titleh1 xsl:otherwise
xsl:choose xsl:for-each
body html
xsl:template xsl:stylesheet
page 159
Our background JPEG looks like Figure 8-4
.
Figure 8-4. Background JPEG image
Figure 8-5 shows a couple of graphics created by the combination of our XML sample
document, our stylesheet, and the extension function.
Figure 8-5. Generated JPEG files for XML title elements
These files are title1.jpg and title8.jpg, respectively. Our extension function has taken the text of the appropriate
title
elements, drawn it on top of the background graphic, then written the new image out as a JPEG graphic.
Lets take a look at the call to our extension function:
xsl:value-of select=jpeg:createJPEGtitle, bg.jpg,
concattitle, position, .jpg, Swiss 721 Bold Condensed, BOLD, 22, 52, 35
First of all, look at the call itself. What weve written here is
jpeg:createJPEG
as the name of the function. The namespace prefix
jpeg
is defined in the stylesheet. We associated this prefix with the string
xalan:JPEGWriter
; this string tells Xalan that any function invoked with this prefix should be treated as a method of the named class
JPEGWriter
. If you use an XSLT processor other than Xalan, the way you define and invoke an extension function will
probably vary. Next, lets look at the parameters to the function. Were passing eight different parameters:
•
The text that should be written in the JPEG image. This text is passed in as a
NodeList
, one of the datatypes available to us in the Xalan API. In our previous example, were selecting all
title
elements contained in the current node.
•
The filename of the background image that should be used. This filename is passed in as a
String
.
•
The filename of the created JPEG image. The image will be created, then written out to this filename. Notice that in our example, we generate the filename by
concatenating the string title, the position of the current node, and the string .jpg. This procedure ensures that all our title graphics have unique filenames. It also makes
it easy to determine which JPEG matches a given
title
element.
•
The name of the font we want to use. This name is a
String
.
•
The font style we want to use. Weve written our function to accept three different values:
BOLD
,
ITALIC
, and
BOLDITALIC
. These values mirror the three values used by the Java
Font
class.