Team lead for the TopLink/EclipseLink JAXB & SDO implementations, and the Oracle representative on those specifications. Blaise is a DZone MVB and is not an employee of DZone and has posted 44 posts at DZone. You can read more from them at their website. View Full User Profile

Using JAXB With XSLT to Produce HTML

11.21.2012
| 10665 views |
  • submit to reddit

JAXB (JSR-222)enables Java to treat a domain model as XML.  In this post I will demonstrate how to leverage this by applying an XSLT stylesheet to a JAXB model to produce HTML.  This approach is often leveraged when creating JAX-RS applications.

Java Model

Below is the Java model that will be used for this example.  It represents information about a collection of books.

Library

package blog.jaxbsource.xslt;
 
import java.util.*;
import javax.xml.bind.annotation.*;
 
@XmlRootElement
public class Library {
 
    private List<Book> books = new ArrayList<Book>();
 
    @XmlElement(name="book")
    public List<Book> getBooks() {
        return books;
    }
 
}

Book

package blog.jaxbsource.xslt;
 
public class Book {
 
    private String title;
    private String author;
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    public String getAuthor() {
        return author;
    }
 
    public void setAuthor(String author) {
        this.author = author;
    }
 
}


XML Structure 
Our JAXB model can be used to produce XML documents that conform to the following XML schema.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
 <xs:element name="library" type="library" />
 
 <xs:complexType name="library">
  <xs:sequence>
   <xs:element name="book" type="book" minOccurs="0"
    maxOccurs="unbounded" />
  </xs:sequence>
 </xs:complexType>
 
 <xs:complexType name="book">
  <xs:sequence>
   <xs:element name="author" type="xs:string" minOccurs="0" />
   <xs:element name="title" type="xs:string" minOccurs="0" />
  </xs:sequence>
 </xs:complexType>
 
</xs:schema>

The above XML schema was produced using the following code.

package blog.jaxbsource.xslt;
 
import java.io.IOException;
import javax.xml.bind.*;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
 
public class GenSchema {
 
    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Library.class);
         
        jc.generateSchema(new SchemaOutputResolver() {
 
            @Override
            public Result createOutput(String namespaceURI, String suggestedFileName)
                    throws IOException {
                StreamResult result = new StreamResult(System.out);
                result.setSystemId(suggestedFileName);
                return result;
            }
             
        });
    }
 
}


Stylesheet
Below is the XSLT stylesheet that we will use to convert the XML (JAXB model) to HTML.

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:template match="/">
  <html>
   <body>
    <h2>My Library</h2>
    <table>
     <tr>
      <th>Title</th>
      <th>Author</th>
     </tr>
     <xsl:for-each select="library/book">
      <tr>
       <td>
        <xsl:value-of select="title" />
       </td>
       <td>
        <xsl:value-of select="author" />
       </td>
      </tr>
     </xsl:for-each>
    </table>
   </body>
  </html>
 </xsl:template>
</xsl:stylesheet>
Demo Code
In our demo code we will use the standard javax.xml.transform APIs to do the conversion. Our JAXB input is wrapped in an instance of JAXBSource, and the output is wrapped in an instance of StreamResult.
package blog.jaxbsource.xslt;
 
import javax.xml.bind.*;
import javax.xml.bind.util.JAXBSource;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
 
public class Demo {
 
    public static void main(String[] args) throws Exception {
        // XML Data
        Book book1 = new Book();
        book1.setAuthor("Jane Doe");
        book1.setTitle("Some Book");
 
        Book book2 = new Book();
        book2.setAuthor("John Smith");
        book2.setTitle("Another Novel");
         
        Library catalog = new Library();
        catalog.getBooks().add(book1);
        catalog.getBooks().add(book2);
 
        // Create Transformer
        TransformerFactory tf = TransformerFactory.newInstance();
        StreamSource xslt = new StreamSource(
                "src/blog/jaxbsource/xslt/stylesheet.xsl");
        Transformer transformer = tf.newTransformer(xslt);
 
        // Source
        JAXBContext jc = JAXBContext.newInstance(Library.class);
        JAXBSource source = new JAXBSource(jc, catalog);
 
        // Result
        StreamResult result = new StreamResult(System.out);
         
        // Transform
        transformer.transform(source, result);
    }
 
}

Output 
The following HTML output was produced as a result of running the demo code.
<?xml version="1.0" encoding="UTF-8"?>
<html>
 <body>
  <h2>My Library</h2>
  <table>
   <tr>
    <th>Title</th>
    <th>Author</th>
   </tr>
   <tr>
    <td>Some Book</td>
    <td>Jane Doe</td>
   </tr>
   <tr>
    <td>Another Novel</td>
    <td>John Smith</td>
   </tr>
  </table>
 </body>
</html>




Published at DZone with permission of Blaise Doughan, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Lance Semmens replied on Wed, 2012/11/21 - 5:09am

 I urge anyone considering an XSLT solution to first consider Freemarker instead. The benefits include:

  • XSLT templates are very verbose, freemarker templates are much more concise
  • In freemarker, you can inject helper java objects into the context
  • Custom freemarker tags are easy to write
  • Localization is far more easy to implement in freemarker than XSLT
  • Freemarker templates are far more readable and maintainable than XSLT
  • Whilst freemarker has excellent support for XML inputs, it can support imputs of any type including POJOs.
  • Formatting dates and strings is simple and concise

http://freemarker.sourceforge.net/docs/xgui_imperative_learn.html

http://freemarker.sourceforge.net/docs/ref_builtins_string.html

http://freemarker.sourceforge.net/docs/ref_builtins_date.html



Xavier Dury replied on Wed, 2012/11/21 - 9:07am

I'm using the same method to generate invoices in FOP (PDF), it works really well.

David Heinecke replied on Wed, 2012/11/21 - 9:30pm

I'll play the part of the grey-beard developer here: why not just use JSP?

Blaise Doughan replied on Thu, 2012/11/22 - 6:12am in response to: David Heinecke

The key point to this post is that an XSLT transform can be applied to a Java model annotated with JAXB (JSR-222) annotations.  One reason HTML was used as the result as the document would be sufficiently different from the source.  The other reason is that this is a common use case in the creation of JAX-RS (JSR-311) services that return HTML.


Lund Wolfe replied on Thu, 2012/11/22 - 5:35pm

I agree that FreeMarker templates are much better for generating html pages from Java.  I've seen XSLT used for web page generation in old web apps and it's very ugly.

I also have a strong dislike of XML/XSLT programming, but there are times when you need to produce a very complex XML standard format from your simple Java/XML format, as Blaise says, and XSLT serves that purpose very well.  I prefer to separate the Java to XML and XML to complex XML stages, though, to help debug which stage isn't working as expected.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.