Entries from January 2007 ↓

A tourist trap in Ghana

It’s not every day one hears about Ghana. Most Americans don’t know where it is, and many don’t even know it exists. The only mainstream media that gives Ghana any attention is the BBC News, but their stories are almost always soccer-related: a Ghanaian player transfers to a European club, a coach for the Black Stars gets fired, that sort of thing. As a returned Peace Corps Ghana volunteer, I’m a little disappointed the country doesn’t get more press.

That’s why, when watching ABC World News Tonight last December, my mouth dropped open. Charles Gibson suddenly started talking about Ghana! The story, from London-based correspondent Mike Lee, was all about Paga, a small town far in the northeast that is famous for one thing: crocodiles.

Note that Mike mispronounces the town’s name: It’s pägä, not pāgä. (Surprising, given that he actually visited the place.) Otherwise, it’s a nice segment that provides a fun glimpse into Ghanaian-style tourism. If you’re interested in even more scenes from Paga, check out the videos Straddling a Crocodile and sight n sound from the jungle.

These videos are especially fascinating for me because I’ve never actually been to Paga, even though I lived for twenty-six months in Tumu, a town less than 100 kilometers away. And I would often pass through Navrongo, a town just 10 kilometers from Paga, for my trips south. (If you use Google Earth, see just how close I was.)

So why did I never end up in Paga? At the time, I was much more interested in using my vacation days to head down to Accra, the only place in the whole country where a guy can get a burger, a shake, and a movie! But the next time I visit Ghana, I’ll definitely be swinging by Paga.

How to use Saxon with Ant

As the only open-source processor that supports the XSLT 2.0 specification, Saxon is becoming indispensable. I use it in my HR-XSL project, and the new functions and features of XSLT 2.0 have helped make the code a lot simpler.

A typical way of running Saxon is via Ant, which offers built-in support for XSLT processors. Its Xslt task defaults to the Xalan processor, but because this task understands the TrAX API, switching to Saxon is trivial. All you need to do is put Saxon’s JAR on the classpath. (This works because Saxon declares support for the TransformerFactory service in its manifest. When TrAX finds a match for this service, it knows which processor to use.)

But there’s a problem here. Xalan also supports TrAX, so it specifies the TransformerFactory service, as well. Thus it becomes a contest. The first processor listed on the classpath wins!

Now, one would think this wouldn’t be an issue. Xslt’s classpath attribute trumps the system’s classpath, right? Unfortunately, that’s not how it works—as discussed in the Ant FAQ—and as a result, you get unpredictable behavior: Your Ant script may or may not use Saxon depending on whether Xalan happens to be in your system’s classpath. This can be a real problem if, for example, you’ve used Fink to install Ant, which places Xalan on the system classpath by default.

All right, so that’s bad. Is there an easy way to solve this dilemma? How about the <factory> element of the Xslt task? It specifies a particular transformer factory to use, rather than letting TrAX instantiate the first one it happens to find. With this element, you should easily be able to force Ant to use Saxon, like this:

<xslt ...>
    <classpath location=“/path/to/saxon.jar”/>
    <factory name=“net.sf.saxon.TransformerFactoryImpl”/>

Alas, this also fails to work. For some reason, Ant always throws a ClassNotFoundException when you try to use the <factory> element this way. (See bug #41314 for more details.)

This was starting to hurt. I didn’t want my HR-XSL users submitting bug reports just because Ant couldn’t find Saxon. I needed a way to ensure that Saxon would run every time.

After following a number of dead ends, I finally found a solution. The trick is to set the Java property javax.xml.transform.TransformerFactory to Saxon’s transformer factory class. The TrAX implementation in Ant happens to look for this property and, if set, it will use the specified class rather than whatever it discovers on the classpath.

The hard part, surprisingly, is how to set the property. Ant provides no mechanism for changing Java’s system properties, so I rely instead on a custom Java class that extends and replaces Ant’s default TrAX handler. Just before a transformation occurs, it sets the transform factory property to net.sf.saxon.TransformerFactoryImpl, forcing Saxon to be used, then it restores the previous setting when the transformation is complete. (Restoring the property prevents conflicts with other XSLT-related Ant tasks, such as FOP.)

Once this class has been compiled, you tell Ant to use it via the processor attribute. For example, if the custom class is called SaxonLiaison (to reflect the class that it overrides, TraXLiaison), you’d call the Xslt task like this:

<xslt ... processor=“SaxonLiaison”>
    <classpath location=“/path/to/saxon.jar:/path/to/SaxonLiaison”/>

That’s it! Saxon will be used every time, regardless of what’s on the system classpath.

You can find a complete listing of my SaxonLiaison custom class in the util directory of the HR-XSL distribution.