XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.


Using XSLT to Fix Swing

August 02, 2006

Swing is a Java framework for building cross-platform graphical user interfaces. Many areas of the framework have recently enjoyed some compelling improvements. The portion that renders HTML hasn't been so lucky. When Swing debuted, HTML was at a youthful version 3.2, and practices such as nestling paragraphs within tags could still be considered newfangled. Today, they are familiar if not mandatory, and it's easy to consider it a bug when Swing inserts an unrequested line break between a formally declared paragraph and its preceding headline.

One solution is to abandon Swing's HTML Renderer and JEditorPane in favor of another renderer, such as the javadesktop Flying Saucer project or a native HTML browser. This approach won't help if you are working with frameworks such as JavaHelp, which is hardwired to use Swing's renderer.

Luckily, there's a straightforward solution involving XSLT.

Screenshot of a JEditorPane incorrectly displaying HTML with an extra line break

Screenshot of a JEditorPane incorrectly displaying HTML with an extra line break

Extensible Stylesheet Language Templates

XSLT (eXtensible Stylesheet Language Templates) is origami for XML. XSLT can easily fold one kind of XML document into any other kind you can dream up. It accomplishes this by matching a set of templates to patterns of varying specificity and position in a target XML document. These templates introduce new patterns into an output document, constructed from information found in the target. This lends itself to very subtle and recursive use.

Conveniently for us, Java has had XSLT built-in since J2SE 1.4.

We'll need to format our HTML data as XHTML. XHTML is a flavor of XML and accordingly, is susceptible to the wiles of XSLT.

line 1<br>
line 2<br>
line 3
<h3>my headline</h3>
<p>my paragraph</p>
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
line 1<br/>
line 2<br/>
line 3
<h3>my headline</h3>
<p>my paragraph</p>
source.html source.xhtml

As you can see, the only significant differences here are the XML header and the self-closing tags. If your source HTML has validity problems or you're just lazy, TagSoup is an excellent tool for automating the process.

Using XSLT, we can convert our original XHTML document into an HTML 3.2 representation that will look good in Swing's HTML renderer.

The Identity Transform

We'll start with an identity transform that will more or less faithfully reproduce the structure of our original document.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  <xsl:output method="html" version="3.2" />
  <xsl:strip-space elements="*" />
  <xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="@*|node()"/>
  <xsl:template match="@*">
    <xsl:attribute name="{local-name()}">
      <xsl:value-of select="."/>

The html method attribute in the xsl:output tag will prompt empty output tags to refrain from closing themselves. That's important, because the practice confounds Swing's HTML Renderer.

The * wildcard character in the match attribute of the first template will pull in a source element. Initially, this will be the source document root. The stylesheet will copy the matched element to the output document. Finally, the template will start over with another element or will release control to the next template for processing child attributes.

The @* character sequence in the second template's match attribute will target a source attribute. The stylesheet will copy the attribute into the output document.

In this manner, all elements and attributes will find their way over to the output document.

Save the stylesheet above to a file named identity.xsl. Pull up a command shell and type

java org.apache.xalan.xslt.Process -IN source.xhtml -XSL identity.xsl -OUT output.html

This should invoke a handy main method in Xalan, Java's default XSLT implementation. If you're using a JDK more recent than 1.4, you may need to download a fresh copy of Xalan and put it into your class path, because the more recent bundled versions seem to lack this interface on at least one platform.

Review the output file and verify that your basic document structure is unchanged. In fact, it should closely resemble the pre-XHTML version.

Pages: 1, 2, 3

Next Pagearrow