使用Java根据本地DTD文件验证XML文件

问题描述:

如何根据本地存储为文件的DTD验证XML文件? XML文件没有任何DOCTYPE声明(或者可能有一个应该被覆盖)。我看了一下this thread,但除了他们使用.NET的事实之外,我怀疑这是一个很好的解决方案。使用Java根据本地DTD文件验证XML文件

任何输入赞赏!

在理想的世界中,您可以使用Validator进行验证。事情是这样的:

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")); 

不幸的是,Sun实现(至少,如Java 6)不包括从DTD创建Schema实例的支持。您可能能够追踪第三方实施。

最好的办法可能是在使用其他一些机制解析之前,将文档改为包含DTD。


可以使用transformer插入DTD声明:

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)); 

...但是这似乎并没有取代现有的DTD声明。


StAX事件的读者可以做的工作:

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; 
    } 

    } 

它会在文档刚开始之后发送给定DTD声明,并丢弃任何从旧文件。

演示用法:

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 

注意,XMLEventReader的可以构成为执行验证一些其他的转化机制的来源。


如果您有该选项,使用W3模式进行验证会容易得多。

您必须实施EntityResolver,结帐this example

+0

感谢您的帮助,但如果没有指定DOCTYPE,该怎么办?在这种情况下EntityResolver不会帮助我,是吗? – Simon 2009-07-08 06:34:19

+0

@Bluegene:如果没有DOCTYPE,你在验证什么? – 2009-07-08 07:12:36

即时通讯相当肯定,如果没有DOCTYPE已在 全部被指定的东西,上述将工作..

感谢您的帮助,但什么?在这种情况下EntityResolver不会帮助我,是吗? - Simon Simon 09年8月8日在6:34

@Bluegene:什么是验证,如果没有DOCTYPE? - J-16 SDiZ 09年7月8日7:12

对我自己的DTD。我只想确保我收到的XML 符合我的DTD,而不仅仅是发件人指定的任何DTD。 - 西蒙月 8 '09在23:09

如果问题是你希望它针对您的DTD进行验证,而不是作家,你应该确保有清晰的文档,详细文档类型,以及哪些必须在xml文件中