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

发布于 2024-07-26 04:41:27 字数 266 浏览 1 评论 0原文

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

任何意见表示赞赏!

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

Any input appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

拧巴小姐 2024-08-02 04:41:27

在理想的情况下,您可以使用 验证器。 像这样的事情:

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。


您可以使用转换器插入 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 模式进行验证会容易得多。

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.

所谓喜欢 2024-08-02 04:41:27

我很确定前面提到的东西会起作用..

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

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

针对我自己的 DTD。 我只是想确保我收到的 XML
符合我的 DTD,而不仅仅是发件人指定的任何 DTD。 ——西蒙·朱尔
09 年 8 月 23:09

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

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

凹づ凸ル 2024-08-02 04:41:27

您必须实现 EntityResolver,请查看此示例< /a>.

You have to implement the EntityResolver, checkout this example.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文