Scripting Xalan XSL with Python
In contrast, Python extensions are just as dynamic as, well, Python scripts in general. In the most simple scenario, one just updates the XSL stylesheet and its embedded Python functions and does nothing more. Even in the more complicated use scenarios, updating the code is rather trivial.
To use Python with Xalan, you need two libraries: bsf.jar and jython.jar, Bean scripting framework and Jython implementation, respectively. There's a catch, though. The bean scripting framework was originally implemented at IBM, but was later donated to Jakarta Apache project. Now, the current distribution of BSF at Jakarta is complete, but it seems that they've changed the package names to correspond the current maintainer, org.apache.bsf etc., but recent implementations of Xalan live in the past and expect the BSFManager and BSFEngine to be in package com.ibm.bsf.
So, if you just use the Jakarta's bsf.jar and standard jython.jar (and put them in the classpath), you will probably see a longish stack trace, complaining something like this:
java.lang.ClassNotFoundException: com/ibm/bsf/BSFManager
There is, at least, two ways to resolve this.
The easier way is to grab bsf.jar from http://archive.apache.org/dist/ws/soap/version-2.2/.
It should work as such. The other way is to grab the binary or source release of BSF from Jakarta (which, by the way, as a website is completely confusing and unusable) and make dummy implementations of the classes com.ibm.bsf.BSFManager and com.ibm.bsf.BSFEngine.
For BSFManager, you need to create class BSFManager in the package com.ibm.bsf and make it extend org.apache.bsf.BSFManager, thus:
package com.ibm.bsf;For BSFEngine, things are a bit trickier. See,public class BSFManager extends org.apache.bsf.BSFManager {}
org.apache.bsf.BSFEngine is only an interface, which is partly implemented by org.apache.bsf.BSFEngineImpl. The rest is left to concrete implementations. But need not worry, you can just fake the BSFEngine with an implementation of your needs, thus:
package com.ibm.bsf;With these tweaks, you can use the Jakarta BSF distribution as you would use the original IBM distribution. To make things somewhat modular in the XSL world (XSL and modularity don't quite fit in the same sentence, though), we first create a funcs.xsl stylesheet:import org.apache.bsf.engines.jython.JythonEngine;
public class BSFEngine extends JythonEngine {}
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:xalan="http://xml.apache.org/xalan"
xmlns:jython="ext_jython"
exclude-result-prefixes="jython">
<xalan:component prefix="jython" functions="rjust">
<xalan:script lang="jython">
def rjust(s, length):
return s[:int(length)].rjust(int(length))
</xalan:script>
</xalan:component>
</xsl:stylesheet>
And use it in another stylesheet:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:jython="ext_jython" exclude-result-prefixes="jython">Which results in a right-justified (to 19 characters) string. (Right-justifying is of course possible in pure XSL too, but programming in XSL is just too painful.)<xsl:include href="funcs.xsl" />
<xsl:output method="xml" encoding="utf-8"/>
<xsl:template match="/"> <xsl:apply-templates /> </xsl:template>
<xsl:template match="p"> <xsl:value-of select="jython:rjust(string(.), 19)"/> </xsl:template> </xsl:stylesheet>
Now, if you process these stylesheets with Java (and Xalan), like I showed in a previous post, and have CLASSPATHs and the relative path to the xsl:include correct, you should have a successful result applying Python scripting in XSL stylesheet.
Update: two things I forgot to say. First, Xalan extensions work fine with different charsets, at least with ISO-8859-1 and UTF-8 (what more do you need?). Second, the performance seems comparable to Java methods though I haven't really measured it and won't announce some half-hearted numbers from ad-hoc tests like I have done before. At least in our environment, which consists of many subsystems and other potential bottle-necks, scripting XSL with Python doesn't seem to make a significant impact to the performance.
Another update: In case you download the readily available bsf.jar from archive.apache.org etc., you need to declare that the script language is jpython, like this:
<xalan:script lang="jpython">
(Instead of "jython", that is.)