![]() |
Home | Articles | Talks | Links | Contact Me | ISA | ThoughtWorks |
A view that process domain data element by element and transforms it into HTML
When you issue requests for data to the domain and data source layers, you'll get back all the data you need to satisfy a request, but without the formatting you need to make a proper web page. The role of the view in Model View Controller is to render this data into a web page. Using Transform View means thinking of this as a transformation where you have the model's data as input and the HTML as output.
The basic notion of Transform View is to write a program that will look at domain oriented data and convert it to HTML. The program walks the structure of the domain data and as it recognizes each form of domain data it writes out the particular piece of HTML for that data. If you think about this in an imperative way you might have a method called renderCustomer
that takes a customer object and renders it into HTML. If the customer contains a bunch of orders, the renderCustomer
method would loop over the orders calling renderOrder
The key difference between Transform View and Template View is the way in which the view is organized. A Template View is organized around the output. A transform view is organized around separate transforms for each kind of input element. The transform is controlled by something like a simple loop that looks at each input element, finds the appropriate transform for that element, and then calls that transform on the input element. A typical Transform View's elements can be arranged in any order without affecting the resulting output.
You can write a Transform View in any language, however at the moment the dominant choice for writing Transform Views is XSLT. The interesting thing about this is that XSLT is a functional programming language, similar to Lisp, Scheme, Haskell and other languages that never quite made it into the IS mainstream. As such it has a different kind of structure to it. Rather than explicitly calling routines, the language recognizes elements in the domain data and then invokes the appropriate rendering transformations.
To carry out an XSLT transform we need to begin with some XML data. The simplest way this can happen is if the natural return type of the domain logic is either XML or something that is automatically transformable to XML. A good example of an automatic transform is a .NET object that can transform itself to XML. Failing that we need to produce the XML ourselves. A good way to do this is to populate a Data Transfer Object that can serialize itself into XML. That way the data can be assembled using a convenient api.In simpler cases a Transaction Script can return XML directly.
The XML that's fed into the transform does not need to be a string, unless a string form is needed to cross a communication line. It's usually quicker and easier to produce a DOM and hand that to the transform.
Once we have the XML we pass it to XSLT engine, increasingly these are available commercially. The logic for the transform is captured in an XSLT stylesheet which we also pass to the transformer. The transformer then applies the stylesheet to the input XML to yield the output HTML, which we can write directly to the HTTP response.
The choice between a Transform View and a Template View mostly comes down to which environment is preferable for the team working on the view software to use. The presence of tools is a key factor here. Increasingly there are HTML editors which you can use to write Template Views. Tools for XSLT are, at least so far, much less sophisticated. XSLT can also be an awkward language to master, due its functional programming style coupled with its awkward XML syntax.
One of the strengths of XSLT is its portability. It can be used with almost any web platform. You can use the same XSLT to transform XML created from J2EE or .NET. This can help putting a common HTML view onto data from different sources.
XSLT is also often easier if you are building a view on an XML document. Other environments usually require you to transform the XML document into an object, or indulge in walking the XML DOM, which is often complicated. XSLT fits naturally in an XML world.
Transform View avoids two of the biggest problems with Template View. It's easier to keep the transform focused only on rendering HTML, this avoids having too much other logic in the view. It's also easy to run the Transform View and capture the output for testing. This makes it easier to test the view and you don't need a web server to run the tests.
Transform View transforms directly from domain-oriented XML into HTML. If you need to change the overall appearance of a web site, this can lead to you having to change multiple transform programs. Using common transforms, such as you can do with XSLT includes, helps reduce this problem. Indeed it's much easier to call common transformations using Transform View than it is using Template View. If you need to make global changes easily, or support multiple appearances for the same data, you might consider Two Step View which uses a two stage process.
Setting up a simple transform involves preparing Java code to invoke the right stylesheet to form the response, and preparing the stylesheet to format the response. In these cases most of the response to a page is pretty generic, so it makes sense to use Front Controller. I'll only describe the command here, you should look at Front Controller to see how the command object fits in with the rest of the request response handling.
All the command object does is invoke the methods on the model to obtain an XML input document, then pass that XML document through the XML processor.
class AlbumCommand... public void process() { try { Album album = Album.findNamed(request.getParameter("name")); Assert.notNull(album); PrintWriter out = response.getWriter(); XsltProcessor processor = new SingleStepXsltProcessor("album.xsl"); out.print(processor.getTransformation(album.toXmlDocument())); } catch (Exception e) { throw new ApplicationException(e); } }
The XML document may look something like this
<album> <title>Zero Hour</title> <artist>Astor Piazzola</artist> <trackList> <track><title>Tanguedia III</title><time>4:39</time></track> <track><title>Milonga del Angel</title><time>6:30</time></track> <track><title>Concierto Para Quinteto</title><time>9:00</time></track> <track><title>Milonga Loca</title><time>3:05</time></track> <track><title>Michelangelo '70</title><time>2:50</time></track> <track><title>Contrabajisimo</title><time>10:18</time></track> <track><title>Mumuki</title><time>9:32</time></track> </trackList> </album>
The translation of the XML document is done by an XSLT program. Each template match matches a particular part of the XML and produces the appropriate HTML output for the page. In this case I've kept the formatting to a excessively simple level to just show the essentials. The following template clauses match the basic elements of the XML file.
<xsl:template match="album"> <HTML><BODY bgcolor="white"> <xsl:apply-templates/> </BODY></HTML> </xsl:template> <xsl:template match="album/title"> <h1><xsl:apply-templates/></h1> </xsl:template> <xsl:template match="artist"> <P><B>Artist: </B><xsl:apply-templates/></P> </xsl:template>
These template matches handle the table. The table here has alternating rows highlighted in different colors. This is a good example of something that isn't possible with Cascading Style Sheets but is reasonable to do with XML.
<xsl:template match="trackList"> <table><xsl:apply-templates/></table> </xsl:template> <xsl:template match="track"> <xsl:variable name="bgcolor"> <xsl:choose> <xsl:when test="(position() mod 2) = 1">linen</xsl:when> <xsl:otherwise>white</xsl:otherwise> </xsl:choose> </xsl:variable> <tr bgcolor="{$bgcolor}"><xsl:apply-templates/></tr> </xsl:template> <xsl:template match="track/title"> <td><xsl:apply-templates/></td> </xsl:template> <xsl:template match="track/time"> <td><xsl:apply-templates/></td> </xsl:template>
![]() | ![]() |