隨筆 - 3, 文章 - 152, 評(píng)論 - 17, 引用 - 0
          數(shù)據(jù)加載中……

          SAX之Java實(shí)現(xiàn)學(xué)習(xí)筆記

          本文假設(shè)讀者對(duì)XML有些了解

           

          首先,先給出一個(gè)比較基本的處理xml文件的程序。你不必細(xì)看,直接跳過(guò)即可。需要時(shí)可以返回來(lái)看。

           

           

          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);

                  }

              }

          }

           

          從程序中可以看出,解析一個(gè)XML文件的核心語(yǔ)句是下面一部分:

               // 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)建一個(gè)SAXParserFactory工廠類的實(shí)例,然后通過(guò)SAXParser saxParser = factory.newSAXParser(); 這個(gè)工廠類的方法創(chuàng)建了一個(gè)saxParser。將xml文件(new File(argv[0]))和一個(gè)Sax Event Handlerhandler)(在這個(gè)程序里面,這個(gè)Handler其實(shí)是本身這個(gè)類,這個(gè)類繼承了org.xml.sax.helpers.DefaultHandler 這個(gè)類,并且在前面初始化了它:DefaultHandler handler = new Echo01();  )傳遞給它,讓它進(jìn)行解析。

           

          關(guān)于xml文件的解析過(guò)程中的處理全部在Handler里面實(shí)現(xiàn)。一般Parser接受的是DefaultHandler或者HandlerBase這兩個(gè)類。 這個(gè)例子里面的類是繼承DefaultHandler這個(gè)虛類的。看下圖:

           

           

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

           

           

          不同的方法,在不同的時(shí)候被Parser調(diào)用,(這個(gè)不同的時(shí)候就是Event-based

          詳細(xì)介紹:(暫略)

           

           

          DefualtHandlerUML圖如下:

           

           

          看完Handler,再轉(zhuǎn)過(guò)頭去看Parser,在代碼里面用的是SAXParser(SAXParser saxParser)

          仔細(xì)看里面的代碼

           

          你會(huì)發(fā)現(xiàn),其實(shí)它并沒(méi)有自己完成解析的工作,而是Wrap了另二個(gè)類XMLReaderParser來(lái)完成解析工作。原來(lái)SAXParser只是起到一個(gè)Adapter的工作而已。

           

          UML:

           

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

           

          看到Parser的代碼,你會(huì)大失所望。原來(lái)Parser也只是一個(gè)空殼子而已

           

           

          圖中你可以看到經(jīng)過(guò)層層查找的Parser只是一個(gè)接口而已。

           

          回想一下前面看到生成解析器代碼的時(shí)候

          使用了工廠模式

                        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 這個(gè)類來(lái)控制產(chǎn)生的Parser的類型。我們只是拿來(lái)用就可以了。秘密一定藏在里面。

           

          看到代碼,發(fā)現(xiàn)原來(lái)這個(gè)工廠自己也是一個(gè)虛類,連返回的工廠的實(shí)例都是該虛工廠的一個(gè)實(shí)現(xiàn)而已。

          再去看真正的實(shí)現(xiàn)org.apache.crimson.jaxp.SAXParserFactoryImpl

           

           

          發(fā)現(xiàn)它又wrapSAXParserImpl,可知SAXParserImplSAXParser的一個(gè)子類。

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

           

           

           

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

           

           

          是不是有點(diǎn)感覺(jué)了? 對(duì)了,其實(shí)這個(gè)方法就是留給繼承了SAXParserSAXParserImpl來(lái)實(shí)現(xiàn)的,這樣,SAXParser的子類就可以自由的改換Parser。只要改寫掉getParser方法就可以了。

          急忙去看SAXParserImplgetParser這個(gè)方法

           

           

           

          你會(huì)發(fā)現(xiàn)你又上當(dāng)了,這里又給出了很曖昧的代碼,并不是我們所猜想的那樣是一個(gè)真正的實(shí)現(xiàn),再仔細(xì)看看。 注釋里面有這么句話:Adapt a SAX2 XMLReader into a SAX1 Parser

          XMLReader,是不是很熟?想想看哪里看到過(guò)的?對(duì)了,剛剛在SAXParser體內(nèi)Wrap的二個(gè)類,一個(gè)是我們追蹤至今的Parser,另一個(gè)就是XMLReader,原來(lái)這個(gè)XMLReader才是才是現(xiàn)在在用的SAX2解析器,而為了保持對(duì)以前系統(tǒng)的兼容才保留了SAX1解析器Parser,但其實(shí)是通過(guò)對(duì)XMLReaderWrap得到的。只是個(gè)Adapte而已。

           

          好了,現(xiàn)在可以集中火力去查找XMLReader了。有了剛剛的經(jīng)驗(yàn),很容易的,我們發(fā)現(xiàn),和Parser一樣,XMLReader也是一個(gè)接口:

           

           

          很容易的,我們找到XMLReaderImpl

           

           

           

          和里面的parse方法:

           

           

           

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

           

           

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

          Parser2

           

           

          ValidatingParser

           

          其實(shí),ValidatingParser也是繼承了Parser2的一個(gè)類而已,再加上了驗(yàn)證合法性的功能。

           

           

          今天先找到這里吧。 SAX的實(shí)現(xiàn)包含了許多Pattern,這里只是冰山一角,慢慢回味。。。

          posted on 2005-03-28 16:15 閱讀(458) 評(píng)論(0)  編輯  收藏 所屬分類: Java_Xml

          主站蜘蛛池模板: 额济纳旗| 江门市| 璧山县| 河津市| 乌什县| 砀山县| 安塞县| 靖州| 沛县| 阳山县| 卓尼县| 长春市| 青州市| 荆州市| 凯里市| 图木舒克市| 肇庆市| 镇平县| 武鸣县| 彭泽县| 昔阳县| 西和县| 潜江市| 卓资县| 麻江县| 辉南县| 志丹县| 铜鼓县| 永登县| 磐安县| 雅江县| 永泰县| 富宁县| 侯马市| 日照市| 宜章县| 盐津县| 旬阳县| 西畴县| 丰台区| 藁城市|