Satya Komatenini

Subscribe to Satya Komatenini: eMailAlertsEmail Alerts
Get Satya Komatenini: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Related Topics: Java EE Journal, XML Magazine, Java Developer Magazine

J2EE Journal: Article

Applying Java/XML/XSL Technology

Applying Java/XML/XSL Technology

In Part 1 of this article (XML-J, Vol. 2, issue 4) I discussed the motivation and desire to adapt XSL and JSP to transform the pervasive relational data to HTML.

In Part 2 I discuss a Java-centric design approach to converting relational data to an XML DOM and how Xalan can transform the XML DOM to HTML. In addition, I provide sample code for both Xerces and Xalan. I also demonstrate practical ways to use XSL to transform XML to HTML, and supply appropriate references.

Obtaining Relational Data as XML on the Fly

The design goals for converting relational data to XML in an HTML development environment are:

  1. Optimize XML structure for page design.
  2. Conversion to XML is efficient and less memory-intensive.
  3. Allow for multiple databases.
  4. Allow for multiple data sources, including Java objects, session beans, SQL, and stored procedures.
  5. Should be conducive to multiple transformations (XSL, JSP, Taglibs).
The data needs for an HTML page can be represented by a treelike data structure, which is represented by a Java interface called IpageData. The suggested implementation of this Java interface is expected to consolidate page-level data from the coming URL, the current user session, and application-level constants, and also data from any additional data sources such as relational and Java objects.

If there's a way to gather data from multiple data sources into an IPageData interface, it would be fairly easy to convert IPageData into an XML DOM. I'm going to present an implementation for an IPageData interface called PageDataImplementation that allows for the composition of data from SQL and stored procedures. Then I'll present the Xerces API to convert the IPageData to DOM.

Declarative Design via a Properties File

Since IPageData is an interface, the design intends to allow for an alternative implementation in the future. In that spirit, the implementation class is loaded at runtime from a properties file. The following specification indicates this intent:

Request.ShowBooksPageData.className=
com.ai.PageDataImplementation

This line tells us that if someone were to request a data object represented by "ShowBooksPageData", a Java object of type IPageData will be returned. In this case the implementation was provided by the "PageDataImplementation" class.

This theme of specifying class names in properties files shows up again and again in this article. For those of you familiar with Factory and Strategy patterns, this shouldn't be a surprise. The idea is to provide variations in the implementation.

Listing 1 provides an example of how the PageDataImplementation makes use of the properties file to retrieve the needed key/value pairs and any loop-related data.

PageDataImplementation uses the first section for retrieving the key/value pairs (called MainData from now on) and the second section for retrieving the loop data. Key/value pairs correspond to the entry fields, text substitutions, and more. Loop data is responsible for tables, select boxes, and more. Refer to the sample XML book data presented earlier for an idea of the differences between loops and nonloops.

Back to the properties file - each section starts out with a Java class that's responsible for executing that section. "DBRequestExecutor" is a Java class that knows how to execute JDBC against a database and return a result set. This class can be replaced by any other class as long as it supports the idea of a collection as defined by the framework. In my case this interface is called IDataCollection.

Following the same theme, here's a section that allows for a stored procedure instead of a SQL:

#One of the loop definitions for an Oracle stored procedure
ShowBooksPageData.loop_authors.class
Name=OracleStoredProcedureExecutor
ShowBooksPageData.loop_authros.db=
<your_db>
ShowBooksPageData.loop_authors.stmt=\
Call pkg.sp_getAuthors(?,
{isbn.quote})
As you can see, the "DBRequestExecutor" is replaced with an OracleStoredProcedureExecutor. This is necessary because of the special treatment required to retrieve REFCURSORS in the case of Oracle stored procedures. This also demonstrates the flexibility of the design by allowing for custom section handlers.

Another key aspect of the design is how to pass the needed arguments to SQL and stored procedures. Arguments can be hard-coded when they're known, or they can be specified within "{}" for replacement. For example, {isbn} means look for a key called "isbn" and substitute the value in place of {isbn}. The key/value pairs could be coming from the URL, the session, a master config file, or a previously executed SQL statement. From practice, I can say this freedom is very convenient for developers. What about the ".quote" in {isbn.quote}? The ".quote" indicates that the value of "isbn" needs to be processed in a special way. A Java class defines this special behavior and that class is identified by a ".quote". This provision allows for such things as database nulls and database clauses such as "in". Typically, for a given database, one or two of these classes will do the job for the entire development team.

Calling Multiple Stored Procedures for Each Section

If the page has a set of key/value pairs that won't be satisfied by one data request, you'll have to call multiple requests. The output from each request is combined (or joined) for the final set of key/value pairs (see Listing 2).

A new Java section handler class called DBMultiRequestExecutor is used to accomplish this. The nature of this class is such that it will call multiple individual requests and consolidate their results. It also passes the output of the earlier requests to the later requests so they can make use of these parameters.

Support for Other Data Sources

As described, it's easy to plug in Java objects to this data-gathering framework. It's fairly easy to write wrappers for session beans that can be plugged into it. This allows for almost any data source that's accessible from Java to be declared as an XML data source.

Using Xerces to Convert Data Streams to an XML Stream

If you study the "transformToXML" function from the sample code, you'll see that converting IPageData to DOM is straightforward. Use any of the XML parsers to create an empty DOM document object and append a root node element to it. We'll be creating three kinds of XML nodes:

  1. Key/Value: Holds the key/value pairs
  2. Loop: Holds the rows
  3. Row: Holds a set of key/value pairs again, this time one for each column of that row
As you walk through the IPageData interfaces, these nodes are created and appropriately appended to the document.

An effort has been made to use only the DOM API, not the implementation-specific one. The only exception is the createDocument() function. In an ideal case this will be replaced by a factory method to create the implementation. Another alternative is to use the JAXP for this creation to mask the implementation (see Listing 3).

Using Xalan to Transform
the XML Stream to HTML

Let's now see how to pass the Document object to Xalan to transform it into an HTML stream (see Listing 4).

Xalan is designed in such a way that it's compatible with many XML parsers. This is achieved by writing adapters. One such adapter is the XercesLiaison. The same thing can be done for XML4J as well. These liaisons are needed to instantiate the XSLTProcessor.

In a similar fashion, XSLT allows multiple sources and multiple outputs by allowing an abstraction between the real sources and their interfaces. That's why the "process()" method is passing the real sources through their adapters.

At the completion of this function the print writer will have the transformed HTML file. The first input argument to "transform," namely "xslFilename", is the XSL template that's used to define this transformation. The content of this file is discussed next.

Coding Templatized XSL
to Transform XML to HTML

XSLT is an event-driven transformation engine. As the input is parsed, specified patterns are matched (similar to awk) and the code is executed to write to output streams. I call this the true transformation mode of XSLT. There's another nifty way to use XSLT, which I call the substitution mode. In this scheme only the root node is matched and XSLT is used only for substitutions and control logic. The benefit of this approach (when it's applicable) is that a designer can design the look and feel of a Web page using FrontPage, and XSLT will supply key/value substitutions and loop-based replications in that page. To demonstrate this here's a predesigned HTML sample that could be used as a template.

<html>
<p>Book ISBN {{isbn_goes_here}}
<p>Book Name {{name goes here}}
<p>List of Authors

<table>
<tr><td>{{first_name}}</td><td>{{last
name}}</td></tr>
..more rows go here
</table>

</body></html>

Using the template-based substitution approach the corresponding XSLT file would look like Listing 5.

The HTML template is transformed into an XSLT file almost one to one by replacing the squiggly braces with an XSLT substitution and the repeating table rows with an XSLT for a loop construct. The only XSLT tags we've used are "value-of" and "for-each". While the traditional transformation-based XSLT can be hard to write and maintain, the template-based approach is easy and doesn't alter the HTML structure.

It's this simplicity and separation of data from logic that makes this approach so appealing to both Java and non-Java programmers. With XSL you get all the Java control structures and also the needed data separation.

XSLT Gotchas When
Converting XML to HTML

The first and foremost is that your template HTML file has to be well formed with proper begin and end tags. Here are a few more things you'll run into as soon as you start using XSLT. This should save you some time if you're getting up to speed with XSLT.

Substitutions Within HTML Attributes

XSLT requires that the template document is a properly formed XML document. This puts some limitations on arbitrary substitutions. Using XSL you can't directly substitute into an HTML attribute element. Instead you need to add an attribute.

The following is an example of where you add an attribute to a <tr> element.

<TR>
<xsl:attribute
name="TITLE"><xsl:value-of
select="symbol"/>
is listed on the <xsl:value-of
select="@exchange"/>
stock exchange.</xsl:attribute>
<TD><xsl:value-of select=
"symbol"/></TD>
<TD><xsl:value-of
select="name"/></TD>
</TR>
The same thing can be done using JSP as follows: <tr title=<%=
pageData.getValue("Title") %>
<td>..</td>
<td>..</td>
</tr>

Including JavaScript

For embedding JavaScript in an XSL document you need to use XSL comment tags:

<xsl:comment>
// your script goes here
</xsl:comment>
You can use the CDATA section as well: <xsl:comment>
<![CDATA[
// your script goes here
]]>
</xsl:comment>
Another example: <script language="javascript">
<xsl:comment>
// your script goes here
</xsl:comment>
</script>
Large Data Streams

It's required that the entire DOM tree be built for XSL transformations. This means all loop data would have to materialize before the page drawing can take place. If the page decides not to paint depending on a key/value pair, we've unnecessarily retrieved data that was not going to be used.

Also, when a certain loop has thousands of rows, the resulting DOM tree can be too big for a Web environment as multiple users can quickly exhaust the memory. With the Java interface it's possible to extend the database cursors so it won't generate so much garbage, as one row is processed at a time and discarded. It's much harder to achieve the same level of efficiency with XML/XSL parsers at this time. As a result, JSP and taglibs certainly offer a much better alternative.

Writing Functions

There's some literature available on writing JavaScript functions that can access the XML nodes and do totals. At this time these facilities may be XSL processor-dependent.

Conclusion

Combining the elements we've discussed so far, it's possible to write servlet/ JSP/XML/XSL-based engines that will allow for multiple data sources and multiple data transformations. The abstractions introduced for the data-gathering mechanism completely eliminate any middle-tier Java coding (such as JavaBeans and data accessors). Programmers are much more productive in such an environment as they focus on the page design and the stored procedures. In an RDBMS environment this means your database developers can design a complete Web-based J2EE application without writing a single line of Java code and, at the same time, enjoy the portability of the J2EE platform.

Resources

  1. McLaughlin, B. (2000). Java and XML. O'Reilly. (A must-have for its coverage of SAX, DOM, XSL, JDOM, Cocoon, and Publishing.)
  2. Maruyama, H., Tamura, K., and Uramoto, N. (1999). XML and Java: Developing Web Applications. Addison-Wesley. Good coverage on XML4J and parsers.
  3. Harold, E.R. (1999). XML Bible. Hungry Minds, Inc. A good resource for XML and XSL.
Web Sites
  1. Coins: www.jxml.com
  2. JOX: www.wutka.com
  3. Koala: www-sop.inria.fr/koala/kbml/
  4. JDOM, XSP: www.jdom.org
  5. Aspire (a JSP/XSL/relational Web development framework): www.activeintellect.com/aspir
  6. JAXP, Java data binding: www.javasoft.com
  7. XSL documentation: www.microsoft.com(search for XSL)

More Stories By Satya Komatenini

Satya Komatineni is Chief Technology Officer of INDENT, Inc and the author of a Java based RAD framework for developing J2EE based HTML applications. The product has the distinction of supporting multiple html transformations (XSL,JSP, proprietary templates) while utilizing the same data abstraction to interact with EJBs, relational databases and ERP systems. After earning an M.S. in Electrical Engineering from Indian Institute of Technology, New Delhi, worked with LAN based collaboration technologies, C++ patterns and frameworks, Java and Web based frameworks in a distributed environment.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.