Подтвердить что ты не робот

Проверка файла XML на локальный DTD файл с помощью Java

Как проверить файл XML на DTD, который хранится локально в виде файла? XML файл не имеет никакого объявления DOCTYPE (или может иметь тот, который затем должен быть переопределен). Я просмотрел эту тему, но помимо того, что они используют .NET, я сомневаюсь, что это хорошее решение.

Любой вход оценивается!

4b9b3361

Ответ 1

В идеальном мире вы сможете проверить с помощью 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) не включает поддержку для создания экземпляра Schema из DTD. Возможно, вы сможете отслеживать стороннюю реализацию.

Лучше всего изменить документ, чтобы включить 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, если у вас есть эта опция.

Ответ 2

im довольно уверен, что все вышеизложенное будет работать.

Спасибо за вашу помощь, но что, если ни один DOCTYPE не был указан в все? EntityResolver не помог бы мне в этом случае, не так ли? - Simon Июн 07, 2009 в 6:34

@Bluegene: Что вы проверяете, если нет DOCTYPE? - J-16 SDiZ 8 июля 2009 в 7:12

Против моего собственного DTD. Я просто хочу убедиться, что XML, который я получаю соответствует моему DTD, а не только DTD, который указывает отправитель. - Саймон Джуль 8 '09 в 23:09

Если проблема заключается в том, что вы хотите, чтобы она была проверена против вашего dtd, а не у авторов, вы должны убедиться, что есть четкая документация, в которой подробно описывается тип doctype, и что должно быть в файле xml