使用JAXP進行SAX解析(XMLReaderFactory、XMLReader 、SAXParserFactory與SAXParser)

五柳-先生發表於2015-11-24

SAX解析XML檔案採用事件驅動的方式進行,也就是說,SAX是逐行掃描檔案,遇到符合條件的設定條件後就會觸發特定的事件,回撥你寫好的事件處理程式。使用SAX的優勢在於其解析速度較快,相對於DOM而言佔用記憶體較少。而且SAX在解析檔案的過程中得到自己需要的資訊後可以隨時終止解析,並不一定要等檔案全部解析完畢。凡事有利必有弊,其劣勢在於SAX採用的是流式處理方式,當遇到某個標籤的時候,它並不會記錄下以前所遇到的標籤,也就是說,在處理某個標籤的時候,比如在startElement方法中,所能夠得到的資訊就是標籤的名字和屬性,至於標籤內部的巢狀結構,上層標籤、下層標籤以及其兄弟節點的名稱等等與其結構相關的資訊都是不得而知的。實際上就是把XML檔案的結構資訊丟掉了,如果需要得到這些資訊的話,只能你自己在程式裡進行處理了。所以相對DOM而言,SAX處理XML文件沒有DOM方便,SAX處理的過程相對DOM而言也比較複雜。

        SAX採用事件處理的方式解析XML檔案,利用 SAX 解析 XML 文件,涉及兩個部分:解析器和事件處理器:
解析器可以使用JAXP的API建立,建立出SAX解析器後,就可以指定解析器去解析某個XML文件。
解析器採用SAX方式在解析某個XML文件時,它只要解析到XML文件的一個組成部分,都會去呼叫事件處理器的一個方法,解析器在呼叫事件處理器的方法時,會把當前解析到的xml檔案內容作為方法的引數傳遞給事件處理器。
事件處理器由程式設計師編寫,程式設計師通過事件處理器中方法的引數,就可以很輕鬆地得到sax解析器解析到的資料,從而可以決定如何對資料進行處理。

備註說明:SAX API中主要有四種處理事件的介面,它們分別是ContentHandlerDTDHandler EntityResolver 和 ErrorHandler 

 這裡使用最多的就是ContentHandler,仔細閱讀 API文件,瞭解常用方法:startElement、endElement、characters等

 1.startElement方法說明

[java] view plaincopy
  1. void startElement(String uri,  
  2.                   String localName,  
  3.                   String qName,  
  4.                   Attributes atts)  
  5.                   throws SAXException  
  6. 方法說明:  
  7. 解析器在 XML 文件中的每個元素的開始呼叫此方法;對於每個 startElement 事件都將有相應的 endElement 事件(即使該元素為空時)。所有元素的內容都將在相應的 endElement 事件之前順序地報告。  
  8.   
  9. 引數說明:  
  10. uri - 名稱空間 URI,如果元素沒有名稱空間 URI,或者未執行名稱空間處理,則為空字串  
  11. localName - 本地名稱(不帶字首),如果未執行名稱空間處理,則為空字串  
  12. qName - 限定名(帶有字首),如果限定名不可用,則為空字串  
  13. atts - 連線到元素上的屬性。如果沒有屬性,則它將是空 Attributes 物件。在 startElement 返回後,此物件的值是未定義的  
 2.endElement方法說明

[java] view plaincopy
  1. void endElement(String uri,  
  2.                 String localName,  
  3.                 String qName)  
  4.                 throws SAXException接收元素結束的通知。   
  5. SAX 解析器會在 XML 文件中每個元素的末尾呼叫此方法;對於每個 endElement 事件都將有相應的 startElement 事件(即使該元素為空時)。  
  6.   
  7. 引數:  
  8. uri - 名稱空間 URI,如果元素沒有名稱空間 URI,或者未執行名稱空間處理,則為空字串  
  9. localName - 本地名稱(不帶字首),如果未執行名稱空間處理,則為空字串  
  10. qName - 限定的 XML 名稱(帶字首),如果限定名不可用,則為空字串  

3.characters方法

[java] view plaincopy
  1. void characters(char[] ch,  
  2.                 int start,  
  3.                 int length)  
  4.                 throws SAXException  
  5. 接收字元資料的通知,可以通過new String(ch,start,length)構造器,建立解析出來的字串文字.  
  6. 引數:  
  7. ch - 來自 XML 文件的字元  
  8. start - 陣列中的開始位置  
  9. length - 從陣列中讀取的字元的個數   

其它方法請參考api資料

下面我們就具體講解sax解析的操作.

一.我們通過XMLReaderFactory、XMLReader完成,步驟如下

[java] view plaincopy
  1. 1.通過XMLReaderFactory建立XMLReader物件  
  2. XMLReader reader = XMLReaderFactory.createXMLReader();  
  3. 2. 設定事件處理器物件  
  4. reader.setContentHandler(new MyDefaultHandler());  
  5. 3.讀取要解析的xml檔案  
  6. FileReader fileReader =new FileReader(new File("src\\sax\\startelement\\web.xml"));  
  7. 4.指定解析的xml檔案  
  8. reader.parse(new InputSource(fileReader));  

案例:通過案例對uri、localName、qName和attribute引數有更加深入的瞭解

1.首先建立要解析的web.xml檔案,內容如下

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app version="2.5"   
  3.     xmlns:csdn="http://java.sun.com/xml/ns/javaee"   
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
  5.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
  6.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
  7.   <csdn:display-name></csdn:display-name>     
  8. </web-app>  
  9. <!--   
  10. uri - 名稱空間 URI,如果元素沒有任何名稱空間 URI,或者沒有正在執行名稱空間處理,則為空字串。  
  11. xml namespace-xmlns  
  12. localName - 本地名稱(不帶字首),如果沒有正在執行名稱空間處理,則為空字串。  
  13. qName - 限定的名稱(帶有字首),如果限定的名稱不可用,則為空字串。  
  14. attributes - 附加到元素的屬性。如果沒有屬性,則它將是空的 Attributes 物件。   
  15.  -->  

2.建立解析測試類及事件處理的內部類程式碼如下

[java] view plaincopy
  1. package sax.startelement;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileReader;  
  5.   
  6. import org.junit.Test;  
  7. import org.xml.sax.Attributes;  
  8. import org.xml.sax.InputSource;  
  9. import org.xml.sax.SAXException;  
  10. import org.xml.sax.XMLReader;  
  11. import org.xml.sax.helpers.DefaultHandler;  
  12. import org.xml.sax.helpers.XMLReaderFactory;  
  13.   
  14. public class Demo3 {  
  15.   
  16.     @Test  
  17.     public void test() throws Exception {  
  18.         // 通過XMLReaderFactory建立XMLReader物件  
  19.         XMLReader reader = XMLReaderFactory.createXMLReader();  
  20.         // 設定事件處理器物件  
  21.         reader.setContentHandler(new MyDefaultHandler());  
  22.         // 讀取要解析的xml檔案  
  23.         FileReader fileReader = new FileReader(new File(  
  24.                 "src\\sax\\startelement\\web.xml"));  
  25.         // 指定解析的xml檔案  
  26.         reader.parse(new InputSource(fileReader));  
  27.     }  
  28.   
  29.     // 自定義的解析類,通過此類中的startElement瞭解uri,localName,qName,Attributes的含義  
  30.     class MyDefaultHandler extends DefaultHandler {  
  31.   
  32.         @Override  
  33.         public void startElement(String uri, String localName, String qName,  
  34.                 Attributes attributes) throws SAXException {  
  35.             super.startElement(uri, localName, qName, attributes);  
  36.             System.out  
  37.                     .println("--------------startElement開始執行--------------------------");  
  38.             System.out.println("uri:::" + uri);  
  39.             System.out.println("localName:::" + localName);  
  40.             System.out.println("qName:::" + qName);  
  41.             for (int i = 0; i < attributes.getLength(); i++) {  
  42.                 String value = attributes.getValue(i);// 獲取屬性的value值  
  43.                 System.out.println(attributes.getQName(i) + "-----" + value);  
  44.             }  
  45.             System.out  
  46.                     .println("------------------startElement執行完畢---------------------------");  
  47.         }  
  48.   
  49.     }  
  50. }  

3.程式執行的結果如下:


通過執行結果,希望你對uri,localName,qName有更加深入的瞭解.

二.我們通過SAXParserFactory、SAXParser、XMLReader完成,步驟如下

1.使用SAXParserFactory建立SAX解析工廠
SAXParserFactory spf = SAXParserFactory.newInstance();
2.通過SAX解析工廠得到解析器物件
SAXParser sp = spf.newSAXParser();
3.通過解析器物件得到一個XML的讀取器
XMLReader xmlReader = sp.getXMLReader();
4.設定讀取器的事件處理器
xmlReader.setContentHandler(new BookParserHandler());
5.解析xml檔案
xmlReader.parse("book.xml");

說明:如果只是使用SAXParserFactory、SAXParser他們完成只需要如下3步驟

1.獲取sax解析器的工廠物件
SAXParserFactory factory = SAXParserFactory.newInstance();
2.通過工廠物件 SAXParser建立解析器物件
SAXParser saxParser = factory.newSAXParser();
3.通過解析saxParser的parse()方法設定解析的檔案和自己定義的事件處理器物件
saxParser.parse(new File("src//sax//sida.xml"), new MyDefaultHandler());

案例:解析出"作者"元素標籤中的文字內容

1.需要解析的sida.xml檔案

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE 四大名著[  
  3. <!ELEMENT 四大名著 (西遊記,紅樓夢)>  
  4. <!ATTLIST 西遊記 id ID #IMPLIED>  
  5. ]>  
  6. <四大名著>  
  7.     <西遊記 id="x001">  
  8.         <作者>吳承恩</作者>  
  9.     </西遊記>  
  10.     <紅樓夢 id="x002">  
  11.         <作者>曹雪芹</作者>  
  12.     </紅樓夢>  
  13. </四大名著>  

2.解析測試類和事件處理器類的實現程式碼

[java] view plaincopy
  1. package sax;  
  2.   
  3. import java.io.File;  
  4.   
  5. import javax.xml.parsers.SAXParser;  
  6. import javax.xml.parsers.SAXParserFactory;  
  7.   
  8. import org.junit.Test;  
  9. import org.xml.sax.Attributes;  
  10. import org.xml.sax.SAXException;  
  11. import org.xml.sax.helpers.DefaultHandler;  
  12.   
  13. public class SaxTest {  
  14.   
  15.     @Test  
  16.     public void test() throws Exception {  
  17.         // 1.獲取sax解析器的工廠物件  
  18.         SAXParserFactory factory = SAXParserFactory.newInstance();  
  19.         // 2.通過工廠物件 SAXParser建立解析器物件  
  20.         SAXParser saxParser = factory.newSAXParser();  
  21.         // 3.通過解析saxParser的parse()方法設定解析的檔案和自己定義的事件處理器物件  
  22.         saxParser.parse(new File("src//sax//sida.xml"), new MyDefaultHandler());  
  23.   
  24.     }  
  25.   
  26.     // 自己定義的事件處理器  
  27.     class MyDefaultHandler extends DefaultHandler {  
  28.   
  29.         // 解析標籤開始及結束的的識別符號  
  30.         boolean isOk = false;  
  31.   
  32.         @Override  
  33.         public void startElement(String uri, String localName, String qName,  
  34.                 Attributes attributes) throws SAXException {  
  35.             super.startElement(uri, localName, qName, attributes);  
  36.             // 當解析作者元素開始的時候,設定isOK為true  
  37.             if ("作者".equals(qName)) {  
  38.                 isOk = true;  
  39.             }  
  40.         }  
  41.   
  42.         @Override  
  43.         public void characters(char[] ch, int start, int length)  
  44.                 throws SAXException {  
  45.             // TODO Auto-generated method stub  
  46.             super.characters(ch, start, length);  
  47.             // 當解析的識別符號為true時,列印元素的內容  
  48.             if (isOk) {  
  49.                 System.out.println(new String(ch, start, length));  
  50.             }  
  51.         }  
  52.           
  53.         @Override  
  54.         public void endElement(String uri, String localName, String qName)  
  55.                 throws SAXException {  
  56.             super.endElement(uri, localName, qName);  
  57.             // 當解析作者元素的結束的時候,設定isOK為false  
  58.             if ("作者".equals(qName)) {  
  59.                 isOk = false;  
  60.             }  
  61.         }  
  62.   
  63.     }  
  64. }  

3.程式執行結果如下:


通過以上解析希望你對sax解析有初步的認知.

相關文章