• Aucun résultat trouvé

Using JSP to Validate XML against a DTD

Dans le document Beginning JSP, JSF and Tomcat (Page 146-150)

To validate an XML file against a DTD, you must first associate the XML document with the DTD by adding a DOCTYPE declaration to the XML file. The declaration, which you should insert immediately after the <?xml...?> line, is as follows:

<!DOCTYPE starfleet SYSTEM "http://localhost:8080/xml-validate/dtd/starfleet.dtd">

Notice that the file starfleet.dtd doesn’t need to be in the WEB-INF\dtds\ folder. We had to place the DTDs there because Tomcat expected them there, but if you do the validation yourself, Tomcat is out of the loop. You can therefore place your DTDs wherever you like.

The next step is the definition of an exception handler. This is a Java object of a class that extends org.xml.sax.helpers.DefaultHandler and replaces three of its methods: warning, error, and fatalError.

Once the handler is registered with the parser, the parser executes the appropriate method upon encountering a validation problem. The default behavior of DefaultHandler is to do nothing. Therefore, you need to overwrite the methods in order to report the errors. Listing 5-4 shows you the code of a possible handler. It’s really up to you to decide what level of reporting you’d like to have, but I have decided to report all validation problems and interrupt the parsing.

Listing 5-4. ParsingExceptionHandler.java package myPkg;

import org.xml.sax.helpers.DefaultHandler;

import org.xml.sax.SAXParseException;

public class ParsingExceptionHandler extends DefaultHandler { public SAXParseException parsingException = null;

public String errorLevel = null;

public void warning(SAXParseException e) { errorLevel = "Warning";

parsingException = e;

}

public void error(SAXParseException e) { errorLevel = "Error";

parsingException = e;

}

public void fatalError(SAXParseException e) { errorLevel = "Fatal error";

parsingException = e;

} }

As you can see, it’s pretty simple. You define two public attributes: one to save the exception generated by the parser, and one to save the error level. You then update the two attributes in each one of the three methods. After each parsing, you can check one of the attributes for null in order to determine whether the parsing succeeded or not. Compile this module from the DOS command line with javac ParsingExceptionHandler.java and copy the resulting .class file into the

WEB-INF\classes\myPkg folder of your application directory.

You are now ready to perform the validation. Listing 5-5 shows you a JSP page that implements a SAX parser.

Listing 5-5. starfleet_validate_sax.jsp (first cut)

<%@page language="java" contentType="text/html"%>

<%@page import="javax.xml.parsers.SAXParserFactory"%>

<%@page import="javax.xml.parsers.SAXParser"%>

<%@page import="org.xml.sax.InputSource"%>

<%@page import="myPkg.ParsingExceptionHandler"%>

<html><head><title>Starfleet validation (SAX - DTD)</title></head><body>

<%

SAXParserFactory factory = SAXParserFactory.newInstance();

factory.setValidating(true);

SAXParser parser = factory.newSAXParser();

InputSource inputSource = new InputSource("webapps/xml-validate/xml/enterprises.xml");

ParsingExceptionHandler handler = new ParsingExceptionHandler();

parser.parse(inputSource, handler);

%>

</body></html>

After instantiating the parser factory and setting its validating property to true, you direct the factory to create a SAX parser. Then you instantiate the InputSource class to access the XML document and the exception handler. After that, all you need to do is execute the parser.

This implementation is not very nice, though, because it causes the dumping of a stack trace whenever the validation fails. It is better to wrap the parsing inside a try/catch as shown in Listing 5-6, so that you can display validation errors without stack trace.

Note that before you can execute the improved version of starfleet_validate_sax.jsp, you need to download the StringEscapeUtils from Apache Commons. Their purpose is to convert special characters to their corresponding HTML entities, so that they display correctly in your web page. Go to

http://commons.apache.org/lang/download_lang.cgi and click on the link commons-lang3-3.1-bin.zip.

To install it in Tomcat, unzip the file, copy commons-lang3-3.1.jar to %CATALINA_HOME%\lib\, and restart Tomcat.

„ Tip In alternative to copying libraries to Tomcat’s lib

folder, you can make them available to a particular application by placing them in the

WEB-INF\lib

folder of the application (create it if it’s not yet there). In that way, the library will not be generally available, but you will not run the risk of later needing a different version of the same library for another application and introducing a conflict when both versions are in Tomcat’s

lib

folder.

Listing 5-6. starfleet_validate_sax.jsp

<html><head><title>Starfleet validation (SAX - DTD)</title></head><body>

<%

SAXParserFactory factory = SAXParserFactory.newInstance();

factory.setValidating(true);

SAXParser parser = factory.newSAXParser();

InputSource inputSource = new InputSource("webapps/xml-validate/xml/enterprises.xml");

ParsingExceptionHandler handler = new ParsingExceptionHandler();

try { parser.parse(inputSource, handler); } catch (Exception e) { }

if (handler.errorLevel == null) { out.println("The document is valid.");

} else {

out.println(

"*** Validation " + handler.errorLevel + ": "

+ StringEscapeUtils.escapeHtml4(handler.parsingException.toString()) );

} %>

</body></html>

Now, if you type http://localhost:8080/xml-validate/with-dtd/starfleet_validate_sax.jsp in a browser, you should get a one-liner confirming that enterprises.xml is correct.

When you introduce an error in the XML document, for example by mistyping the closing tag as in

<captain>James Tiberius Kirk</catain>, you get the following message:

*** Validation Fatal error: org.xml.sax.SAXParseException; systemId: ➥

file:///C:/Program%20Files/Apache%20Software%20Foundation/Tomcat/webapps/xml- ➥ validate/xml/enterprises.xml; lineNumber: 7; columnNumber: 35; The element type ➥

"captain" must be terminated by the matching end-tag "</captain>".

Good, isn’t it? Notice that it is a fatal error. Incidentally, the angle brackets around /captain is why you need to escape the message with StringEscapeUtils. If you remove the line altogether, you get this message:

*** Validation Error: org.xml.sax.SAXParseException; systemId: ➥

file:///C:/Program%20Files/Apache%20Software%20Foundation/Tomcat/webapps/xml- ➥ validate/xml/enterprises.xml; lineNumber: 7; columnNumber: 16; The content of ➥ element type "starship" is incomplete, it must match "(class,captain)".

Notice that it is an error, rather than a fatal error. I confess that I tried to get a warning message but didn’t succeed. If you do, please let me know.

To use a DOM parser instead of SAX, make a copy of starfleet_validate_sax.jsp, name it starfleet_validate_dom.jsp, and replace six lines with seven new lines, as shown in Listing 5-7.

Listing 5-7. starfleet_validate_dom.jsp

<html><head><title>Starfleet validation (DOM - DTD)</title></head><body>

<%

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

factory.setValidating(true);

DocumentBuilder parser = factory.newDocumentBuilder();

InputSource inputSource = new InputSource("webapps/xml-validate/xml/enterprises.xml");

ParsingExceptionHandler handler = new ParsingExceptionHandler();

parser.setErrorHandler(handler);

try { parser.parse(inputSource); } catch (Exception e) { }

if (handler.errorLevel == null) { out.println("The document is valid.");

} else {

out.println(

"*** Validation " + handler.errorLevel + ": "

+ StringEscapeUtils.escapeHtml4(handler.parsingException.toString()) );

} %>

</body></html>

Dans le document Beginning JSP, JSF and Tomcat (Page 146-150)