April 17, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Xalan: Extending XSLT with Java

  • August 1, 2000
  • By Benoît Marchal
  • Send Email »
  • More Articles »

If you have developed with XML, you probably have learned XSLT (Extensible Stylesheet Language Transformations), the transformation language underlying so many XML solutions. Developers use XSLT to transform XML documents to HTML, enabling fast publishing of XML. It can also be used to convert between different XML vocabularies (DTDs), such as DocBook and XHTML or WML.

XSLT is a useful addition to the Java developer toolbox, but many complain that is too limited. In my experience, I find that XSLT provides 70% to 95% of what I need, and I have to complement that with Java coding. This article demonstrates one solution to enhancing XSLT with Java.

XSLT Fell Short

To introduce this example, I need to discuss ISBN (International Standard Book Number) briefly. Look on the back of any book and you will see an ISBN along with the barcode. The ISBN is a number that uniquely identifies the book. No two titles have the same number across the publishing industry worldwide.

Listing 1 is an XML purchase order. The order simply lists books by ISBN, there is no need to include titles or author names: the ISBN prevents confusion, and it saves bandwidth, which can be important when ordering thousands of books at a time.


<?xml version="1.0"?>
<PurchaseOrder>
   <From>
      <Address>Playfield Bookstore</Address>
      <Address>34 Fountain Square Plaza</Address>
      <Address>Cincinnati, OH 45202</Address>
   </From>
   <To>
      <Address>Que</Address>
      <Address>201 West 103RD Street</Address>
      <Address>Indianapolis, IN 46290</Address>
   </To>
   <List>
      <Book>
         <ISBN>0789722429</ISBN>
         <Quantity>5</Quantity>
      </Book>
      <Book>
         <ISBN>0789724308</ISBN>
         <Quantity>3</Quantity>
      </Book>
   </List>
</PurchaseOrder>

Listing 1: A purchase order in XML.

Yet, even though the ISBN is efficient, people find titles friendlier; so if we were to write an XSLT stylesheet to transform Listing 1 in HTML, it would be logical to print the titles next to the ISBN. How so? Well, there are so many books in print that the only option is to lookup the titles in an ISBN database.

Wait, how do you query a database from XSLT? There is no JDBC equivalent! Again XSLT does 90% of what we need (converting XML to HTML), but it lacks the final 10% (querying the database). Fortunately, we can work around this limitation with some Java coding.

XSLT Extensions

Wisely, the W3C built an extension mechanism into XSLT. It allows the programmer to define new functions and new elements. Unfortunately, the W3C did not completely specify the extension mechanism. Therefore, vendors have implemented extensions differently. This article was tested with Xalan 1.0 (the Apache XSLT processor, available from xml.apache.com), you will find that other XSL processors differ slightly in their implementation.

As a Java programmer, it is not difficult to write a function to query a relational database. However, for simplicity, I won't use a real database but a hashtable. A hashtable is enough to demonstrate the extension, but it is simpler to write.

Listing 2 is the code for the extension in Java. It creates a new XSLT element

(put)
and a new XSLT function
(get)
.


package com.psol.xslxt;

import java.util.Hashtable;
import org.apache.xalan.xslt.*;

public class Dictionary
{
   protected Hashtable hashtable = new Hashtable();

   public Dictionary()
      {}

   public void put(XSLProcessorContext context, 
                   ElemExtensionCall extElem)
   {
      String key = extElem.getAttribute("key"),
             value = extElem.getAttribute("value");
      hashtable.put(key,value);
   }   

   public String get(String key)
   {
      String value = (String)hashtable.get(key);
      return null != value ? value : "";
   }
}

Listing 2: Dictionary.java.

Xalan calls this class when it encounters the

put
element or the
get
function in a style sheet. The
put()
method takes two parameters: a pointer to context information and a pointer to the extension element. Using the latter, the method retrieves the element's attribute and populates the hashtable.

As for the

get()
method, it is a straightforward Java method, but its signature must match the signature of the XSLT function. It looks up a value in the hashtable and returns the result.

Listing 3 is an XSLT stylesheet that demonstrates how to call the Dictionary. If you are new to XSLT, don't panic. The stylesheet is only one template long (

xsl:template
), and it is a straightforward one. The template is HTML code mixed with XSLT elements (
xsl:value-of
,
xsl:for-each
) to extract data from the source XML document.


<?xml version="1.0"  encoding="ISO-8859-1"?>

<xsl:stylesheet
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:axslt="http://xml.apache.org/xslt"
   xmlns:psol="http://www.psol.com/java/xslxt"
   extension-element-prefixes="psol"
   version="1.0">

<axslt:component prefix="psol"
                 functions="get"
                 elements="put">
   <axslt:script lang="javaclass"
                 src="com.psol.xslxt.Dictionary"/>
</axslt:component>

<xsl:output method="html"/>

<xsl:template match="/">

<psol:put key="0789722429"
          value="XML by Example"/>
<psol:put key="0789724308"
          value="Developing XML Solutions"/>

<HTML>
   <HEAD><TITLE>Purchase Order</TITLE></HEAD><BODY>
   <H1>Purchase Order</H1>
   <TABLE BORDER="1">
      <TR><TD>From</TD><TD>To</TD></TR>
      <TR><TD><xsl:for-each
         select="PurchaseOrder/From/Address">
         <xsl:value-of select="."/><BR/>
      </xsl:for-each></TD>
      <TD><xsl:for-each
         select="PurchaseOrder/To/Address">
         <xsl:value-of select="."/><BR/>
      </xsl:for-each></TD></TR>
   </TABLE>
   <TABLE BORDER="1">
      <TR><TD>ISBN</TD><TD>Title</TD>
         <TD>Quantity</TD></TR>
      <xsl:for-each
         select="PurchaseOrder/List/Book">
         <xsl:variable name="isbn"
                       select="ISBN"/>
         <TR><TD><xsl:value-of
            select="$isbn"/></TD>
         <TD><xsl:value-of
            select="psol:get(string($isbn))"/></TD>
         <TD ALIGN="RIGHT"><xsl:value-of
            select="Quantity"/></TD>
         </TR>
      </xsl:for-each>
   </TABLE>
</BODY></HTML>

</xsl:template>

</xsl:stylesheet>

Listing 3: The XSLT Stylesheet.

Let's review the stylesheet step by step:

  • The style sheet declares an extra namespace (http://www.psol.com/java/xslxt associated with the psol prefix) for the extensions.
  • It further declares psol as an extension-element-prefix.
  • Next, it links to the implementation using the
    axslt:component
    and
    axslt:script
    elements. Unlike extension-element-prefixes,
    axslt:component
    and
    axslt:script
    are specific to Xalan (as their namespace indicates). They declare the new element and function and associate them with a Java class. Xalan uses the Bean Scripting Framework to load the extensions, so you could also write in JavaScript, JPython, Tcl, Perl or other BSF-compliant languages.
  • The style sheet calls
    psol:put
    and
    psol:get()
    . Note the use of the
    string()
    function to convert the parameter from a DOM Node to a string, so the function call matches the signature of the Java method. Also worth noting is the use of the psol prefix to differentiate extension elements and functions from standard ones.

Running the Example

You need Xalan 1.0.0, Xerces 1.0.2, and the Bean Scripting Framework in your classpath to run this example. You can download them from the xml.apache.org Web site. Alternatively, you can download a snapshot of this project from my own site.

Conclusion

As interest for XML continues to grow, XSLT becomes a powerful addition to your Java toolbox. XSLT does only one thing (transforming XML documents), but it does it well. However, since we can extend XSLT with new elements and functions written in Java, its applications are limitless.

For example, you could write XSLT extensions to query a database, perform heavy-duty calculation, issue RMI requests, or simply communicate between the stylesheet and a user interface.

About the Author

Benoît Marchal is a software engineer and writer who has been working extensively in Java and XML. He is the author of the book XML by Example and has his own business, Pineapplesoft, in Namur, Belgium. He is currently working on a new XML book.






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel