Home arrow XML arrow Page 4 - XSL Transformation With Xalan

The Anatomy Of A Transformation - XML

If you've been following along, you already know how to parse XML documents using both SAX and the DOM with the Java-based Xerces XML parser. But why stop there? In this article, take your Java/XML skills to the next level by converting your XML into other formats with the very powerful Xalan XSLT engine

TABLE OF CONTENTS:
  1. XSL Transformation With Xalan
  2. The Introductions
  3. Meeting The World's Greatest Detective
  4. The Anatomy Of A Transformation
  5. The Write Stuff
  6. Still Hungry?
By: icarus, (c) Melonfire
Rating: starstarstarstarstar / 7
March 20, 2002

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement
As always with Java, the first step involves pulling all the required classes into the application.

// import required classes import javax.xml.transform.*; import javax.xml.transform.stream.*; import java.io.*;
In case you're wondering, first come the classes for JAXP, followed by the classes for exception handling and file I/O. Now, I bet you're wondering, what's JAXP? According to the Unofficial JAXP FAQ, available at http://xml.apache.org/~edwingo/jaxp-faq.html, the Java API for XML Processing (JAXP) "enables applications to parse and transform XML documents using an API that is independent of a particular XML processor implementation". Or, to put it very simply, JAXP provides an abstraction layer, or standard API, that allows for code reuse across different XSLT processors. You might be wondering how JAXP, as an abstraction layer, knows which class to use during the transformation process. This information is available via the javax.xml.transform.TransformerFactory property. In case this didn't make any sense to you, don't worry about it; if it did, and you want to know more, take a look at http://xml.apache.org/xalan-j/apidocs/javax/xml/transform/TransformerFactory.html Next, I've instantiated some variables to hold the names of the various files I'll be using in the application.

// store the names of the files public static String xmlFile, xslFile, resultFile = "";
And now for the constructor:

// constructor public addressBookConverter(String xmlFile, String xslFile, String resultFile) { try { // create an instance of the TransformerFactory // this allows the developer to use an API that is independent of // a particular XML processor implementation. TransformerFactory tFactory = TransformerFactory.newInstance(); // create a transformer which takes the name of the stylesheet // as an input parameter Transformer transformer = tFactory.newTransformer(new StreamSource(xslFile)); // transform the given XML file transformer.transform(new StreamSource(xmlFile), new StreamResult(resultFile)); System.out.println("Done!"); } catch (TransformerException e) { System.err.println("The following error occured: " + e); } }
The first step is to create an instance of the TransformerFactory class. This can be used to create a Transformer object, which reads the XSLT stylesheet and converts the templates within it into a Templates object. This Templates object is a dynamic representation of the instructions present in the XSLT file - you won't see any reference to it in the code above, because it all happens under the hood, but trust me, it exists.

Once the stylesheet is processed, a new Transformer object is generated. This Transformer object does the hard work of applying the templates within the Templates object to the XML data to produce a new result tree, via its transform() method. The result tree is stored in the specified output file.

Finally, the main() method sets the ball in motion:

// everything starts here public static void main (String[] args) { if(args.length != 3) { System.err.println("Please specify three parameters:n1. The name and path to the XML file.n2. The name and path to the XSL file.n3. The name of the output file."); return; } // assign the parameters passed as input parameters to // the variables defined above xmlFile = args[0]; xslFile = args[1]; resultFile = args[2]; addressBookConverter myFirstExample = new addressBookConverter (xmlFile, xslFile, resultFile); }
This method first checks to see if the correct number of arguments was passed. If so, it invokes the constructor to create an instance of the addressBookConverter class; if not, it displays an appropriate error message.{mospagebreak title=Six Degrees Of Separation} Let's move on to something a little more complicated. Let's suppose that I wanted to convert my address book from XML into a delimiter-separated ASCII file format, for easy import into another application. With XSLT and Xalan, the process is a snap.

Here's the XML data:

<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="/home/me/xsl/xml2csv.xsl"?> <addressbook> <item> <name>Bugs Bunny</name> <address>The Rabbit Hole, The Field behind Your House</address> <email>bugs@bunnyplanet.com</email> </item> <item> <name>Batman</name> <address>The Batcave, Gotham City</address> <tel>123 7654</tel> <url>http://www.belfry.net/</url> <email>bruce@gotham-millionaires.com</email> </item> </addressbook>
Now, in order to convert this XML document into a delimiter-separated file, I need an XSLT stylesheet like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/> <!- Set the "|" symbol as the default delimiter <xsl:param name="delimiter" select="normalize-space('|')"/> <xsl:template match="/addressbook"> <xsl:for-each select="item"> <xsl:value-of select="normalize-space(name)"/> <xsl:value-of select="$delimiter"/> <xsl:value-of select="normalize-space(address)"/> <xsl:value-of select="$delimiter"/> <xsl:value-of select="normalize-space(tel)"/> <xsl:value-of select="$delimiter"/> <xsl:value-of select="normalize-space(email)"/> <xsl:value-of select="$delimiter"/> <xsl:value-of select="normalize-space(url)"/> <!- hexadecimal value for the new-line character <xsl:text>&#x0A;</xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
And here's the Java code to tie it all together:

// imported java classes import javax.xml.transform.*; import javax.xml.transform.stream.*; import java.io.*; public class xml2csv { // store the names of the files public static String xmlFile, xslFile, resultFile,delimiterValue = ""; // parameters for the getAssociatedStylesheet() method of the TransformerFactory class // Set them to null as they are not essential here String media = null , title = null, charset = null; public xml2csv(String xmlFile, String resultFile, String delimiterValue) { try { // create an instance of the TransformerFactory class TransformerFactory tFactory = TransformerFactory.newInstance(); // get the name of the stylesheet that has been defined in the XML file. // create a Source object for use by the upcoming newTransformer() method Source stylesheet = tFactory.getAssociatedStylesheet (new StreamSource(xmlFile),media, title, charset); // create a transformer which takes the name of the stylesheet // as an input parameter Transformer transformer = tFactory.newTransformer(stylesheet); // set a delimiter via the setParameter() method of the transformer transformer.setParameter("delimiter",delimiterValue); // perform the transformation transformer.transform(new StreamSource(xmlFile), new StreamResult(resultFile)); System.out.println("Done!"); } catch (TransformerException e) { System.err.println("The following error occured: " + e); } } // everything starts here public static void main (String[] args) { if(args.length != 3) { System.err.println("Please specify three parameters:n1. The name and path to the XML file.n2. The name of the output file.n3. The delimiter to be used."); return; } // set some variables xmlFile = args[0]; resultFile = args[1]; delimiterValue = args[2]; xml2csv mySecondExample = new xml2csv(xmlFile, resultFile, delimiterValue); } }


Most of the code is identical to the previous example. There are a couple of important differences, though. First, the parameters passed to the constructor are different in this case.

public xml2csv(String xmlFile, String resultFile, String delimiterValue) { // snip }
Over here, I'm passing three parameters to the constructor: the name of the XML file, the name of the output file, and the delimiter to be used between the various elements of a record. What about the XSLT file, you ask? Well, that's sourced automatically from the XML file via the getAssociatedStylesheet() method of the TransformerFactory class.

// create an instance of the TransformerFactory class TransformerFactory tFactory = TransformerFactory.newInstance(); // get the name of the stylesheet that has been defined in the XML file. // create a Source object for use by the upcoming newTransformer() method Source stylesheet = tFactory.getAssociatedStylesheet (new StreamSource(xmlFile),media, title, charset); [/code]

A new Source object is created to represent this stylesheet; this Source object is ultimately passed to the Transformer class.

// create a transformer which takes the name of the stylesheet // as an input parameter Transformer transformer = tFactory.newTransformer(stylesheet);
If you take a close look at the XSLT file above, you'll see that I'vedefined an XSLT parameter named "delimiter". This parameter isessentially a variable which can be accessed by XSLT, and a value can beassigned to it via the setParameter() method of the Transformer class.

// set a delimiter via the setParameter() method of the transformer transformer.setParameter("delimiter",delimiterValue);
In this case, the "delimiter" parameter is set to whatever delimiter wasspecified by the user.

Finally, the actual transformation is performed, the output stored inthe desired output file, and a result code generated.[code]// perform the transformation transformer.transform(new StreamSource(xmlFile), newStreamResult(resultFile)); System.out.println("Done!");
Here's what it looks like, assuming you use a pipe (|) as delimiter (I haven't used a comma simply because some of the entries already contain commas):

Bugs Bunny|The Rabbit Hole, The Field behind Your House||bugs@bunnyplanet.com| Batman|The Batcave, Gotham City|123 7654|bruce@gotham-millionaires.com|http://www.belfry.net/
Isn't it simple when you know how?

 
 
>>> More XML Articles          >>> More By icarus, (c) Melonfire
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

XML ARTICLES

- Google Docs and Xpath Data Functions
- Flex Array Collection Sort and Filtering
- The Flex Tree Control
- Flex List Controls
- Working with Flex and Datagrids
- How to Set Up Podcasting and Vodcasting
- Creating an RSS Reader Application
- Building an RSS File
- An Introduction to XUL Part 6
- An Introduction to XUL Part 5
- An Introduction to XUL Part 4
- An Introduction to XUL Part 3
- An Introduction to XUL Part 2
- An Introduction to XUL Part 1
- XML Matters: Practical XML Data Design and M...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: