【发布时间】:2010-11-08 22:37:49
【问题描述】:
如何根据本地存储为文件的 DTD 验证 XML 文件? XML 文件没有任何 DOCTYPE 声明(或者可能有一个应该被覆盖的声明)。我查看了this thread,但除了他们使用.NET 之外,我怀疑这是一个好的解决方案。
任何意见表示赞赏!
【问题讨论】:
标签: java xml validation dtd
如何根据本地存储为文件的 DTD 验证 XML 文件? XML 文件没有任何 DOCTYPE 声明(或者可能有一个应该被覆盖的声明)。我查看了this thread,但除了他们使用.NET 之外,我怀疑这是一个好的解决方案。
任何意见表示赞赏!
【问题讨论】:
标签: java xml validation dtd
在理想情况下,您可以使用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 实例。您或许能够追踪到第 3 方的实施。
最好的办法是在使用其他机制进行解析之前更改文档以包含 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 架构进行验证会容易得多。
【讨论】:
inFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false)。
我很确定前面提到的东西会起作用..
感谢您的帮助,但是如果没有指定 DOCTYPE 怎么办? 全部?在这种情况下,EntityResolver 不会帮助我,不是吗? – 西蒙 2009 年 7 月 8 日 6:34
@Bluegene:如果没有 DOCTYPE,你要验证什么? – J-16 SDiZ 2009 年 7 月 8 日 7:12
反对我自己的 DTD。我只是想确保我收到的 XML 符合我的 DTD,而不仅仅是发件人指定的任何 DTD。 – 西蒙·朱尔 2009 年 8 月 23:09
如果问题是您希望根据您的 dtd 而不是作者对其进行验证,则应确保有明确的文档详细说明 doctype 以及 xml 文件中必须包含的内容
【讨论】:
你必须实现EntityResolver,结帐this example。
【讨论】: