使用Java验证针对本地DTD文件的XML文件

Sim*_*mon 24 java xml validation dtd

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

任何输入赞赏!

McD*_*ell 25

在理想的世界中,您可以使用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"));
Run Code Online (Sandbox Code Playgroud)

不幸的是,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));
Run Code Online (Sandbox Code Playgroud)

......但这似乎并没有取代现有的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;
    }

  }
Run Code Online (Sandbox Code Playgroud)

它将在文档开始后立即发送给定的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
Run Code Online (Sandbox Code Playgroud)

请注意,XMLEventReader可以构成执行验证的其他转换机制的源.


如果您有这个选项,使用W3架构验证会容易得多.