Share this page 

Validate XML file using external DTD Tag(s): XML


It's a little bit tricky if you want to provide your own DTD when the XML does not specify one or to simply override the one supplied.

We load the XML and set the property with a given DTD and start a transformation.

Take this XML with no DTD specified.

<?xml version="1.0" encoding="ISO-8859-1"?>
<howto>
  <topic>
      <title>Java</title>
      <url>http://www.rgagnon.com/topics/java-xml.html</url>
  </topic>
    <topic>
      <title>PowerBuilder</title>
      <url>http://www.rgagnon.com/topics/pb-powerscript.htm</url>
  </topic>
  <topic>
        <title>Javascript</title>
        <url>http://www.rgagnon.com/topics/js-language.html</url>
  </topic>
  <topic>
        <title>VBScript</title>
        <url>http://www.rgagnon.com/topics/wsh-vbs.html</url>
  </topic>
</howto>
We want to apply this DTD
<!ELEMENT howto (topic*)>
<!ELEMENT topic (title,url)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT url (#PCDATA)>
The required code is :
import java.io.*;

import org.w3c.dom.*;
import org.xml.sax.*;
import javax.xml.parsers.*;

import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

public class XMLUtils {

  private XMLUtils() {}

  public static boolean validateWithExtDTDUsingDOM(String xml, String dtd)
  throws TransformerException, ParserConfigurationException, IOException
  {
    try{
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      factory.setValidating(false);  // we don't want to validate
      DocumentBuilder builder = factory.newDocumentBuilder();
      builder.setErrorHandler(new ErrorHandler() {
        public void warning(SAXParseException e) { } // do nothing
        public void error(SAXParseException e) { } // do nothing
        public void fatalError(SAXParseException e) { } // do nothing
      });

      Document xmlDocument = builder.parse(new FileInputStream(xml));
      DOMSource source = new DOMSource(xmlDocument);
      StreamResult result = new StreamResult(new StringWriter());
      TransformerFactory tf = TransformerFactory.newInstance();
      Transformer transformer = tf.newTransformer();
      transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dtd);
      transformer.transform(source, result); // result is discarded
      return true;
    }
    catch (TransformerConfigurationException tce) {
      throw tce;
    }
    catch (ParserConfigurationException pce) {
      throw pce;
    }
    catch (IOException io) {
      throw io;
    }
    catch (SAXException se){
      System.out.println("ERROR : " + se.getMessage());
      return false;
    }
  }

  public static void main (String args[]) throws Exception{
    System.out.println
    (XMLUtils.validateWithExtDTDUsingDOM
        ("c:/temp/howto.xml", "howto.dtd"));
  }
}
The result when the xml is valid :
result:true
In the xml, if we change
<title>Java</title>

-->

<badtitle>Java</title>
then result, as expected, is
FATAL : The element type "badtitle" must be terminated by the matching end-tag "</badtitle>".
ERROR : The element type "badtitle" must be terminated by the matching end-tag "</badtitle>".

result:false