Thursday, 12 May 2011

How to Schema Validate XML Using SAX

This blog builds on my Checking for Well-Formed XML blog creating a class that can validate XML messages against their schemas by using extra features available in the SAX parser.

This example uses JDom, as part of its interface, but you could use any XML API, such as XmlBeans, or even pass in a String.

The steps required to create a schema validator class are:

1) Create the parser:

    XMLReader parser = XMLReaderFactory.createXMLReader();

2) Enable Schema Validation:

    parser.setFeature("http://xml.org/sax/features/validation", true);
    parser.setFeature
("http://apache.org/xml/features/validation/schema", true);
    parser.setFeature
("http://apache.org/xml/features/validation/schema-full-checking",
       
true);

3) Attach the schema to the parser:

    parser.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation",
        schemaName +
" " + schemaFilename);

4) Turn your input type into an InputSource
This section of code converts our JDom Element input into an InputSource:

    XMLOutputter output = new XMLOutputter(Format.getPrettyFormat());
    String xml = output.outputString
(result);
    source is =
new InputSource(new ByteArrayInputStream(xml.getBytes()));

5) Create an Error Handler:
The error handler is used to communicate any schema validation errors with the caller. This is done using exceptions in order to communicate error details back to the caller.

  private class ErrorHandler extends DefaultHandler {

   
@Override
   
public void error(SAXParseException e) {

     
handleError(e);
   
}

   
@Override
   
public void warning(SAXParseException e) {

     
handleError(e);
   
}

   
@Override
   
public void fatalError(SAXParseException e) {

     
handleError(e);
   
}

   
private void handleError(SAXParseException e) {

     
System.err.println("Error is: " + e.getMessage());
     
throw new SchemaValidationException(e);
   
}
  }

6) Attach the error handler to the parser
Once you’ve created your error handler, attach it to the parser:

    parser.setErrorHandler(new ErrorHandler());

7) Run the parser:

    parser.parse(source);

Once written, the only additional step (apart from writing your unit test code) is to use the object:

    Element element = getElementToValidate("france.xml");
   
// failure throws an exception
   
instance.validate(element);

For clarity, the full code listing for the SchemaValidator follows....

public class SchemaValidator {
 
 
private final String schemaFilename;

 
private final String schemaName;

 
public SchemaValidator(String schemaFilename, String schemaName) {

   
this.schemaFilename = checkSchemaFile(schemaFilename);
   
this.schemaName = schemaName;
 
}

 
private String checkSchemaFile(String schemaFile) {

   
File f = new File(schemaFile);

   
if (!f.exists()) {
     
throw new SystemException("Invalid Schema Filename: " + schemaFile);
   
}
   
return schemaFile;
 
}

 
public void validate(Element element) throws SAXException, IOException {

   
InputSource source = getXMLSource(element);
    XMLReader parser = createParser
();

    parser.parse
(source);
 
}

 
private InputSource getXMLSource(Element result) {

   
String xml = getXML(result);
   
return new InputSource(new ByteArrayInputStream(xml.getBytes()));
 
}

 
private String getXML(Element result) {

   
XMLOutputter output = new XMLOutputter(Format.getPrettyFormat());
   
return output.outputString(result);
 
}

 
private XMLReader createParser() throws SAXException {

   
XMLReader parser = XMLReaderFactory.createXMLReader();
    enableSchemaValidation
(parser);
    attachSchemaFileToParser
(parser);
    parser.setErrorHandler
(new ErrorHandler());

   
return parser;
 
}

 
private void enableSchemaValidation(XMLReader parser) throws SAXException {

   
parser.setFeature("http://xml.org/sax/features/validation", true);
    parser.setFeature
("http://apache.org/xml/features/validation/schema", true);
    parser.setFeature
("http://apache.org/xml/features/validation/schema-full-checking",
       
true);
 
}

 
private void attachSchemaFileToParser(XMLReader parser) throws SAXNotRecognizedException,
      SAXNotSupportedException
{

   
parser.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation",
        schemaName +
" " + schemaFilename);
 
}

 
/**
   * This is the error handler - it overrides the default handler throwing an exception if
   * there's an error
   */
 
private class ErrorHandler extends DefaultHandler {

   
@Override
   
public void error(SAXParseException e) {

     
handleError(e);
   
}

   
@Override
   
public void warning(SAXParseException e) {

     
handleError(e);
   
}

   
@Override
   
public void fatalError(SAXParseException e) {

     
handleError(e);
   
}

   
private void handleError(SAXParseException e) {

     
System.err.println("Error is: " + e.getMessage());
     
throw new SchemaValidationException(e);
   
}
  }
}

1 comment:

Unknown said...

i did more example..but this example make me to understand clearly..