本文假設(shè)讀者對XML有些了解
首先,先給出一個比較基本的處理xml文件的程序。你不必細(xì)看,直接跳過即可。需要時可以返回來看。
Echo01.java
import java.io.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
public class Echo01 extends DefaultHandler
{
StringBuffer textBuffer;
public static void main(String argv[])
{
if (argv.length != 1) {
System.err.println("Usage: cmd filename");
System.exit(1);
}
// Use an instance of ourselves as the SAX event handler
DefaultHandler handler = new Echo01();
// Use the default (non-validating) parser
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// Set up output stream
out = new OutputStreamWriter(System.out, "UTF-8");
// Parse the input
SAXParser saxParser = factory.newSAXParser();
saxParser.parse( new File(argv[0]), handler);
} catch (Throwable t) {
t.printStackTrace();
}
System.exit(0);
}
static private Writer out;
//===========================================================
// SAX DocumentHandler methods
//===========================================================
public void startDocument()
throws SAXException
{
emit("<?xml version='1.0' encoding='UTF-8'?>");
nl();
}
public void endDocument()
throws SAXException
{
try {
nl();
out.flush();
} catch (IOException e) {
throw new SAXException("I/O error", e);
}
}
public void startElement(String namespaceURI,
String sName, // simple name
String qName, // qualified name
Attributes attrs)
throws SAXException
{
echoText();
String eName = sName; // element name
if ("".equals(eName)) eName = qName; // not namespaceAware
emit("<"+eName);
if (attrs != null) {
for (int i = 0; i < attrs.getLength(); i++) {
String aName = attrs.getLocalName(i); // Attr name
if ("".equals(aName)) aName = attrs.getQName(i);
emit(" ");
emit(aName+"=\""+attrs.getValue(i)+"\"");
}
}
emit(">");
}
public void endElement(String namespaceURI,
String sName, // simple name
String qName // qualified name
)
throws SAXException
{
echoText();
String eName = sName; // element name
if ("".equals(eName)) eName = qName; // not namespaceAware
emit("</"+eName+">");
}
public void characters(char buf[], int offset, int len)
throws SAXException
{
String s = new String(buf, offset, len);
if (textBuffer == null) {
textBuffer = new StringBuffer(s);
} else {
textBuffer.append(s);
}
}
//===========================================================
// Utility Methods ...
//===========================================================
// Display text accumulated in the character buffer
private void echoText()
throws SAXException
{
if (textBuffer == null) return;
String s = ""+textBuffer;
emit(s);
textBuffer = null;
}
// Wrap I/O exceptions in SAX exceptions, to
// suit handler signature requirements
private void emit(String s)
throws SAXException
{
try {
out.write(s);
out.flush();
} catch (IOException e) {
throw new SAXException("I/O error", e);
}
}
// Start a new line
private void nl()
throws SAXException
{
String lineEnd = System.getProperty("line.separator");
try {
out.write(lineEnd);
} catch (IOException e) {
throw new SAXException("I/O error", e);
}
}
}
從程序中可以看出,解析一個XML文件的核心語句是下面一部分:
// Use an instance of ourselves as the SAX event handler
DefaultHandler handler = new Echo01();
// Use the default (non-validating) parser
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// Set up output stream
out = new OutputStreamWriter(System.out, "UTF-8");
// Parse the input
SAXParser saxParser = factory.newSAXParser();
saxParser.parse( new File(argv[0]), handler);
} catch (Throwable t) {
t.printStackTrace();
}
先是創(chuàng)建一個SAXParserFactory工廠類的實(shí)例,然后通過SAXParser saxParser = factory.newSAXParser(); 這個工廠類的方法創(chuàng)建了一個saxParser。將xml文件(new File(argv[0]))和一個Sax Event Handler(handler)(在這個程序里面,這個Handler其實(shí)是本身這個類,這個類繼承了org.xml.sax.helpers.DefaultHandler 這個類,并且在前面初始化了它:DefaultHandler handler = new Echo01(); )傳遞給它,讓它進(jìn)行解析。
關(guān)于xml文件的解析過程中的處理全部在Handler里面實(shí)現(xiàn)。一般Parser接受的是DefaultHandler或者HandlerBase這兩個類。 這個例子里面的類是繼承DefaultHandler這個虛類的。看下圖:

而DefaultHandler是實(shí)現(xiàn)了EntityResolver, DTDHandler, ContentHandler, ErrorHandler四個接口的虛類。分別定義了如下的方法:

不同的方法,在不同的時候被Parser調(diào)用,(這個不同的時候就是Event-based)
詳細(xì)介紹:(暫略)
DefualtHandler的UML圖如下:
看完Handler,再轉(zhuǎn)過頭去看Parser,在代碼里面用的是SAXParser(SAXParser saxParser)
仔細(xì)看里面的代碼


你會發(fā)現(xiàn),其實(shí)它并沒有自己完成解析的工作,而是Wrap了另二個類XMLReader和Parser來完成解析工作。原來SAXParser只是起到一個Adapter的工作而已。
UML:

那我們?nèi)タ纯?/SPAN>Parser(org.xml.sax.Parser)去,

看到Parser的代碼,你會大失所望。原來Parser也只是一個空殼子而已

圖中你可以看到經(jīng)過層層查找的Parser只是一個接口而已。
回想一下前面看到生成解析器代碼的時候
使用了工廠模式
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// Set up output stream
out = new OutputStreamWriter(System.out, "UTF-8");
// Parse the input
SAXParser saxParser = factory.newSAXParser();
saxParser.parse( new File(argv[0]), handler);
完全由SAXParserFactory 這個類來控制產(chǎn)生的Parser的類型。我們只是拿來用就可以了。秘密一定藏在里面。

看到代碼,發(fā)現(xiàn)原來這個工廠自己也是一個虛類,連返回的工廠的實(shí)例都是該虛工廠的一個實(shí)現(xiàn)而已。
再去看真正的實(shí)現(xiàn)org.apache.crimson.jaxp.SAXParserFactoryImpl

發(fā)現(xiàn)它又wrap了SAXParserImpl,可知SAXParserImpl是SAXParser的一個子類。
繼續(xù)追蹤下去,因?yàn)?/SPAN>SAXParserImpl繼承了SAXParser,所以它也繼承了SAXParser的方法。在SAXParserImpl體內(nèi),并沒有發(fā)現(xiàn)覆寫掉parser方法的地方,所以SAXParserImpl的parser也就是SAXParser的那個parser,呵呵,是不是有點(diǎn)繞口令的味道?那么怎么我們繞了半天,又回去了呢。再仔細(xì)看看SAXParser的parser方法

可以看到其實(shí)在里面的Parser parser這個實(shí)例是調(diào)用了this.getParser()這個方法來得到的。再看看SAXParser里面的getParser方法

是不是有點(diǎn)感覺了? 對了,其實(shí)這個方法就是留給繼承了SAXParser的SAXParserImpl來實(shí)現(xiàn)的,這樣,SAXParser的子類就可以自由的改換Parser。只要改寫掉getParser方法就可以了。
急忙去看SAXParserImpl的getParser這個方法

你會發(fā)現(xiàn)你又上當(dāng)了,這里又給出了很曖昧的代碼,并不是我們所猜想的那樣是一個真正的實(shí)現(xiàn),再仔細(xì)看看。 注釋里面有這么句話:Adapt a SAX2 XMLReader into a SAX1 Parser。
XMLReader,是不是很熟?想想看哪里看到過的?對了,剛剛在SAXParser體內(nèi)Wrap的二個類,一個是我們追蹤至今的Parser,另一個就是XMLReader,原來這個XMLReader才是才是現(xiàn)在在用的SAX2解析器,而為了保持對以前系統(tǒng)的兼容才保留了SAX1解析器Parser,但其實(shí)是通過對XMLReader的Wrap得到的。只是個Adapte而已。
好了,現(xiàn)在可以集中火力去查找XMLReader了。有了剛剛的經(jīng)驗(yàn),很容易的,我們發(fā)現(xiàn),和Parser一樣,XMLReader也是一個接口:


很容易的,我們找到XMLReaderImpl

和里面的parse方法:

可以看到里面選擇parse的部分,是根據(jù)是否需要Validation選擇不同的parser的實(shí)現(xiàn)。

Parser的真面目已經(jīng)找到啦。
Parser2:

ValidatingParser:

其實(shí),ValidatingParser也是繼承了Parser2的一個類而已,再加上了驗(yàn)證合法性的功能。
今天先找到這里吧。 SAX的實(shí)現(xiàn)包含了許多Pattern,這里只是冰山一角,慢慢回味。。。