示例文件
如何构造这样一个应用程序,它使用 SAX 来记录一组用户的答案,这些用户被要求就他们与外星人的遭遇接受调查。
下面是调查表:
答案将存储在一个 XML 文件中:
<?xml version="1.0"?>
<surveys>
<response username="bob">
<question subject="appearance">A</question>
<question subject="communication">B</question>
<question subject="ship">A</question>
<question subject="inside">D</question>
<question subject="implant">B</question>
</response>
<response username="sue">
<question subject="appearance">C</question>
<question subject="communication">A</question>
<question subject="ship">A</question>
<question subject="inside">D</question>
<question subject="implant">A</question>
</response>
<response username="carol">
<question subject="appearance">A</question>
<question subject="communication">C</question>
<question subject="ship">A</question>
<question subject="inside">D</question>
<question subject="implant">C</question>
</response>
</surveys>
创建事件处理程序
在应用程序能够使用 SAX 来处理 XML 文档之前,它必须首先创建一个事件处理程序。
SAX 提供了一个类DefaultHandler
,应用程序可以扩展该类。要使用 SAX 来进行正确的解析,需要对处理程序的方法进行特殊调用,而这些调用
不能是静态的。这意味着您需要特别地实例化处理程序对象,因此下面将提供简单的
概述,以防您还不习惯使用对象。当新的对象被创建时,它会寻找要执行的任何类构造函数。例如:
import org.xml.sax.helpers.DefaultHandler; public class SurveyReader extends DefaultHandler { public SurveyReader() { System.out.println("Object Created."); } public void showEvent(String name) { System.out.println("Hello, "+name+"!"); } public static void main (String args[]) { SurveyReader reader = new SurveyReader(); reader.showEvent("Nick"); } }
当
main
方法执行时,它会创建SurveyReader
类的一个新实例。这样会导致构
造函数执行,从而输出Object Created
(以及下面的问候语)。然后您可以使用
该对象来执行showEvent()
方法。
直接指定 SAX 驱动程序
在准备好事件处理程序之后,下一步就是使用 SAX 驱动程序来创建解析器,或
XMLReader
。
您可以使用三种方式中的任一种来创建解析器:
- 直接调用驱动程序
- 允许在运行时指定驱动程序
- 将驱动程序作为
createXMLReader()
的参数来传递
如果知道 SAX 驱动程序的类名称,您可以直接调用它。例如,如果该类是(虚构的)com.nc.xml.SAXDriver
,您可以使用如下代码:
try {
XMLReader xmlReader = new com.nc.xml.SAXDriver();
} catch (Exception e) {
System.out.println("Can't create the parser: " + e.getMessage());
}
来直接创建 XMLReader
。
您还可以使用系统属性来使得应用程序更灵活。例如,您可以在运行应用程序时,从命令行
将类名称作为 org.xml.sax.driver
属性的值来指定。
java -Dorg.xml.sax.driver=com.nc.xml.SAXDriver SurveyReader
(注意,-D
后面 不 应该有空格。)
这使得该信息对 XMLReaderFactory
可用,因此您可以使用这样的代码:
try {
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
} catch (Exception e) {
System.out.println("Can't create the parser: " + e.getMessage());
}
如果您知道驱动程序名称,还可以将它作为 createXMLReader()
的参数来直接传递。
创建解析器
这个例子使用了一对类 SAXParserFactory
和 SAXParser
来创建解析器,因此您不
必知道驱动程序本身的名称。
首先声明 XMLReader
、xmlReader
,然后使用 SAXParserFactory
来创建一个 SAXParser
。 XMLReader
是由 SAXParser
提供的。
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.XMLReader;
public class SurveyReader extends DefaultHandler
{
public SurveyReader() {
}
public static void main (String args[]) {
XMLReader xmlReader = null;
try {
SAXParserFactory spfactory = SAXParserFactory.newInstance();
SAXParser saxParser = spfactory.newSAXParser();
xmlReader = saxParser.getXMLReader();
} catch (Exception e) {
System.err.println(e);
System.exit(1);
}
}
}
验证与非验证解析器
要使用 XML 文档做任何事情,你都必须读取其中的信息。做这个工作的应用程序称为解析器。
解析器的两种类型分别是:非验证 和 验证。
- 非验证解析器是适用于格式良好(well-formed)文档的解析器。 它读取每个信息
单元,并将其添加到文档 —— 或者在 SAX 应用程序的情况下处理事件,而不管实际
的结构和内容如何。 - 另一方面,验证解析器根据已定义的语法检查 XML 文档的内容和结构。 有时,这个
语法是文档类型定义(Document Type Definition,DTD)的形式,但是近来它更
可能在 XML Schema 文档中定义。在任一种情况下,解析器都会检查文档,以确保每
个元素和属性都已定义,并且包含正确类型的内容。例如,您可以指定每个order
都有一个
(订单)status(状态)
。 如果在没有语法定义的情况下尝试创建文档,
验证解析器将会提示错误。
已经由验证解析器检验过的文档被认为是有效的文档。
设置验证选项
对于本教程,您将不会验证调查结果,因此可以通过设置 validating
属性,关闭
SAXParserFactory
创建的任何解析器的验证特性:
...
public static void main (String args[]) {
XMLReader xmlReader = null;
try {
SAXParserFactory spfactory =
SAXParserFactory.newInstance();
spfactory.setValidating(false);
SAXParser saxParser =
spfactory.newSAXParser();
xmlReader = saxParser.getXMLReader();
} catch (Exception e) {
System.err.println(e);
System.exit(1);
}
}
...
设置内容处理程序
解析器必须将它的事件发送到一个
ContentHandler
。为简单起见,SurveyReader
将同时用作主应用程序和内容处理程序,因此创建它的一个新实例,并使用XMLReader
的setContentHandler()
方法来将它设置为ContentHandler
:... xmlReader = saxParser.getXMLReader(); xmlReader.setContentHandler(new SurveyReader()); } catch (Exception e) { ...
当然,这是内容处理程序的唯一选项。
解析 InputSource
要实际解析一个文件(或解析其他任何内容!)您需要一个
InputSource
。这个 SAX
类包装了你要处理的任何数据,因此您不必(太)关心它来自何处。现在您就准备好实际解析文件了。
parse()
方法接受该文件,将它包装到InputSource
中,然后处理它,同时将每个事件发送给ContentHander
。... import org.xml.sax.InputSource; ... xmlReader = saxParser.getXMLReader(); xmlReader.setContentHandler(new SurveyReader()); InputSource source = new InputSource("surveys.xml"); xmlReader.parse(source); } catch (Exception e) { ...
设置 ErrorHandler
您可以像创建内容处理程序一样创建一个错误处理程序。通常,您会把这个处理程序创建
为ErrorHandler
的一个单独的实例,但是为简化这里的例子,我们将把错误处理直
接包括在SurveyResults
中。这种双重用途是可以实现的,因为该类扩展了DefaultHandler
,因而同时包括了ContentHandler
方法和ErrorHandler
方法的实现。设置新的
ErrorHandler
就像设置ContentHandler
一样:... xmlReader.setContentHandler(new SurveyReader()); xmlReader.setErrorHandler(new SurveyReader()); InputSource source = new InputSource("surveys.xml"); ...
同样,如果此时运行应用程序,仍然应该什么事情也不会发生,因为每个事件的默认实现
不做任何事情。在下一节中,我们将考察添加新的实现来处理解析期间发生的事件。