Using XSLT to Fix Swing
by Dave Horlick
|
Pages: 1, 2, 3
Further Changes to the Document Structure
Let's add one more workaround. This one will do some juggling to prevent Swing from rendering extraneous line breaks before named anchors that immediately follow other elements.
<?xml version="1.0" encoding="UTF-8"?> |
| source2.xhtml |
The new templates below should be added to the existing stylesheet file after the template that matches paragraphs, and before the ones that match everything.
<!-- workaround for JEditorPane's tendency to issue an
extraneous line break upon encountering a named anchor
According to the suggestion at
http://docs.sun.com/source/819-0913/release/limitations.html
The best way to work around this problem is to nest the text of the target
within the anchor tag. For example:
<H2><a name="widgets">Working With Widgets</a></H2>
-->
<xsl:template match="xhtml:a">
<xsl:variable name="next-node-name" select="name(following-sibling::*[1])" />
<xsl:choose>
<!-- If this is named and href-less, and the next element is a headline,
we want to shift that headline inside this -->
<xsl:when test="not(@href) and @name and string-length($next-node-name)=2
and substring($next-node-name,1,1)='h'">
<xsl:element name="a">
<xsl:apply-templates select="@*|node()|following-sibling::*[1]">
<xsl:with-param name="shifted">yes</xsl:with-param>
</xsl:apply-templates>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="a">
<xsl:apply-templates select="@*|node()" />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="xhtml:h1|xhtml:h2|xhtml:h3|xhtml:h4|xhtml:h5|xhtml:h6">
<xsl:param name="shifted">no</xsl:param>
<xsl:variable name="previous-node-name" select="name(preceding-sibling::*[1])" />
<xsl:if test="$shifted='yes' or $previous-node-name!='a'
or preceding-sibling::*[1]/@href or not(preceding-sibling::*[1]/@name)">
<xsl:element name="{local-name()}">
<xsl:apply-templates />
</xsl:element>
</xsl:if>
</xsl:template>
The first new template will shift headlines inside named anchors. The second template will transcribe any unshifted headlines that are encountered. But it will refrain from re-outputting shifted headlines when iterating past their original locations in the source document.
The completed stylesheet will produce documents that are much better able to weather the transition from your favorite web browser to Swing.
Coordination
These XSLT revisions can be applied at runtime via the javax.xml.transform.Transformer class and what is sometimes referred to as the TrAX API.
Transformer autobot
= TransformerFactory.newInstance().newTransformer(
new StreamSource(
ClassLoader.getSystemResourceAsStream("xsl/xhtml2swing.xsl"));
autobot.transform(new StreamSource(
ClassLoader.getSystemResourceAsStream("resources/source.xhtml"),
new StreamResult(outputStream));
outputStream.flush();
Alternately, you could generate HTML at compile time, and package it up with your distribution. The Ant target for this might look like
<target name="dist" depends="compile">
<style in="${dist.docs.dir}/source.xhtml" style="${scripts.dir}/xhtml2swinghtml.xsl"
processor="trax" out="${resources.dir}/content.html" force="true" />
<jar jarfile="${dist.purejava.dir}/${ant.project.name}">
<fileset dir="${classes.dir}" />
<fileset dir="${resources.dir}" />
</jar>
</target>
Then, you would read the modified document from a resource stream with the following Java code
JEditorPane jEditorPane = new JEditorPane();
URL docURL = ClassLoader.getSystemResource("resources/content.html");
jEditorPane.setPage(docURL);
If you enlist TagSoup's parser (org.ccil.cowan.tagsoup.Parser), you could even cut out the step of generating XHTML files and process raw HTML directly.
Future Directions
Using these techniques, you should be able to accommodate the rendering limitations of any HTML renderer, not just Swing's.
Once you get comfortable with XSLT, you may want to use it upstream from HTML to spruce up your content model. If you start with a more conceptual document format such as DocBook XML (not to be confused with DocBook SGML) or poorly named Extensible Stylesheets Language Format Objects (XSL-FO), then XHTML can become just another output format alongside PDF, RTF, and JavaHelp.
You can write the stylesheets to accomplish this yourself, or appeal to DocBook XSL (not to be confused with DocBook DSSL) and Apache Forms Object Processor (FOP).
You might also want to experiment with other XSLT implementations. In particular, Saxon supports the XSLT 2.0 specification, which includes many improvements such as more flexible grouping and standardized data-type conversions.
- Tagsoup
2006-08-03 03:05:01 Kit Davies