package javacodebook.xml.processing.dom.parse; import java.util.*; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXParseException; import org.xml.sax.SAXException; import org.w3c.dom.*; /** * Die ErrorCollector-Klasse implementiert das org.xml.sax.ErrorHandler * Interface und lässt sich somit sowohl bei SAX-Parsern als auch bei * DOM-Parsern als ErrorHandler registrieren. Im Wesentlichen sammeln * Objekte dieser Klasse Fehlermeldungen, die beim Parsen aufgetreten sind * und stellen diese in aufbereiterter Form zur Verfügung. */ public class ErrorCollector implements ErrorHandler { private Vector warnings = new Vector(); private Vector errors = new Vector(); private Vector fatalErrors = new Vector(); // dieses Objekt wird ausschließlich als Factory benutzt, um // DOM-Knoten zu instanziieren und Fehlermeldungen in XML // zur Verfügung stellen zu können. private Document domFactory = new org.apache.xerces.dom.DocumentImpl(); // Eine Methode, die von dem org.xml.sax.ErrorHandler Interface // gefordert wird. Falls ein ErrorCollector-Objekt bei einem Parser // registriert ist, wird sie jedesmal aufgerufen, fall eine Warnung // auftritt. public void warning(SAXParseException exception) throws SAXException { // die Meldungen der Warnung werden in dem Vector namens 'warnings' // aufbewahrt. warnings.add(exception.getMessage()); } // analog zur warning-Methode public void error(SAXParseException exception) throws SAXException { // die Meldungen der Fehler werden in dem Vector namens 'errors' // aufbewahrt. errors.add(exception.getMessage()); } // analog zur warning-Methode public void fatalError(SAXParseException exception) throws SAXException { // die Meldungen der fatalen Fehler werden in dem Vector namens 'fatalErrors' // aufbewahrt. fatalErrors.add(exception.getMessage()); } /** * Die Methode dient zum Zurücksetzen aller * Fehlermeldungen und Warnings. */ public void reset() { warnings.removeAllElements(); errors.removeAllElements(); fatalErrors.removeAllElements(); } /** * Die Methode liefert ein Element welches die Fehler- * meldungen wiederum in seinen Unterelementen * kapselt. Auf diese Weise können Fehlermeldungen * sehr flexibel weiterverarbeitet werden. * * @return org.w3c.dom.Element */ public Element getErrorMessagesAsXML() { return formatAsXML(errors, "errors"); } // siehe getErrorMessagesAsXML() public Element getWarningsMessagesAsXML() { return formatAsXML(warnings, "warnings"); } // siehe getErrorMessagesAsXML() public Element getFatalErrorMessagesAsXML() { return formatAsXML(fatalErrors, "fatalErrors"); } /** * Diese Methode liefert die Fehlermeldungen als einfachen leicht * formatierten Text. * * @return java.lang.String */ public String getErrorMessagesAsText() { return formatAsText(errors, "errors"); } // siehe getErrorMessagesAsText() public String getWarningsMessagesAsText() { return formatAsText(warnings, "warnings"); } // siehe getErrorMessagesAsText() public String getFatalErrorMessagesAsText() { return formatAsText(fatalErrors, "fatalErrors"); } /** * Diese Methode liefert die Fehlermeldungen in Form eines * Vectors von Strings. * * @return java.lang.String */ public Vector getErrorMessages() { return errors; } // siehe Methode getErrorMessages() public Vector getWarningsMessages() { return warnings; } // siehe Methode getErrorMessages() public Vector getFatalErrorMessages() { return fatalErrors; } /** * Diese Methode verpackt Fehlermeldungen eines Typs in * eine w3c-DOM-Element. Auf diese Weise können die Fehler- * meldungen sehr flexibel weiterverarbeitet werden. * * @param vectorWithStringElements * @param type * @return org.w3c.dom.Element */ private Element formatAsXML(Vector vectorWithStringElements, String type) { Element messages = domFactory.createElement("messages"); messages.setAttribute("type", type); Enumeration enum = vectorWithStringElements.elements(); while (enum.hasMoreElements()) { Element message = domFactory.createElement("message"); Text text = domFactory.createTextNode( (String) enum.nextElement()); message.appendChild(text); messages.appendChild(message); } return messages; } /** * Diese Methode formatiert Fehlermeldungen eines Typs als einfachen String * * @param vectorWithStringElements * @param type * @return java.lang.String */ private String formatAsText(Vector vectorWithStringElements, String type) { if(vectorWithStringElements.size()==0)return "no "+type+" occured"; String returnString = "The following " + type + " have occured"; Enumeration enum = vectorWithStringElements.elements(); while (enum.hasMoreElements()) { String message = (String) enum.nextElement(); returnString = returnString + "\n\t* " + message + "\n"; } return returnString; } // Einige Methoden, um den Verlauf des Parsing-Prozesses beurteilen // zu können, ohne die Fehlermeldungen zu erfragen. public boolean hasWarnings() { if(warnings.size()>0) return true; else return false; } public boolean hasErrors() { if(errors.size()>0) return true; else return false; } public boolean hasFatalErrors() { if(fatalErrors.size()>0) return true; else return false; } public boolean anyProblems() { if (hasWarnings() || hasErrors() || hasFatalErrors()) return true; else return false; } } --- Neue Klasse --- package javacodebook.xml.processing.jdom.parse; import java.io.*; import org.jdom.*; import org.jdom.input.SAXBuilder; import javacodebook.xml.processing.dom.parse.ErrorCollector; public class ValidatingJDOMParseUtil { private static final String USAGE = "\nBenutzerhinweis: javacodebook.xml.processing.jdom.parse.ValidatingJDOMParseUtil " + "\n\nwobei\n\n\n" + "die URI ist, unter der ein XML-Dokument zu finden ist das geparst und validiert werden soll.\n"; public static void main(String[] args) { if (args.length != 1) { System.out.println(getUsage()); return; } String documentLocation = args[0]; // Da JDOM JAXP benutzt, was widerum als Default-Parser den Crimson Parser benutzt, // wir aber Xerces verwenden wollen, muss folgende System-Property gesetzt werden, damit // JAXP und somit JDOM den Xerces Parser verwendet. // Im Gegensatz zu Crimson validiert Xerces sowohl gegen DTDs als auch gegen Schemata System.setProperty("javax.xml.parsers.SAXParserFactory","org.apache.xerces.jaxp.SAXParserFactoryImpl"); ValidatingJDOMParseUtil validatingJDOMParseUtil = new ValidatingJDOMParseUtil(); // Es wird ein ErrorCollector aus dem processing.dom.parse-Beispiel // instanziiert. ErrorCollector errorCollector = new ErrorCollector(); // parsen des Dokuments Document document = validatingJDOMParseUtil.parseDocument(documentLocation, errorCollector); // Eventuell aufgetretene Fehler werden verarbeitet boolean isValid = validatingJDOMParseUtil.processErrors(errorCollector); // Falls das Dokument valide ist, wird es verarbeitet if (isValid) { validatingJDOMParseUtil.processDocument(document); } else { System.out.println( "Dokument wurde nicht verarbeitet, da es nicht valide ist"); } } /** * Diese Methode parst eine URI in ein JDOM-Document und * validiert es dabei. * * @param documentLocation * @return org.jdom.Document */ public Document parseDocument(String documentLocation, ErrorCollector errorCollector) { // Ein SAXBuilder-Objekt wird erzeugt. // Dadurch dass true an den Konstruktor übergeben wird // ist die Validierung eingeschaltet. SAXBuilder builder = new SAXBuilder(true); // Beim SAXBuilder wird der ErrorCollector registriert. builder.setErrorHandler(errorCollector); try { // Der SAXBuilder erstellt von der URI ein Document-Object Document document = builder.build(documentLocation); if (document != null) { // Falls keine Exceptions aufgetreten sind ist das Dokument valide. System.out.println(documentLocation + " ist valide"); } return document; } // Hier werden well-formedness or Validitätsfehler gefangen. catch (JDOMException e) { System.out.println(documentLocation + " ist nicht valide."); System.out.println(e.getMessage()); } catch (Exception e) { System.out.println("Fehler bei der Verarbeitung des Dokuments: " + e); } return null; } /** * Die Methode liefert die Pseudoverarbeitung eines Dokuments. * Es wird der Dokumententyp in den Ausgabestrom geschrieben. * * @param document */ public void processDocument(Document document) { // Das Dokument kann nun verarbeitet werden if(document==null)return; if(document.getDocType()!=null) { System.out.println("Der Dokumententyp (SystemID) ist: " + document.getDocType().getSystemID()); } } /** * Die Methode verarbeitet Fehlermeldungen, die vom ErrorCollector-Objekt * gesammelt wurden. Sie liefert einen boolschen Wert zurück, der besagt, * ob das Dokument valide war oder nicht. * * @param errorCollector * @return boolean */ public boolean processErrors(ErrorCollector errorCollector) { // Falls Probleme aufgetreten sind, werden die entsprechenden // Meldungen in die Standardausgabe geschrieben. if (errorCollector.anyProblems()) { System.out.println(errorCollector.getWarningsMessagesAsText()); System.out.println(errorCollector.getErrorMessagesAsText()); System.out.println(errorCollector.getFatalErrorMessagesAsText()); return false; } else { System.out.println("Das Dokument entspricht Schema bzw. DTD"); return true; } } public static String getUsage() { return USAGE; } }