W idealnym świecie można sprawdzić poprawność za pomocą Validator. Coś takiego:
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"));
Niestety, implementacja Sun (przynajmniej, jak Java 6) nie obejmują wsparcie dla tworzenia instancji schematu z DTD. Być może uda Ci się wyśledzić implementację innej firmy.
Najlepszym rozwiązaniem może być zmiana dokumentu tak, aby zawierał DTD przed analizą za pomocą innego mechanizmu.
Można użyć transformer wstawić deklaracji 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));
... ale to nie wydaje się, aby zastąpić istniejący deklaracji DTD.
Ten StAX czytelnik zdarzenie może wykonać zadanie:
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;
}
}
Będzie wysłać daną deklarację DTD tuż po rozpoczęciu dokumentu i wyrzucić każdy ze starego dokumentu.
Wykorzystanie Demo:
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
Zauważ, że XMLEventReader mogłyby stanowić źródło dla innego mechanizmu transformacji, który przeprowadził weryfikację.
Znacznie łatwiej byłoby sprawdzić poprawność za pomocą schematu W3, jeśli masz taką opcję.
Dziękuję bardzo za wyczerpującą odpowiedź, która bardzo mi pomaga. Spróbuję przekonwertować DTD na schemat W3, ponieważ mogę wtedy użyć Validatora Słońca. – Simon
mój plik XML nie zawiera deklaracji DOCTYPE. i parsuję plik używając SAXParser w systemie Android. DTD generowane przeze mnie. Jak mogę sprawdzić poprawność pliku XML za pomocą mojego DTD, w analizie SAX? –
@ Chusbu - byłoby lepiej, gdybyś zadał nowe pytanie. – McDowell