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 create 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 the 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.example.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();
    }
}

How do I build object from XML file using SAX?

This example will show you how to parse an XML file using SAX parser and build an object graph from the parsed XML. We will read the records.xml file that contains some recording information and create the Record object from it.

The DefaultHandler in this example created as an anonymous class. We override some method related to the ContentHandler interface such as the startElement, endElement and characters methods.

package org.kodejava.example.xml;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class SAXDataDemo {
    // List of our records data.
    private List<Record> records = new ArrayList<Record>();

    // Stacks for storing the elements and objects.
    private Stack<String> elements = new Stack<String>();
    private Stack<Record> objects = new Stack<Record>();


    public static void main(String[] args) {
        SAXDataDemo demo = new SAXDataDemo();
        demo.run();
    }

    private void run() {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();

            String filename = "/records.xml";
            InputStream is = getClass().getResourceAsStream(filename);

            parser.parse(is, new DefaultHandler() {
                @Override
                public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                    elements.push(qName);
                    if ("record".equals(qName)) {
                        Record record = new Record();
                        objects.push(record);
                        records.add(record);
                    }
                }

                @Override
                public void endElement(String uri, String localName, String qName) throws SAXException {
                    elements.pop();
                }

                @Override
                public void characters(char[] ch, int start, int length) throws SAXException {

                    String value = new String(ch, start, length);
                    if (value.length() == 0) {
                        return;
                    }

                    if ("title".equals(currentElement())) {
                        Record record = objects.peek();
                        record.setTitle(value);
                    } else if ("artist".equals(currentElement())) {
                        Record record = objects.peek();
                        record.setArtist(value);
                    } else if ("genre".equals(currentElement())) {
                        Record record = objects.peek();
                        record.setGenre(value);
                    } else if ("year".equals(currentElement())) {
                        Record record = objects.peek();
                        record.setYear(Integer.valueOf(value));
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

        for (Record record : records) {
            System.out.println("record = " + record);
        }
    }

    private String currentElement() {
        return elements.peek();
    }
}

The Record class.

package org.kodejava.example.xml;

public class Record {
    private String title;
    private String artist;
    private String genre;
    private int year;

    public Record() {
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }

    public void setGenre(String genre) {
        this.genre = genre;
    }

    public void setYear(int year) {
        this.year = year;
    }

    @Override
    public String toString() {
        return "Record{" +
                "title='" + title + "'n" +
                ", artist='" + artist + "'n" +
                ", genre='" + genre + "'n" +
                ", year=" + year +
                '}';
    }
}

The following XML is the content of our records.xml file.

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

When we run this example will get the following output:

record = Record{title='Brand New Eyes'
, artist='Paramore'
, genre='Punk Rock'
, year=2011}
record = Record{title='Rock Beatles'
, artist='Various Artist'
, genre='Rock'
, year=2010}

How do I parse an XML file using SAX?

This example show you how to read / parse an xml file using the SAX (Simple API for XML) parser. In the main class (SAXDemo) we create the instance of SAXParserFactory and the SAXParser. The SAXParser.parse() method will parse the given InputStream and handle the xml document using the SAXHandler class that we created.

package org.kodejava.example.xml;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;

public class SAXDemo {
    public static void main(String[] args) throws Exception {
        // Creates a new instance of SAXParserFactory that in turn
        // creates a SAXParser.
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();

        // The handler that will listen to the SAX event during
        // the xml traversal.
        SAXHandler handler = new SAXHandler();
        InputStream data = SAXDemo.class.getResourceAsStream("/person.xml");
        parser.parse(data, handler);
    }
}

The SAXHandler class extended from the org.xml.sax.helpers.DefaultHandler class. The handler will listen to the event triggered by the SAXParser. This handler methods is defined by the interfaces such as the ContentHandler, ErrorHandler, DTDHandler, and EntityResolver.

For example to read the content of the XML file there are methods to listen to events such as startDocument, endDocument, startElement, endElement, etc, which defined by the ContentHandler interface.

package org.kodejava.example.xml;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SAXHandler extends DefaultHandler {
    @Override
    public void startDocument() throws SAXException {
        System.out.println("startDocument");
    }

    @Override
    public void endDocument() throws SAXException {
        System.out.println("endDocument");
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        System.out.println("startElement: " + qName);
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.println("endElement");
    }

    @Override
    public void characters(char[] ch, int start, int length)throws SAXException {
        System.out.println("characters  : " + new String(ch, start, length));
    }
}

Here an example of the xml file will be read by our program:

<root>
    <persons>
        <person>
            <name>Foo</name>
        </person>
        <person>
            <name>Bar</name>
        </person>
    <persons>
</root>

Our program will print the following output:

startDocument
startElement: root
characters  : 
    
startElement: persons
characters  : 
        
startElement: person
characters  : 
            
startElement: name
characters  : Foo
endElement
characters  : 
        
endElement
characters  : 
        
startElement: person
characters  : 
            
startElement: name
characters  : Bar
endElement
characters  : 
        
endElement
characters  : 
    
endElement
characters  : 

endElement
endDocument