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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1096365/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 23:39:55  来源:igfitidea点击:

Validate an XML file against local DTD file with Java

javaxmlvalidationdtd

提问by Simon

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 threadbut besides the fact they are using .NET I doubt that this is a good solution.

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

Any input appreciated!

任何输入表示赞赏!

采纳答案by McDowell

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

在理想情况下,您可以使用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"));

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.

不幸的是,Sun 实现(至少从 Java 6 开始)不支持从 DTD 创建 Schema 实例。您也许能够追踪第 3 方实施。

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

最好的办法可能是在使用其他机制解析之前修改文档以包含 DTD。



You can use a transformerto insert a DTD declaration:

您可以使用转换器插入 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));

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

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



This StAXevent reader can do the job:

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

  }

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

它将在文档开始后立即发送给定的 DTD 声明并丢弃旧文档中的任何声明。

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.

请注意, XMLEventReader 可以形成执行验证的某些其他转换机制的源。



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

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

回答by J-16 SDiZ

You have to implement the EntityResolver, checkout this example.

你必须实现EntityResolver,结帐这个例子

回答by zachary

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

感谢您的帮助,但是如果根本没有指定 DOCTYPE 呢?在这种情况下,EntityResolver 不会帮助我,是吗?– 西蒙 2009 年 7 月 8 日 6:34

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

反对我自己的 DTD。我只想确保我收到的 XML 符合我的 DTD,而不仅仅是发件人指定的任何 DTD。– 西蒙 09 年 7 月 8 日,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

如果问题是您希望根据您的 dtd 而不是作者对其进行验证,您应该确保有明确的文档详细说明 doctype,以及 xml 文件中必须包含的内容