XML and the Model-View-Controller Pattern
When I refer to XML as a presentation technology, I am referring primarily to the view in an app using a Model-View-Controller (MVC) architecture. Model-View-Controller is a software architecture originally documented as a pattern for traditional client apps (like those created with Swing) but has been widely adopted as an architecture for web apps. In short, an MVC app separates an app into three main areas:
Model
-
The raw data and business rules of an app
View
-
The user-visible rendition of the model
Controller
-
Functionality that receives requests from users, interprets those requests, interacts with the model, and provides the view with any necessary model objects
In more concrete terms, an MVC web app written with Java servlets and JSPs could processes a request in four steps:
- A servlet (the controller) receives the request and parses it.
- The servlet calls some methods on a data access object (the model).
- The servlet passes model data objects to a JSP page for rendering.
- The JSP page outputs an HTML page including data from the model objects.
There are a number of Java web MVC frameworks available that provide much of the base code necessary in any web app. Popular examples include Apache Struts (http://struts.apache.org), Spring MVC (http://www.springframework.org), JavaServer Faces (http://java.oracle.com/javaee/javaserverfaces), and Tapestry (http://tapestry.apache.org).
XML in MVC Web apps
XML can be used in several places in an MVC web app. Most MVC frameworks make heavy use of XML for internal configuration. More interesting for our purposes is where XML is used to contain the data passed between the view and the controller. Instead of the controller passing one or more model objects to the view, the controller constructs an XML representation of the model objects and passes the XML document to the view. In some cases, your app is responsible for delivering XML; the "view" is simply serializing the XML document as the HTTP response. In others, the view is some form of server-side transformation from the controller-supplied XML to a different XML syntax or to HTML. In addition, the use of XML to transfer model data between the controller and the view allows us to move any necessary transformations from the server to users' client apps (usually web browsers). To start, let's simply create a servlet that produces an XML document. Example 13-1 contains a simple servlet that creates an XML document containing a list of tutorials. Our model is a List of Map objects. Once it has created a DOM Document object, the servlet outputs the document using the identity transformation technique discussed in .
Example Servlet generating XML document
package javaxml3.ch13; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Text; public class BookListXMLServlet extends HttpServlet { private DocumentBuilderFactory documentBuilderFactory; private TransformerFactory transformerFactory; public void init( ) { documentBuilderFactory = DocumentBuilderFactory.newInstance( ); transformerFactory = TransformerFactory.newInstance( ); } private Element newElementFromMap(Map map, String key, Document doc) { String text = (String) map.get(key); Text textNode = doc.createTextNode(text); Element element = doc.createElement(key); element.appendChild(textNode); return element; } protected void renderDocument(Document doc, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // tell the browser we're sending XML response.setContentType("text/xml"); // now do the identity transformation try { Transformer identity = transformerFactory.newTransformer( ); // our Result object is a StreamResult wrapping the // ServletOutputStream Result result = new StreamResult(response.getOutputStream( )); identity.transform(new DOMSource(doc), result); } catch (TransformerException e) { throw new ServletException( "Unable to perform identity transformation", e); } } protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List tutorialList = BookListFactory.INSTANCE; DocumentBuilder docBuilder = null; try { docBuilder = documentBuilderFactory.newDocumentBuilder( ); } catch (ParserConfigurationException e) { throw new ServletException( "Unable to create DocumentBuilderFactory", e); } // create the DOM document Document doc = docBuilder.newDocument( ); Element tutorials = doc.createElement("books"); doc.appendChild(books); for (Iterator it = tutorialList.iterator( ); it.hasNext( );) { Map tutorialMap = (Map) it.next( ); Element tutorial = doc.createElement("book"); tutorials.appendChild(book); tutorial.appendChild(newElementFromMap(bookMap, BookListConstants.TITLE, doc)); tutorial.appendChild(newElementFromMap(bookMap, BookListConstants.AUTHOR, doc)); tutorial.appendChild(newElementFromMap(bookMap, BookListConstants.PUBDATE, doc)); } renderDocument(doc, request, response); } } class BookListConstants { public static final String AUTHOR = "author"; public static final String PUBDATE = "pubdate"; public static final String TITLE = "title"; } class BookListFactory { public static final List INSTANCE; static { List templist = new ArrayList( ); Map m = new HashMap( ); m.put(BookListConstants.TITLE, "Ajax Hacks"); m.put(BookListConstants.AUTHOR, "Bruce W. Perry"); m.put(BookListConstants.PUBDATE, "March 2006"); templist.add(m); m = new HashMap( ); m.put(BookListConstants.TITLE, "LDAP System Administration"); m.put(BookListConstants.AUTHOR, "Gerald Carter"); m.put(BookListConstants.PUBDATE, "March 2003"); templist.add(m); m = new HashMap( ); m.put(BookListConstants.TITLE, "Java Servlet Programming"); m.put(BookListConstants.AUTHOR, "Jason Hunter"); m.put(BookListConstants.PUBDATE, "April 2001"); templist.add(m); INSTANCE = Collections.unmodifiableList(templist); } private BookListFactory( ) { } } |
Example 13-2 contains a web.xml servlet configuration file that maps this servlet to the path /booklist-xml.
Example Simple web.xml file
<?xml version="1.0" encoding="UTF-8"?> <web-app id="ch13-servlet" version="2.4" xmlns="http://java.oracle.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <display-name>ch13-servlet</display-name> <servlet> <servlet-name>BookListXMLServlet</servlet-name> <servlet-class>javaxml3.ch13.BookListXMLServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>BookListXMLServlet</servlet-name> <url-pattern>/booklist-xml</url-pattern> </servlet-mapping> </web-app> |
Once we've created a web app containing this servlet class and configuration file, we can view the results in a browser, as seen in .
XML output from a servlet

We didn't have to use a servlet to build this document. A page using JSP or another template language (such as Velocity) could build the same document. Instead of the servlet from Example 13-1, we could have a much simpler servlet such as Example 13-3 and then do the XML creation in a JSP such as the one seen in Example 13-4.
Example Much simpler tutorial list servlet
package javaxml3.ch13; import java.io.IOException; import java.util.List; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class BookListXMLJSPServlet extends HttpServlet { protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List tutorialList = BookListFactory.INSTANCE; request.setAttribute("bookList", tutorialList); RequestDispatcher dispatcher = getServletContext( ) .getRequestDispatcher("/booklist1.jsp"); dispatcher.include(request, response); } } |
Example Rendering XML with JSP tags
<?xml version="1.0" encoding="UTF-8" ?> <%@ page contentType="text/xml"%> <%@ taglib prefix="c" uri="http://java.oracle.com/jsp/jstl/core"%> <books> <c:forEach items="${bookList}" var="book"> <book> <title>${book.title}</title> <author>${book.author}</author> <pubdate>${book.pubdate}</pubdate> </book> </c:forEach> </books> |
|
However, when we generate XML with a JSP such as Example 13-4, we are now able to produce an XML document that is not well-formed. Because the servlet in Example 13-2 creates its document with DOM, there's no way a document that's not well-formed would be produced (except in case of a bug in the XML libraries). But with this method of creating a document with JSP, there is nothing to prevent you from accidentally creating a document with mismatched end tags such as:
<?xml version="1.0" encoding="UTF-8" ?> <books> <book> <title>Ajax Hacks</title> <author>Bruce W. Perry</pubdate> <pubdate>March 2006</author> </book> </books>
Or any of a variety of other well-formedness issues. Nevertheless, creating the document this way with JSP is bound to be faster and consume far less memory, since intermediate DOM objects are not created.