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.dom.parse; import org.w3c.dom.*; import org.xml.sax.*; /** * Die ValidatingDOMParseUtil-Klasse parst ein XML-Dokument und kann * dabei sowohl gegen DTDs als auch gegen XML-Schemata validieren. * Um Fehler, die beim parsen von nicht validem XML aufgetreten sind * zu analysieren, bedient sie sich einem Objekt der Klasse * ErrorCollector, dass das SAX-ErrorHandler-Interface implementiert. */ public class ValidatingDOMParseUtil { private static final String USAGE = "\nBenutzerhinweis: javacodebook.xml.processing.dom.parse.ValidatingDOMParseUtil " + "\n\nwobei\n\n\n" + "die URI ist, unter der ein XML-Dokument zu finden ist das geparst und validiert werden soll.\n"; /** * Im wesentlichen passieren 3 Schritte in der main-Methode. Zunächst wird ein * Dokument geparst und validiert. Dann werden die Fehler die beim Parsen auf- * getreten sind analysiert und zum Schluss wird, falls keine fatalen Fehler * aufgetreten sind, das Dokument verarbeitet. * * @param args */ public static void main(String[] args) { if (args.length != 1) { System.out.println(getUsage()); System.exit(1); } String documentLocation = args[0]; ValidatingDOMParseUtil validatingDOMParseUtil = new ValidatingDOMParseUtil(); // Es wird ein Objekt unserer ErrorHandler-Implementierung // instanziiert. ErrorCollector errorCollector = new ErrorCollector(); // das Dokument wird geparst Document document = validatingDOMParseUtil.parseDocument(documentLocation, errorCollector); // Eventuell aufgetretene Fehler werden verarbeitet boolean isValid = validatingDOMParseUtil.processErrors(errorCollector); // Falls das Dokument valide ist, wird es verarbeitet if(isValid) { validatingDOMParseUtil.processDocument(document); } else { System.out.println("Dokument wurde nicht verarbeitet, da es nicht valide ist"); } } public Document parseDocument(String documentLocation, ErrorCollector errorCollector) { // Ein DOMParser-Objekt wird instanziiert. org.apache.xerces.parsers.DOMParser parser = new org.apache.xerces.parsers.DOMParser(); try { // über die die setFeature-Methode des Parser-Objektes kann // die Validierung eingeschaltet werden. parser.setFeature("http://xml.org/sax/features/validation", true); // Das ErrorHandler-Objekt wird beim Parser als // ErrorHandler registriert. parser.setErrorHandler(errorCollector); // Das Dokument, dass als Parameter übergeben // wurde, wird geparst. parser.parse(documentLocation); } catch (Exception e) { System.out.println("Dokument konnte nicht verarbeitet werden: " + e + "\n" + errorCollector.getFatalErrorMessagesAsText()); } // das geparste Dokument kann von dem Parser geholt werden. return parser.getDocument(); } /** * 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; } } /** * Die Methode liefert die Pseudoverarbeitung eines Dokuments. * Es werden alle Namen der Elemente innerhalb der Root-Elements * in die Standardausgabe geschrieben. * * @param document */ public void processDocument(Document document) { Element root = document.getDocumentElement(); NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { System.out.println(node.getNodeName()); } } } public static String getUsage() { return USAGE; } }