1. 程式人生 > >SAX解析XML文件

SAX解析XML文件

ttr api文檔 深入 ttl parser 解析 流式 resolve art

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中主要有四種處理事件的接口,它們分別是ContentHandler,DTDHandler, EntityResolver ErrorHandler

技術分享圖片

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

1.startElement方法說明

  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. uri - 名稱空間 URI,如果元素沒有名稱空間 URI,或者未執行名稱空間處理,則為空字符串
  10. localName - 本地名稱(不帶前綴),如果未執行名稱空間處理,則為空字符串
  11. qName - 限定名(帶有前綴),如果限定名不可用,則為空字符串
  12. atts - 連接到元素上的屬性。如果沒有屬性,則它將是空 Attributes 對象。在 startElement 返回後,此對象的值是未定義的

2.endElement方法說明

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


3.characters方法

  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完成,步驟如下

  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文件,內容如下

  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.創建解析測試類及事件處理的內部類代碼如下

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


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文件

  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.解析測試類和事件處理器類的實現代碼

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


3.程序運行結果如下:

技術分享圖片

SAX解析XML文件