Ответ 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, если у вас есть эта опция.