有效使用 SAX InputSource

转自:http://www.ibm.com/developerworks/cn/xml/tips/x-tipsaxis/index.html

当您使用 SAX API 时,所有输入都从使用 org.xml.sax.InputSource 类开始。这个类包含在 SAX API 中,并且提供了输入规范(通过类似于文件或 I/O 流的标准 Java 构造),同时还提供一个公用的系统标识。 接着,SAX 在解析时从 InputSource 抽取这些信息,从而能够解析外部实体以及其它特定于文档来源的资源。

类似地,当您对 SAX 使用封装器(类似于 JAXP API)时,可以调用不同方法。最后,解析使用 SAX InputSource。例如,考虑 清单 1 中所示的代码段,它使用 JAXP 来启动 SAX 解析。


清单 1. 将 JAXP 用于 SAX 解析

[java] view plaincopy
 
  1. SAXParserFactory spf = SAXParserFactory.newInstance();  
  2. SAXParser parser = spf.newSAXParser();  
  3. parser.parse(myFile, myHandler);  

即使输入了 java.io.File 文件,它也会在被转交给底层 SAX 实现之前转换成 SAX InputSource 。之所以发生这个转换,是因为这个 JAXP 代码最终访问 org.xml.sax.XMLReader 类,该类只为启动解析提供 清单 2 中所示的两个特征符。


清单 2. 用于 XMLReader 的解析入口点

[java] view plaincopy
 
  1. public void parse(InputSource inputSource);  
  2. public void parse(String systemID);  

在此基础上,大多数 SAX 解析器实现(如 Apache Xerces)实际上将字符串系统标识转换为 InputSource ,并将它分配给接收 InputSource 的 parse() 版本。无论您如何编码自己的应用程序,SAX 最终都接收 InputSource 来用于解析。但是,并非所有这样处理的方法都同等地好。

为了避免您代码中出现令人不快的意外,最好直接使用 SAX InputSource 类,而不是让 JAXP 或 SAX 为您处理这个任务。因为实现必须要处理每种可能的情况,所以您常常会看到构造 InputSource 实例的代码,类似于 清单 3 中所示。


清单 3. 一般的 InputSource 构造方法

[java] view plaincopy
 
  1. InputSource inputSource = new InputSource();  
  2. // May be a null parameter  
  3. inputSource.setByteStream(inputStream);  
  4. // May be a null parameter  
  5. inputSource.setCharacterStream(reader);  
  6. // May be a null parameter  
  7. inputSource.setSystemId(systemId);  
  8. // May be a null parameter  
  9. inputSource.setPublicId(publicId);  
  10. // Derived parameter  
  11. inputSource.setEncoding(encoding);  

正如您从注释中看到的,这些方法中的许多被传递了 null 参数。虽然执行这些方法不会花费很多时间,但 XML 解析应用程序中的每一秒都很关键;遗憾的是,这些不执行任何操作的方法浪费了宝贵的时间。通过自行构造InputSource 实例,您可以将这个过程简化为一至两个方法调用,如 清单 4 所示。


清单 4. 改进 InputSource 构造

[c-sharp] view plaincopy
 
  1. InputSource inputSource = new InputSource(myInputStream);  
  2. inputSource.setSystemId("http://www.oreilly.com");  
  3. inputSource.setEncoding("UTF-8");  

我还使用了 setEncoding() 方法来通知 SAX 解析器使用何种编码;在涉及国际化或使用多字节字符集的 XML 应用程序中,这一点很重要。

但是,这里产生了另一个问题:对于字符编码,用手工设置字符编码的编码与所提供的输入流(通过java.io.InputStream 或 java.io.Reader )所用的编码 不同 ,这种情况很常见。如果这些编码不匹配,就可能发生各种解析问题。要避免这种情况,请始终用 Java InputStream 创建您的 InputSource ,而不要用 Reader 或String 系统标识(这些都是 JAXP API 的可能选项)。当您提供 InputStream 时,SAX 实现将流封装在InputStreamReader 中;然后 SAX 自动从流中检测正确的字符编码。随后,您可以省略 setEncoding() 步骤,再次减少方法调用。结果是应用程序运行更快了,并且字符编码始终正确。

原文地址:https://www.cnblogs.com/handsome1013/p/5124705.html