使用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模式进行验证会容易得多。
答
即时通讯相当肯定,如果没有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文件中
感谢您的帮助,但如果没有指定DOCTYPE,该怎么办?在这种情况下EntityResolver不会帮助我,是吗? – Simon 2009-07-08 06:34:19
@Bluegene:如果没有DOCTYPE,你在验证什么? – 2009-07-08 07:12:36