Validate an XML file against local DTD file with Java

前端 未结 3 1349
栀梦
栀梦 2020-11-28 07:26

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 overri

相关标签:
3条回答
  • 2020-11-28 08:03

    You have to implement the EntityResolver, checkout this example.

    0 讨论(0)
  • 2020-11-28 08:04

    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

    0 讨论(0)
  • 2020-11-28 08:08

    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.

    0 讨论(0)
提交回复
热议问题