除了提供ContentHandler接口处理解析过程中的事件之外,SAX还提供了ErrorHandler接口,可以通过实现该接口来处理解析过程中出现的各种错误。这个接口与我们已经构造好的处理类的工作方式是相同的,但是它只定义了三个方法,通过这三个方法,SAX解析器可以处理和报告所有的错误情况。
每个方法都通过SAXParseException来接收出错信息或者发出错误警告信息。该对象保存了出现错误的行号,所处理文档的URI(可以是已解析的文档或者是文档中引用的外部文件)和普通异常的详细信息,例如错误信息和可输出的栈轨迹。另外,每个方法都可以抛出SAXException异常。乍看起来有点奇怪,异常处理方法还抛出异常?请记住,每个异常处理方法都接收解析异常。这可以是不会引起解析过程停止的警告信息,也可以是需要解决以后才能继续进行解析的严重错误,然而,回调方法仍然需要执行系统I/O或者其他的操作来抛出异常,而且还必须能够把这些操作中产生的问题沿着异常链向上发送。
举例来说,一般认为错误处理可以接收错误信息并将它们写入错误日志。这个回调方法必须能向本地文件系统中的错误日志文件添加错误信息,或者创建错误日志文件。如果在解析XML文档的过程中出现了警告信息,则错误处理方法会将该警告报告出来。本来警告是要向回调方法传递信息,然后继续解析XML文档的,然后,如果错误处理方法不能写入日志文件的话,它就必须能够通知解析器和应用程序让所有的解析活动中止。这可以通过捕获I/O异常,并重新抛出这些异常给应用程序,从而终止文档的解析过程。这种情形非常普遍,也是为何错误处理方法必须能够抛出异常的原因。如例:
public void warning(SAXParseException exception) throws SAXException { try{ FileWriter fw = new FileWriter("error.log"); BufferedWriter bw = new BufferedWriter(fw); bw.write("Warning" " + exception.getMessage() + "\n"); bw.flush(); bw.close(); fw.close(); }catch (IOException e) { throw new SAXException("Could not write to log file",e); }}
定义ErrorHandler的实现框架相当容易,并且可以使用和注册文档处理类一样的方法来注册错误处理类:
public class ParseXML1 { public static void main(String[] args) { try { XMLReader reader = XMLReaderFactory.createXMLReader(); reader.setContentHandler(new MyContentHandler()); reader.setErrorHandler(new MyErrorHandler()); //注册错误处理类 reader.parse(new InputSource(new FileInputStream( new File("/home/fuhd/apk/gw/com.application.zomato.apk/AndroidManifest.xml")))); } catch (SAXException e1) { e1.printStackTrace(); } catch(Exception e2){ e2.printStackTrace(); } }}
warning方法
当一个在XML1.0标准中定义的警告信息出现时,就要调用已注册的错误处理类中的warning方法。有好几种情况可以产生警告信息,然而它们都与DTD和文档的合法性有关。示例中的代码会将警告信息写入日志文件,在没有再次抛出SAXException的情况下,会继续完成解析过程。
public void warning(SAXParseException exception) throws SAXException { try{ FileWriter fw = new FileWriter("error.log"); BufferedWriter bw = new BufferedWriter(fw); bw.write("**Warning**\n"); bw.write("\tLine: "); bw.write(exception.getLineNumber()); bw.write("\n\tURI: "); bw.write(exception.getSystemId()); bw.write("\n\tMessage: "); bw.write(exception.getMessage()); bw.write("\n\n"); bw.flush(); bw.close(); fw.close(); }catch(IOException e){ throw new SAXException("Could not write to log file",e); }}
error方法
非致命错误(nonfatal error)是指解析过程中发生的,可恢复的但是违反了XML标准某些部分的错误。错误处理方法至少应该将其写入日志文件,因为它们虽然没有严重到要引起解析过程中止,但也应该通知应用程序的用户或管理员。
public void error(SAXParseExcption exception) throws SAXException { try{ Filewriter fw = new FileWriter("error.log"); BufferedWriter bw = new BufferedWriter(fw); bw.write("**Error**\n"); bw.write("\tLine: "); bw.write(exception.getLineNumber()); bw.write("\n\tURI: "); bw.write(exception.getSystemId()); bw.write("\n\tMessage: "); bw.write(exception.getMessage()); bw.write("\n\n"); bw.flush(); bw.close(); bw.close(); }catch(IOException e) { throw new SAXException("Could not write to log file", e); }}
fatalError方法
致命错误(fatal error)指的是使解析器必须中止的错误,一般都是XML文档中非格式良好的部分,它们的存在会使其后的解析要么是完全在浪费时间,要么在技术上根本不可能。当致命性错误出现时,错误处理方法必须通知用户或程序管理员,在默认情况下,也许会使应用程序突然停止。本例中,我们希望致命性错误出现时,还是和另两个回调方法类似,中止解析,并将错误信息再次抛出显示在屏幕上。
public void fatalError(SAXParseException exception) throws SAXException { try{ FileWriter fw = new FileWriter("error.log"); BufferedWriter bw = new BufferedWriter(fw); bw.write("**Fatal Error**\n"); bw.write("\tLine: "); bw.write(exception.getLineNumber()); bw.write("\n\tURI: "); bw.write(exception.getSystemId()); bw.write("\n\tMessage: "); bw.write(exception.getMessage()); bw.write("\n\n"); bw.flush(); bw.close(); bw.close(); //bail out throw new SAXException("Fatal Error! Check the log!"); }catch(IOException e){ throw new SAXException("Could not write to log file",e); }}