JAXP and XSLT
Now let’s up the ante a bit. Instead of hard-coding a response to a web request, we’ll trigger the execution of XSLT. To accomplish this goal, we need to dip into the Java API for XML (JAXP). Built into the Java SDK, JAXP contains classes for parsing XML and for executing XSLT transforms. In step 4 on our path to XML mastery, we’ll look at some options for parsing XML with JAXP, but right now we’ll start with a quick review of JAXP’s powerful XSLT component.
JAXP provides the capability to create a Java object that executes a specific XSLT transformation. All the templates and pattern-matching specified in the XSLT are translated into a Java algorithm that executes the transform process efficiently. Once created, the Java object executes the same transform against whatever XML is fed to it as input (see Figure 2).
Figure 2 Standalone vs. Java servlet transform using JAXP’s factory pattern.
Listing 2 shows the doGet method for a servlet that will enable our XSLT transform on the server.
Listing 2 A servlet doGet method that will execute an XSLT transform using JAXP’s TransformerFactory.
1. public void doGet (HttpServletRequest request, 2. HttpServletResponse response) 3. throws ServletException, IOException, 4. java.net.MalformedURLException { 5. 6. // Tell the response object that our servlet returns HTML 7. response.setContentType("text/html; charset=UTF-8"); 8. 9. // Ask for a response stream 10. PrintWriter out = response.getWriter(); 11. 12. // This block tries to open our XML and XSLT files 13. // which may throw an exception, thus the try..catch 14. try { 15. // Get a empty transform factory (factory pattern) 16. TransformerFactory tFactory = TransformerFactory.newInstance(); 17. 18. // Get the actual server path for XML and XSLT files 19. String loc = getServletContext().getRealPath("") + "/"; 20. 21. // Get the XML input document and the stylesheet using 22. // the string loc that holds the path information, 23. // creating a JAXP Source instance 24. Source xmlSource = new StreamSource( 25. new URL("file", "", loc + "zbBooks.xml").openStream()); 26. 27. Source xslSource = new StreamSource( 28. new URL("file", "", loc + "zbBookListGen.xslt").openStream()); 29. 30. // Generate the transformer 31. Transformer transformer = tFactory.newTransformer(xslSource); 32. 33. // GRAND FINALE! 34. // Perform the transformation, send output to the browser 35. transformer.transform(xmlSource, new StreamResult(out)); 36. 37. } 38. catch (Exception e) 39. { 40. out.write(e.getMessage()); 41. e.printStackTrace(out); 42. } 43. out.close(); 44. }
Our doGet method to execute our XSLT is not much more complicated than our simple HelloWorldServlet in Listing 1. The key concepts here:
- Line 16: Uses JAXP’s TransformerFactory for a new factory instance that we can customize based on our XSLT.
- Line 19: Asks the servlet context to tell us where our servlet files live on the server. Because servlets are deployed for us, we can’t know in advance exactly where any files we want access to will be located. The variable loc holds the complete path, to which we append our XML and XSLT filenames.
- Lines 24–28: Sets up two StreamSources for our XML and XSLT. A StreamSource is a JAXP abstraction that hides details of whether the XML appears as a file or some other form, such as a DOM tree.
- Line 31: Turns our factory from an empty shell to one that will process XML based on the rules in our XSLT file.
- Line 35: One line now does it all! We feed the XML to our factory and pass the HTML output to the stream connected to the browser.
The reason the servlet code is so simple is that XSLT is doing all the heavy lifting. More comfortable with PHP, Perl, or .NET? The code will be equally as simple in those languages. Because XSLT represents a different programming paradigm from conventional languages, it’s often misunderstood by programmers who find the XML rule-based syntax different from what they’re accustomed to. What’s important is to see how XSLT can be used as a weapon in your development arsenal.