JSTL-XML
— print (last updated: Oct 28, 2009) print

Select font size:
To run this sample project in NetBeans, download the JSTL-XML.zip archive. This uses the JSTL library files (jstl.jar, standard.jar) and these new JAR files:
xalan.jar
xercesImpl.jar
serializer.jar
These JAR files are part of the Apache Xalan distribution found at:
http://xml.apache.org/xalan-j/
A recent version is 2.7.1 and the binary distribution can be downloaded from the course server at
xalan-j_2_7_1-bin.zip
Using Eclipse, download and install the WAR file: JSTL-XML.war

XML

XML (eXtensible Markup Language) is a common way of expressing hierarchical information for data interchange between various applications. Like HTML, it is a derivative of the exceedingly complex SGML (Standard General Markup Language). Web applications, as well as other many other applications, need to know how to read, validate and create such XML files. This example we will several aspects of XML usage Both the JSTL core (c) and XML (x) tags are used.

The XML file

Our example is a bookstore containing, of course, books (at least they have different fields than usual). Each book has a title, one or more authors, a year and an optional price. The book belongs to a category and the title may express a language for how it appears. Here is the file of interest:

books.xml
<?xml version="1.0" encoding="UTF-8"?> <bookstore> <book category="COOKING"> <title>Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> </book> <book category="WEB"> <title lang="en">XQuery Kick Start</title> <author>James McGovern</author> <author>Per Bothner</author> <year>2005</year> <price>39.95</price> </book> <book category="FICTION"> <title lang="sp">La Casa De Los Espiritus</title> <author>Isabelle Allende</author> <year>1982</year> <price>15.00</price> </book> </bookstore>

Basic Display

Our first two example merely capture the books.xml and display it. At the core of both is the JSTL tag usage:
<c:import var="xml" url="static/books.xml" /<
which "captures" the entire XML file into the EL variable. The scripts are these:

xmlview1.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <c:set var="title" value="XML View 1" /> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>${title}</title> </head> <body> <h1>${title}</h1> <c:import var="xml" url="books.xml" /> <pre><c:out value="${xml}" /></pre> </body> </html>

xmlview2.jsp
<%@page contentType="text/xml" pageEncoding="UTF-8" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><c:import var="xml" url="books.xml" /><c:out value="${xml}" escapeXml="false" />
Notes about these scripts are:
  1. xmlview1 shows what the literal XML code is by dumping it within a pre-formatted (pre) element. The crucial escaping is implicit using the c:out tag.
  2. xmlview2 sends the XML to the browser, as if you clicked on the unadorned XML file, per se. In JSP you cannot have any space characters whatsoever up to the c:out display in which we do not want to escape the XML.

    The rendering which takes place is courtesy of the browser capabilities; both Firefox and IE will render the XML in some default manner. However, Eclipse's built-in browser completely ignores the unknown tags.

    Although this type of rendering would have better control in a servlet, the c:import tag is hard to beat for convenience.

Rendering via an XSL stylesheet

XSLT (eXtensible Stylesheet Language Transformations) is an XML-based language which can be used to access information in an XML file via XPath expressions and output it in a suitable format. This "suitable" output format is often HTML, in which the content of the XML file can be viewed readily. Simply by attaching the XSL file to the XML file books.xml via the statement:
<?xml-stylesheet type="text/xsl" href="books.xsl"?>
causes modern, XML-aware, browsers to do the transformation. Here is the XSL file:

books.xsl
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <xsl:apply-templates /> </xsl:template> <xsl:template match="/bookstore"> <html> <table cellpadding="5px" border="1"> <tr align="left"> <th>category</th> <th>title</th> <th>lang</th> <th>authors</th> <th>year</th> <th>price</th> </tr> <xsl:for-each select="./book"> <tr valign="top"> <td><xsl:value-of select="./@category" /></td> <td><xsl:value-of select="./title" /></td> <td><xsl:value-of select="./title/@lang" /></td> <td> <xsl:for-each select="./author"> <xsl:value-of select="." /> <br /> </xsl:for-each> </td> <td><xsl:value-of select="./year" /></td> <td> <xsl:choose> <xsl:when test="./price/text()"> <xsl:value-of select="./price" /> </xsl:when> <xsl:otherwise>?</xsl:otherwise> </xsl:choose> </td> </tr> </xsl:for-each> </table> </html> </xsl:template> </xsl:stylesheet>
The first approach is to simply pass this XML content directly to the browser as we did before:

xmlview3.jsp
<%@page contentType="text/xml" pageEncoding="UTF-8" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><c:import var="xml" url="books-use-xsl.xml" /><c:out value="${xml}" escapeXml="false" />
The only difference is that the books.xml has been modified by adding an extra line, making it this file:

books-use-xsl.xml
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="static/books.xsl"?> <bookstore>

XPath Notation

The type of notation used to access data in the XML tree is called XPath notation. Examples of the XPath expressions used are in this class are:
"/bookstore/book"    access the book elements
"./title/text()      access the text of book selected
"./@category"        access the category attribute of book selected
"./title/@lang"      access the lang attribute of the title of book selected
We'll see the same expressions in JSTL.

Applying the XSL stylesheet in JSTL

The x:transform tag makes it, in many ways, easier to apply the stylesheet. In this case, the XSL stylesheet's extra html tags, which were necessary in the previous case, are superfluous here, and are effectively ignored.

xmlview4.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml"%> <c:set var="title" value="XML View 4" /> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>${title}</title> </head> <body> <h1>${title}</h1> <c:import var="xml" url="books.xml" /> <c:import var="xsl" url="books.xsl" /> <x:transform xml="${xml}" xslt="${xsl}" /> </body> </html>

XML to HTML directly in JSTL

Additional XML (x) tags can be used to effect a conversion from XML to HTML as is done by the XSL stylesheet. Again, the XPath notation is used to extract the XML information and embed in into HTML code using the XML tags. Aside from minor syntactic differences, the two conversions to HTML is virtually identical.

xmlview5.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml"%> <c:set var="title" value="XML View 5" /> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>${title}</title> </head> <body> <h1>${title}</h1> <c:import var="xml" url="books.xml" /> <x:parse var="doc" doc="${xml}" /> <x:set var="bookstore" select="$doc/bookstore" /> <table cellpadding="5px" border="1"> <tr align="left"> <th>category</th> <th>title</th> <th>lang</th> <th>authors</th> <th>year</th> <th>price</th> </tr> <x:forEach var="book" select="$bookstore/book"> <tr valign="top"> <td><x:out select="$book/@category" /></td> <td><x:out select="$book/title" /></td> <td><x:out select="$book/title/@lang" /></td> <td> <x:forEach var="author" select="$book/author"> <x:out select="$author" /> <br /> </x:forEach> </td> <td><x:out select="$book/year" /></td> <td> <x:choose> <x:when select="$book/price"> <x:out select="$book/price" /> </x:when> <x:otherwise>?</x:otherwise> </x:choose> </td> </tr> </x:forEach> </table> </body> </html>

Validation

Validation of an XML file signfies that that its structure, in terms of elements and attributes matches an established pattern or schema.

DTD validation

The original validation specification built into XML is called Document Type Definition (DTD). It can be embedded within the XML file directly or, preferably, be accessed as an external file as follows:

books-use-dtd.xml
<?xml version="1.0"?> <!DOCTYPE bookstore SYSTEM "books.dtd"> <bookstore>
The external file DTD file is this:

books.dtd
<!ELEMENT bookstore (book)* > <!ELEMENT book (title, author+, year, price?) > <!ELEMENT title (#PCDATA) > <!ELEMENT author (#PCDATA) > <!ELEMENT year (#PCDATA) > <!ELEMENT price (#PCDATA) > <!ATTLIST title lang (en|sp|gr) #IMPLIED> <!ATTLIST book category CDATA #REQUIRED>

XML Schema validation

The DTD schema has some significant limitations in terms of its expressive capabilities. For example, there is no real notion of data types for elements or attributes. The XML schema is one such alternative validation schema. It itself is written in XML and offers significantly more expressive capabilities. The reference to the external file books.xsd is added to the starting tag:

books-use-xsd.xml
<?xml version="1.0"?> <bookstore xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="books.xsd">
The external XSD validation file is significantly more complicated than the DTD file:

books.xsd
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="bookstore"> <xsd:complexType> <xsd:sequence> <xsd:element name="book" type="bookType" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:complexType name="bookType"> <xsd:sequence> <!-- XML schema makes it tricky to have a non-empty element with attributes. It has to be a complexType to have attributes but you have to specify simpleContent --> <xsd:element name="title" minOccurs="1"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="lang" type="langType" /> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> <xsd:element name="author" type="xsd:string" maxOccurs="4"/> <xsd:element name="year" type="yearType"/> <xsd:element name="price" type="xsd:decimal" minOccurs="0"/> </xsd:sequence> <xsd:attribute name="category" type="xsd:string" use="required"/> </xsd:complexType> <xsd:simpleType name="langType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="en"/> <xsd:enumeration value="sp"/> <xsd:enumeration value="gr"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="yearType"> <xsd:restriction base="xsd:string"> <xsd:pattern value="\d{4}"/> </xsd:restriction> </xsd:simpleType> </xsd:schema>

Validation Example

This is the JSP file which sets up for validating either of the two files:
books-use-dtd.xml
books-use-xsd.xml
There are several interesting new features in this code per se, include the use of the EL global variable:
pageContext
which allows us to access features of JSP including the request, response and session. In this example we make use of the pageContext.request in order to construct the full URL from variable information.

validate.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <jsp:useBean id="validator" scope="request" class="util.DomValidator" /> <c:set var="title" value="XML Validation" /> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>${title}</title> </head> <body> <h1>${title}</h1> <form action=""> XML file: <select name="file"> <option>books-use-dtd.xml</option> <option "${param.file=="books-use-xsd.xml"?"selected":""}" >books-use-xsd.xml</option> </select> <input type="submit" value="Validate" /> </form> <c:if test="${!empty(param.file)}" > <br /><br /> <c:set var="xmlFile" value="${param.file}" /> <b><c:out value="${xmlFile}" /></b> <!-- We have to construct the full URL to the sample file --> <c:set var="server" value="${pageContext.request.serverName}" /> <c:set var="port" value="${pageContext.request.serverPort}" /> <c:set var="path" value="${pageContext.request.contextPath}" /> <c:set var="url" value="http://${server}:${port}${path}/${xmlFile}" /> <c:set target="${validator}" property="url" value="${url}" /> <c:set var="status" value="${validator.status}" /> <br /><br /> <c:choose> <c:when test="${status == 0}">VALID</c:when> <c:when test="${status > 0}"> WARNINGS:<br /> <c:out value="${validator.info}" /> </c:when> <c:otherwise> ERRORS:<br /> <c:out value="${validator.info}" /> </c:otherwise> </c:choose> </c:if> </body> </html>
The key code which performs the validation is below. The idea behind validation is the ability to both From a Java standpoint, parsing an XML file can be viewed according to two types of parsing models: A DOM parser sees the XML file as a tree structure consisting of a heirarchical set of nodes; everything about the XML document is represented in the tree structure. The SAX parse process the XML file as a series of "events" in which one enters or leaves an element tag, no representation of the entire structure is ever created. From a Java perspective, we use JAXP (Java API for XML Parsing) which provides programming for DOM, SAX and XSLT processing.

The DOM parser, although more costly in terms of space usage, provides the best mechanism for XML validation. The actual validation is done by the Java object:
DOMParser parser = new DOMParser();
in one simple step:
parser.parse(url);
where the url is the constructed URL to one of the files books-use-dtd.xml or books-use-xsd.xml. Prior to running the parser, several preparatory steps must be taken, including: After execution, information set by the handler provides the means for determining the degree of validity of the XML file. This is the validator bean code:

util/DomValidator.java
package util; import org.xml.sax.*; import org.xml.sax.helpers.*; import org.apache.xerces.parsers.DOMParser; public class DomValidator { private String url; private String info; private boolean error; public String getInfo() { return info; } public void setUrl(String url) { this.url = url; } public int getStatus() { try { DOMParser parser = new DOMParser(); parser.setFeature("http://xml.org/sax/features/validation", true); parser.setFeature( "http://apache.org/xml/features/validation/schema", true); error = false; info = ""; ErrorHandler handler = new DefaultHandler() { @Override public void error(SAXParseException x) { info += " *** Parse error: " + x.getMessage(); error = true; } @Override public void warning(SAXParseException x) { info += " *** Parse warning: " + x.getMessage(); } @Override public void fatalError(SAXParseException x) throws SAXParseException { throw x; } }; parser.setErrorHandler(handler); parser.parse(url); if (error) { return -1; } else if (!info.equals("")) { return 1; } return 0; } catch (Exception x) { info = " *** " + x.toString(); return -1; } } }

Checking the validation

Here are some tweaks you can do to the XML files
books-use-dtd.xml
books-use-xsd.xml
to get feedback. Open these files in your IDE, make these changes in both files, test the validation and then change them back (undo):
  1. Remove the year element in one of the books.
  2. Remove the category attribute from one of the book elements.
  3. Add the unknown attribute/value a="test" into one of the book elements.
  4. Modify the XML statement by changing "en" to "en1"
    <title lang="en1">XQuery Kick Start</title>
    
  5. Change one of the years to an invalid string, like 200x.
The last example illustrates the limitations of the DTD file, which will say the false year is valid, wherease the XSD file will catch the mistake. Another example is that the XSD file indicates that there can be no more than four author elements, something not expressible in DTD.


© Robert M. Kline