Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validate an XML file against local DTD file with Java

Tags:

How can I validate an XML file against a DTD that is stored locally as a file? The XML file does not have any DOCTYPE declaration (or may have one that should then be overridden). I had a look at this thread but besides the fact they are using .NET I doubt that this is a good solution.

Any input appreciated!

like image 938
Simon Avatar asked Jul 08 '09 06:07

Simon


People also ask

Can validate your XML against a DTD?

Using XML DTD validation tools − You can use some IDEs such as XML Spy (not free) and XMLStarlet(opensource) can be used to validate XML files against DTD document. Using XML DTD on-line validators − W3C Markup Validation Service is designed to validate Web documents.

How do I validate a DTD file?

To do this you can load the . dtd file in eclipse (copy it into a project, or point your project towards your dtd file). Then in the file navigator in eclipse, you can right click on the dtd, then click validate.

How do you know an XML document is attached to a DTD?

Attribute-list declarations name the permitted attributes for each declared element, including the type of each attribute value, if not an explicit set of valid value(s). A DTD is associated with an XML document via a Document Type Declaration, which is a tag that appears near the start of the XML document.


2 Answers

In an ideal world, you'd be able to validate using a Validator. Something like this:

SchemaFactory schemaFactory = SchemaFactory     .newInstance(XMLConstants.XML_DTD_NS_URI); Schema schema = schemaFactory.newSchema(new File(     "xmlValidate.dtd")); Validator validator = schema.newValidator(); validator.validate(new StreamSource("xmlValidate.xml")); 

Unfortunately, the Sun implementation (at least, as of Java 6) does not include support for creating a Schema instance from a DTD. You might be able to track down a 3rd party implementation.

Your best bet may be to alter the document to include the DTD before parsing using some other mechanism.


You can use a transformer to insert a DTD declaration:

TransformerFactory tf = TransformerFactory     .newInstance(); Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(     OutputKeys.DOCTYPE_SYSTEM, "xmlValidate.dtd"); transformer.transform(new StreamSource(     "xmlValidate.xml"), new StreamResult(System.out)); 

...but this does not seem to replace an existing DTD declaration.


This StAX event reader can do the job:

  public static class DTDReplacer extends       EventReaderDelegate {      private final XMLEvent dtd;     private boolean sendDtd = false;      public DTDReplacer(XMLEventReader reader, XMLEvent dtd) {       super(reader);       if (dtd.getEventType() != XMLEvent.DTD) {         throw new IllegalArgumentException("" + dtd);       }       this.dtd = dtd;     }      @Override     public XMLEvent nextEvent() throws XMLStreamException {       if (sendDtd) {         sendDtd = false;         return dtd;       }       XMLEvent evt = super.nextEvent();       if (evt.getEventType() == XMLEvent.START_DOCUMENT) {         sendDtd = true;       } else if (evt.getEventType() == XMLEvent.DTD) {         // discard old DTD         return super.nextEvent();       }       return evt;     }    } 

It will send a given DTD declaration right after the document start and discard any from the old document.

Demo usage:

XMLEventFactory eventFactory = XMLEventFactory.newInstance(); XMLEvent dtd = eventFactory     .createDTD("<!DOCTYPE Employee SYSTEM \"xmlValidate.dtd\">");  XMLInputFactory inFactory = XMLInputFactory.newInstance(); XMLOutputFactory outFactory = XMLOutputFactory.newInstance(); XMLEventReader reader = inFactory     .createXMLEventReader(new StreamSource(         "xmlValidate.xml")); reader = new DTDReplacer(reader, dtd); XMLEventWriter writer = outFactory.createXMLEventWriter(System.out); writer.add(reader); writer.flush();  // TODO error and proper stream handling 

Note that the XMLEventReader could form the source for some other transformation mechanism that performed validation.


It would be much easier to validate using a W3 schema if you have that option.

like image 157
McDowell Avatar answered Oct 10 '22 02:10

McDowell


im pretty sure the stuff aforementioned will work..

Thanks for your help, but what if no DOCTYPE has been specified at all? The EntityResolver would not help me in that case, would it? – Simon Jul 8 '09 at 6:34

@Bluegene: What are you validating against if no DOCTYPE? – J-16 SDiZ Jul 8 '09 at 7:12

Against my own DTD. I just want to make sure the XML I receive conforms to my DTD, not just any DTD the sender specifies. – Simon Jul 8 '09 at 23:09

if the problem is you want it to be validated against your dtd rather than the authors you should ensure that there is clear documentation that details the doctype, and what must be in the xml file

like image 34
zachary Avatar answered Oct 10 '22 00:10

zachary