Xml validation against xsd using jaxb

XSD’s (XML Schema Definition) are used for xml validation. An xsd contains a certain set of rules which the xml should follow. In this article we will how to use JAXB for xml schema validation.

XML

Shown below is an xml file which we would validate against an xsd and then unmarshal into a java object. We call the xml as employee.xml.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Employee id="1">
    <name>Abhishek</name>
    <email>[email protected]</email>
    <mobile>9856778856</mobile>
    <joiningDate>10-21-2010</joiningDate>
</Employee>

XSD

Now we create our xsd which contains all the rules and restriction to be validated upon. Let's name it as employee.xsd.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" 
    xmlns:tns="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.w3.org/2001/XMLSchema">
    
    <xsd:element name="Employee">
        <xsd:complexType>
    	    <xsd:sequence>
    		<xsd:element name="name" type="nameType"></xsd:element>
   		<xsd:element name="email" type="string"></xsd:element>
    		<xsd:element name="mobile" type="mobileType"></xsd:element>
    		<xsd:element name="joiningDate" type="string"></xsd:element>
    	    </xsd:sequence>
    	    <xsd:attribute name="id" type="integer"></xsd:attribute>
    	</xsd:complexType>
    </xsd:element>
    
    <xsd:simpleType name="nameType">
    	<xsd:restriction base="xsd:string">
   	    <xsd:pattern value="[A-Za-z]" />
    	</xsd:restriction>
    </xsd:simpleType>
    
    <xsd:simpleType name="mobileType">
    	<xsd:restriction base="xsd:integer">
   	    <xsd:pattern value="^[0-9]{10}$" />
    	</xsd:restriction>
    </xsd:simpleType>
    
</xsd:schema>

POJO

Now that we have our xml and xsd in place, we need to create a POJO to unmarshal the xml into an object. Eclipse IDE provides a convenient option to generate the POJO from the xsd. We will leverage this option and generate the Employee class from our employee.xsd.

To generate the POJO, just right click on employee.xsd and go to 'Generate'-->'JAXB Classes' as shown in the figure below:

The Employee class generated from the xsd is shown below:

/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * <complexType>
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="name" type="{http://www.w3.org/2001/XMLSchema}nameType"/>
 *         <element name="email" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         <element name="mobile" type="{http://www.w3.org/2001/XMLSchema}mobileType"/>
 *         <element name="joiningDate" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *       </sequence>
 *       <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}integer" />
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"name","email","mobile","joiningDate"})
@XmlRootElement(name = "Employee")
public class Employee {

    @XmlElement(required = true)
    @XmlSchemaType(name = "nameType")
    protected String name;
    
    @XmlElement(required = true)
    protected String email;
    
    @XmlElement(required = true)
    @XmlSchemaType(name = "mobileType")
    protected BigInteger mobile;
    
    @XmlElement(required = true)
    protected String joiningDate;
    
    @XmlAttribute(name = "id")
    protected BigInteger id;

    /**
     * Gets the value of the name property.
     * 
     * @return
     *     possible object is
     *     [email protected] String }
     *     
     */
    public String getName() {
        return name;
    }

    /**
     * Sets the value of the name property.
     * 
     * @param value
     *     allowed object is
     *     [email protected] String }
     *     
     */
    public void setName(String value) {
        this.name = value;
    }

    /**
     * Gets the value of the email property.
     * 
     * @return
     *     possible object is
     *     [email protected] String }
     *     
     */
    public String getEmail() {
        return email;
    }

    /**
     * Sets the value of the email property.
     * 
     * @param value
     *     allowed object is
     *     [email protected] String }
     *     
     */
    public void setEmail(String value) {
        this.email = value;
    }

    /**
     * Gets the value of the mobile property.
     * 
     * @return
     *     possible object is
     *     [email protected] BigInteger }
     *     
     */
    public BigInteger getMobile() {
        return mobile;
    }

    /**
     * Sets the value of the mobile property.
     * 
     * @param value
     *     allowed object is
     *     [email protected] BigInteger }
     *     
     */
    public void setMobile(BigInteger value) {
        this.mobile = value;
    }

    /**
     * Gets the value of the joiningDate property.
     * 
     * @return
     *     possible object is
     *     [email protected] String }
     *     
     */
    public String getJoiningDate() {
        return joiningDate;
    }

    /**
     * Sets the value of the joiningDate property.
     * 
     * @param value
     *     allowed object is
     *     [email protected] String }
     *     
     */
    public void setJoiningDate(String value) {
        this.joiningDate = value;
    }

    /**
     * Gets the value of the id property.
     * 
     * @return
     *     possible object is
     *     [email protected] BigInteger }
     *     
     */
    public BigInteger getId() {
        return id;
    }

    /**
     * Sets the value of the id property.
     * 
     * @param value
     *     allowed object is
     *     [email protected] BigInteger }
     *     
     */
    public void setId(BigInteger value) {
        this.id = value;
    }

}

XML Validation / Unmarshalling

Now that everything is in place, we are ready to write out validation and marshalling code. The code is shown below:

public class JAXBExecutor {
	
    public static void main(String args[]) throws JAXBException, SAXException{
		
	File xml = new File("employee.xml");
		
	SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
	Schema schema = sf.newSchema(new File("employee.xsd"));
		
	JAXBContext contx = JAXBContext.newInstance(Employee.class);
	Unmarshaller unmarshaller = contx.createUnmarshaller();
	unmarshaller.setSchema(schema);
	unmarshaller.setEventHandler(new EmployeeValidator());
	Employee emp = (Employee)unmarshaller.unmarshal(xml);		
   }
}

To perform validation we follow the following steps:

  • We create an instance of SchemaFactory by calling the static method newInstance().
  • We create a schema object by calling the method newSchema() of the SchemaFactory. The Schema object is a java object representation of the xsd.
  • Create the JAXBContext object by passing the Employee class (generated POJO from xsd) to the static newInstance method of JAXBContext.
  • Create the unmarshaller object by calling the createUnmarshaller() method of the JAXBContent.
  • Assign the schema to the unmarshaller by calling the setSchema() method of the unmarshaller.
  • We also registered an event handler (optional), which we can use to respond to various events during validation.
  • Finally, we call the unmarshal() method of the unmarshaller to validate/unmarshal the employee.xml to the employee object. 

ValidationEventHandler

The ValidationEventHandler is an interface is used to capture the events triggered during validation of the xml against the xsd.

The code below shows an implementation of ValidationEventHandler that we use to track any validation error.  If any error is encountered during validation we are printing various information corresponding to the error that can help us in tracking the error.

public class EmployeeValidator implements ValidationEventHandler{

    @Override
    public boolean handleEvent(ValidationEvent event) {

	if(event.getSeverity() == ValidationEvent.ERROR || 
event.getSeverity() == ValidationEvent.FATAL_ERROR ){
System.out.println("Severity: " + event.getSeverity()); System.out.println("Message: " + event.getMessage()); System.out.println("Exception: " + event.getLinkedException()); System.out.println(); System.out.println("Line Number: " + event.getLocator().getLineNumber()); System.out.println("Column Number: " + event.getLocator().getColumnNumber()); return false; } return true; } }
RELATED ARTICLES

Generate Namespace & Schema Information using JAXB

Most xml documents used in enterprise applications makes use of namespace to avoid element name conflicts. This article talks about generating these namespace and schema information when marshaling...

View Article

Handling Complex Types with JAXB Adapters

JAXB provides a convenient way to map complex data types to xml representations. JAXB provides XMLJavaAdapter to handle such custom marshalling and unmarshalling needs.

View Article

Object-XML Binding using JAXB

JAXB is a Java API that simplifies the access of XML documents within a Java Application. This articles demonstrates xml to object conversion and vice-versa using JAXB.

View Article