How do I validate XML against XSD in Java?

The javax.xml.validation package provides an API for XML documents validation. The validation process verify that an XML document is an instance of a specified XML schema file or XSD file. In this example we are going to validate if the records.xml file below ins an instance of the records.xsd schema. First we will create the following XML file and an XSD file it should follow.

The XML file:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <records>
        <record>
            <title>Brand New Eyes</title>
            <artist>Paramore</artist>
            <genre>Punk Rock</genre>
            <year>2011</year>
        </record>
        <record>
            <artist>Various Artist</artist>
            <genre>Rock</genre>
            <year/>
        </record>
    </records>
</root>

The XSD file:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified"
           elementFormDefault="qualified">
    <xs:element name="root" type="rootType">
    </xs:element>

    <xs:complexType name="rootType">
        <xs:sequence>
            <xs:element name="records" type="recordsType"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="recordsType">
        <xs:sequence>
            <xs:element name="record" type="recordType" maxOccurs="unbounded" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="recordType">
        <xs:sequence>
            <xs:element type="xs:string" name="title"/>
            <xs:element type="xs:string" name="artist"/>
            <xs:element type="xs:string" name="genre"/>
            <xs:element type="xs:short" name="year"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

The code snippet below will handle the validation process in the following steps. In the main() method we create the XMLValidator instance and call the validate() method and pass the XML file and the XSD file. Our validate() method start by creating an instance of SchemaFactory. The SchemaFactory.newInstance() method return an instance of SchemaFactory. In this example we are creating a W3C XML Schema.

The next step is to create a Schema object by calling the schemaFactory.newSchema() and pass the schema / XSD file. The Schema object will allow us to create an instance of javax.xml.validation.Validator by calling the schema.newValidator() method. And finally to validate if the XML is valid we call validator.validate() method and pass the XML file to be validated. If the XML is not valid, this validate() method will throw exceptions.

The Java code:

package org.kodejava.xml;

import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.Objects;

public class XMLValidator {
    public static final String XML_FILE = "records.xml";
    public static final String SCHEMA_FILE = "records.xsd";

    public static void main(String[] args) {
        XMLValidator XMLValidator = new XMLValidator();
        boolean valid = XMLValidator.validate(XML_FILE, SCHEMA_FILE);

        System.out.printf("%s validation = %b.", XML_FILE, valid);
    }

    private boolean validate(String xmlFile, String schemaFile) {
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        try {
            Schema schema = schemaFactory.newSchema(new File(getResource(schemaFile)));

            Validator validator = schema.newValidator();
            validator.validate(new StreamSource(new File(getResource(xmlFile))));
            return true;
        } catch (SAXException | IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    private String getResource(String filename) throws FileNotFoundException {
        URL resource = getClass().getClassLoader().getResource(filename);
        Objects.requireNonNull(resource);

        return resource.getFile();
    }
}
Wayan

25 Comments

  1. Hi,
    I get a java.lang.NullPointerException when trying to call validator.validate(new StreamSource(new File(getResource(xmlFile))));. It can not find the resource for the second attempt.

    
    public static final String schemaFile = "schemaF.xsd";
    validateXml(writer.toString());
    
    private boolean validateXml(String xml, String schemaFile) throws Exception {
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        try {
            Schema schema = schemaFactory.newSchema(new File(getResource(schemaFile)));
    
            Validator validator = schema.newValidator();
            validator.validate(new StreamSource(new File(getResource(xml))));
            return true;
        } catch (SAXException | IOException e) {
            e.printStackTrace();
            return false;
        }
    
    }
    
    private String getResource(String fileName) throws FileNotFoundException {
        URL resource = getClass().getClassLoader().getResource(fileName);
        Objects.requireNonNull(resource);
    
        return resource.getFile();
    }
    
    
    Reply
  2. Hi Wayan,

    Thank you for the sharing code.

    I encounter error below, may I know why?

    Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
        XMLValidator cannot be resolved to a type
    
    Reply
    • Hi Aakash,

      You can directly load the file if you know the exact location of the file. Something like:

      String schemaFile = "/path/to/schema/file";
      Schema schema = schemaFactory.newSchema(new File(schemaFile));
      
      Reply
  3. Exception in thread "main" java.lang.NullPointerException
        at java.util.Objects.requireNonNull(Unknown Source)
        at xmlValidatorMaven.XMLValidator.getResource(XMLValidator.java:43)
        at xmlValidatorMaven.XMLValidator.validate(XMLValidator.java:30)
        at xmlValidatorMaven.XMLValidator.main(XMLValidator.java:22)
    
    Reply
    • Hi Shakti,

      Your code get an exception because it could not load the xml and xsd files. The code example above written as a maven project and I’ve placed the files under a resources directory. See the structure below.

      |   pom.xml
      |
      \---src
          \---main
              +---java
              |   \---org
              |       \---kodejava
              |           \---xml
              |                   XMLValidator.java
              |
              \---resources
                      records.xml
                      records.xsd
      

      If you don’t use a maven project just replace the call to getResource() method with the full path of your xml and xsd file location.

      Schema schema = schemaFactory.newSchema(new File("/path/to/scschemaFile.xsd"));
      
      Validator validator = schema.newValidator();
      validator.validate(new StreamSource(new File("/path/to/xmlFile.xml")));
      
      Reply
  4. I am getting below error.

    org.xml.sax.SAXParseException; systemId: file:/D:/RBIXSD/ERSTXSD/camt.054.001.06v0.1.xsd; lineNumber: 2; columnNumber: 1; Content is not allowed in prolog.
        at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
        at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177)
        at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
        at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
        at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1472)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:994)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
        at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
        at com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaParsingConfig.parse(SchemaParsingConfig.java:629)
        at com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaParsingConfig.parse(SchemaParsingConfig.java:685)
        at com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOMParser.parse(SchemaDOMParser.java:530)
        at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getSchemaDocument(XSDHandler.java:2179)
        at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:576)
        at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:613)
        at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:572)
        at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:538)
        at com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:255)
        at javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:638)
        at javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:654)
        at XMLValidator.validate(XMLValidator.java:29)
        at XMLValidator.main(XMLValidator.java:21)
    
    Reply
  5. Some errors is XML file, put all the path resource as Wayan Saryada said, but correct the XML file in the section of line 11, 14 and ends the of this form.

    Reply
  6. Thank you very much, worked perfectly! For the ones who are having the NullPointerException, try to delete these lines:

    Schema schema = schemaFactory.newSchema(new File(getResource(schemaFile)));
    validator.validate(new StreamSource(new File(getResource(xml))));
    

    and replace them with:

    Schema schema = schemaFactory.newSchema(new File(schemaFile));
    validator.validate(new StreamSource(new File(xml)));
    

    respectively. This worked for me.

    Reply
  7. Hi, many thanks for this article. I am facing an issue while validating schema. I have my user defined XSD file where in I have user defined “xmlns” and “target namespace” along with “xmlns:xs”. While I am using this code, even if xml is not correct as per this xsd, it is getting pass which is wrong. Request you to please help!

    Reply
  8. Hi Wayan,

    I’ve used the same piece of code you have mentioned above to validate my XML with the XSD. But it’s still giving me a null pointer exception. I have given the XML & XSD directory directly as you have mentioned in the comments who were having the same issue.

    Kindly let me know how I can resolve this issue?

    Reply
  9. I am using Spring Boot application with Jdk17. After updating the latest Docker image, I am getting the schema validation errors twice. It is showing duplicate errors for few xsd validation errors. Any idea on this issue? How we can resolve this issue?

    Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.