Extending the Saxon Processor

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.