读取和操纵 XML 文件的标准方法是 DOM(“文档对象模型”)。遗憾的是,这种方法需要读取整个文件并将它存储到树结构中,因而效率不高、缓慢,并且会过度使用资源。
什么是 SAX
读取和操纵 XML 文件的标准方法是 DOM(“文档对象模型”)。遗憾的是,这种方法需要读取整个文件并将它存储到树结构中,因而效率不高、缓慢,并且会过度使用资源。
一种替代方法是使用 Simple API for XML 或 SAX。SAX 允许正在读取文档时处理该文档,这避免了在采取操作之前需要等待存储文档的所有内容。
SAX 是由 XML-DEV 邮件列表的成员开发的,Java 版本由 David Megginson 维护。他们的目的是提供一种更自然的方法来使用 XML,这种方法不会涉及到使用 DOM 的那种开销。
结果是基于事件的 API。解析器将事件(譬如,元素的开始或结束)发送给处理信息的事件处理程序。然后,应用程序自己可以处理数据。虽然原始文档保持不变,但 SAX 提供了操纵数据的方法,然后会将该方法导向另一个过程或文档。
对于 SAX,没有官方的标准;万维网(W3C)或其它官方组织不维护 SAX,但在 XML 社区中,它是一个事实上的标准。
SAX 处理是如何工作的
SAX 分析经过其的 XML 流,这非常象老式的自动收报机纸条。考虑以下 XML 代码片断:
|
一般情况下,SAX 处理器分析这段代码将生成以下事件:
|
SAX API 允许开发者捕获这些事件,并对它们进行操作。
SAX 处理涉及以下几步:
- 创建事件处理程序。
- 创建 SAX 解析器。
- 将事件处理程序分配给解析器。
- 对文档进行解析,将每个事件发送给处理程序。
在SAX与DOM之间,如何选择
选择 DOM 还是 SAX,这取决于几个因素:
- 应用程序的目的:如果必须对数据进行更改,并且作为 XML 将它输出,则在大多数情况下,使用 DOM。与使用 XSL 转换来完成的简单结构更改不一样,如果是对数据本身进行更改,则尤其应该使用 DOM。
- 数据的数量:对于大文件,SAX 是更好的选择。
- 将如何使用数据:如果实际上只使用一小部分数据,则使用 SAX 将数据抽取到应用程序中,这种方法更好些。另一方面,如果知道将需要向后引用已经处理过的信息,则 SAX 可能不是正确的选择。
- 需要速度:通常,SAX 实现比 DOM 实现快。
记住 SAX 和 DOM 不是互斥的,这一点很重要。可以使用 DOM 来创建事件的 SAX 流,可以使用 SAX 来创建 DOM 树。事实上,大多数解析器实际常常使用 SAX 来创建 DOM 树!
使用 JAXP 来创建解析器
接下来我们来看一下JAXP的SAX Parser是怎么样工作的。
首先声明 XMLReader xmlReader。然后使用 SAXParserFactory 来创建 SAXParser。正是 SAXParser 给您了 XMLReader。
|
设置内容处理程序
一旦创建了解析器,则需要将 SurveyReader 设置为内容处理程序,以便于其接收事件。
xmlReader 的 setContentHandler() 方法完成这项工作。
|
当然,对于内容处理程序,这不是唯一的选项。
解析 InputSource
为了对文件进行实际地解析,需要 InputSource。这个 SAX 类封装了所有将要处理的数据,所以不必担心它来自哪里。
现在,准备对文件进行实际解析。应用程序将封装在 InputSource 中的文件传递给 parse(),然后应用程序会继续运行。
|
可以编译和运行该程序,但这时应该什么也没有发生,因为应用程序还没有定义任何事件。
创建 ErrorHandler
当然总会有可能在试图进行解析时,数据有问题。在这样的情况下,有一个处理程序来处理错误和内容将是有帮助的。
就如同创建内容处理程序一样,可以创建出错处理程序。通常,将作为 ErrorHandler 的单独实例来创建它,但为了简化该示例,出错处理正是包含在 SurveyResults 中。由于该类继承了 DefaultHandler 且没有扩展 ContentHandler,所以这种双重用法是可能的。
需要关注的事件有三个:警告、错误和致命错误。
|
SAX 事件
以下事件是常用的;它们都在 org.xml.sax 包的 HandlerBase 类中定义。
- startDocument 表示文档开始。
- endDocument 表示文档结束。
- startElement 表示元素开始。当一对标记中的起始标记中的所有内容被处理后,解析器 激发此事件。包括了标记名和其属性。
- endElement 表示元素结束。
- characters 包含字符数据,类似于 DOM 的一个 Text 节点。
还有更多的 SAX 事件:
- ignorableWhitespace 此事件类似于我们前面所讨论的无用 DOM 节点。它与 character 事件的区别,好处是:如果您不需要空格符,您可以通过忽略这个事件来忽略所有的空格符。
- warning、error 和 fatalError 这三个事件表示了解析错误。您可根据需要来响应它们。
- setDocumentLocator 这个事件允许您存储一个 SAX 的 Locator 对象。Locator 对象可以用来找出在文档中确切发生事件的地方。