SAX最初是由DavidMegginson采用Java語(yǔ)言開發(fā)的,之后SAX很快在Java開發(fā)者中流行起來(lái)。SAN項(xiàng)目現(xiàn)在負(fù)責(zé)管理其原始API的開發(fā)工作,這是一種公開的、開放源代碼軟件。不同于其他大多數(shù)XML標(biāo)準(zhǔn)的是,SAX沒(méi)有語(yǔ)言開發(fā)商必須遵守的標(biāo)準(zhǔn)SAX參考版本。因此,SAX的不同實(shí)現(xiàn)可能采用區(qū)別很大的接口。不過(guò),所有的這些實(shí)現(xiàn)至少有一個(gè)特性是完全一樣的,這就是事件驅(qū)動(dòng)。
文檔解析
在SAX解析器裝載XML文件時(shí),它遍歷文件文檔并在其主機(jī)應(yīng)用程序中產(chǎn)生事件(經(jīng)由回調(diào)函數(shù)、指派函數(shù)或者任何可調(diào)用平臺(tái)完成這一功能)表示這一過(guò)程。這樣,編寫SAX應(yīng)用程序就如同采用最現(xiàn)代的工具箱編寫GUI程序。
大多數(shù)SAX實(shí)現(xiàn)都會(huì)產(chǎn)生以下若干類型的事件:
在文檔的開始和結(jié)束時(shí)觸發(fā)文檔處理事件。
在文檔內(nèi)每一XML元素接受解析的前后觸發(fā)元素事件。任何元數(shù)據(jù)通常都由單獨(dú)的事件交付。
在處理文檔的DTD或Schema時(shí)產(chǎn)生DTD或Schema事件。
錯(cuò)誤事件用來(lái)通知主機(jī)應(yīng)用程序解析錯(cuò)誤。
顯而易見,在處理文檔時(shí)你最關(guān)心的就是元素事件了。通常,SAX解析器會(huì)向你的主機(jī)應(yīng)用程序提供包含元素信息的事件參數(shù);在最低程度下也會(huì)提供元素的名字。具體取決于你的特定實(shí)現(xiàn),可以定義不同類型的元素事件代表不同類型元素的處理。例如,注釋元素(它可能包含主機(jī)應(yīng)用程序的處理指令)就經(jīng)常在接受處理時(shí)產(chǎn)生特殊的事件。
要解析的XML文件:myClass.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <class>
3 <stu id="001">
4 <name>Allen</name>
5 <sex>男</sex>
6 <age>20</age>
7 </stu>
8 <stu id="002">
9 <name>namy</name>
10 <sex>女</sex>
11 <age>18</age>
12 </stu>
13 <stu id="003">
14 <name>lufy</name>
15 <sex>男</sex>
16 <age>18</age>
17 </stu>
18 </class>
用SAX解析XML的Handler類:Myhandler.java
1 /**
2 * 用SAX解析XML的Handler
3 */
4 package com.xml.util;
5
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Map;
10
11 import org.xml.sax.Attributes;
12 import org.xml.sax.SAXException;
13 import org.xml.sax.helpers.DefaultHandler;
14
15 public class Myhandler extends DefaultHandler {
16 //存儲(chǔ)正在解析的元素的數(shù)據(jù)
17 private Map<String,String> map=null;
18 //存儲(chǔ)所有解析的元素的數(shù)據(jù)
19 private List<Map<String,String>> list=null;
20 //正在解析的元素的名字
21 String currentTag=null;
22 //正在解析的元素的元素值
23 String currentValue=null;
24 //解析的XML文檔中要獲取數(shù)據(jù)的元素標(biāo)簽
25 String nodeName=null;
26
27
28 public Myhandler(String nodeName) {
29 // TODO Auto-generated constructor stub
30 this.nodeName=nodeName;
31 }
32
33 public List<Map<String, String>> getList() {
34 return list;
35 }
36
37 //開始解析文檔,即開始解析根元素時(shí)調(diào)用該方法
38 @Override
39 public void startDocument() throws SAXException {
40 // TODO Auto-generated method stub
41 System.out.println("--startDocument()--");
42 //初始化Map
43 list=new ArrayList<Map<String,String>>();
44 }
45
46 //開始解析每個(gè)元素時(shí)都會(huì)調(diào)用該方法
47 @Override
48 public void startElement(String uri, String localName, String qName,
49 Attributes attributes) throws SAXException {
50 // TODO Auto-generated method stub
51 //判斷正在解析的元素是不是要獲取數(shù)據(jù)的元素標(biāo)簽
52 System.out.println("--startElement()--"+qName);
53 if(qName.equals(nodeName)){
54 map=new HashMap<String, String>();
55 }
56
57 //判斷正在解析的元素是否有屬性值,如果有則將其全部取出并保存到map對(duì)象中,如:<person id="00001"></person>
58 if(attributes!=null&&map!=null){
59 for(int i=0;i<attributes.getLength();i++){
60 map.put(attributes.getQName(i), attributes.getValue(i));
61 }
62 }
63 currentTag=qName; //正在解析的元素
64 }
65
66 //解析到每個(gè)元素的內(nèi)容時(shí)會(huì)調(diào)用此方法
67 @Override
68 public void characters(char[] ch, int start, int length)
69 throws SAXException {
70 // TODO Auto-generated method stub
71 System.out.println("--characters()--");
72 if(currentTag!=null&&map!=null){
73 currentValue=new String(ch,start,length);
74 //如果內(nèi)容不為空和空格,也不是換行符則將該元素名和值和存入map中
75 if(currentValue!=null&&!currentValue.trim().equals("")&&!currentValue.trim().equals("\n")){
76 map.put(currentTag, currentValue);
77 System.out.println("-----"+currentTag+" "+currentValue);
78 }
79 //當(dāng)前的元素已解析過(guò),將其置空用于下一個(gè)元素的解析
80 currentTag=null;
81 currentValue=null;
82 }
83 }
84
85 //每個(gè)元素結(jié)束的時(shí)候都會(huì)調(diào)用該方法
86 @Override
87 public void endElement(String uri, String localName, String qName)
88 throws SAXException {
89 // TODO Auto-generated method stub
90 System.out.println("--endElement()--"+qName);
91 //判斷是否為一個(gè)節(jié)點(diǎn)結(jié)束的元素標(biāo)簽
92 if(qName.equals(nodeName)){
93 list.add(map);
94 map=null;
95 }
96 }
97
98 //結(jié)束解析文檔,即解析根元素結(jié)束標(biāo)簽時(shí)調(diào)用該方法
99 @Override
100 public void endDocument() throws SAXException {
101 // TODO Auto-generated method stub
102 System.out.println("--endDocument()--");
103 super.endDocument();
104 }
105 }
用于解析XML的業(yè)務(wù)類:SaxService.java
1 /**
2 * 封裝解析業(yè)務(wù)類
3 */
4 package com.xml.service;
5
6 import java.io.InputStream;
7 import java.util.List;
8 import java.util.Map;
9
10 import javax.xml.parsers.SAXParser;
11 import javax.xml.parsers.SAXParserFactory;
12
13 import com.xml.util.Myhandler;
14
15 public class SaxService {
16
17 public static List<Map<String,String>> ReadXML(String uri,String NodeName){
18 try {
19 //創(chuàng)建一個(gè)解析XML的工廠對(duì)象
20 SAXParserFactory parserFactory=SAXParserFactory.newInstance();
21 //創(chuàng)建一個(gè)解析XML的對(duì)象
22 SAXParser parser=parserFactory.newSAXParser();
23 //創(chuàng)建一個(gè)解析助手類
24 Myhandler myhandler=new Myhandler("stu");
25 parser.parse(uri, myhandler);
26 return myhandler.getList();
27 } catch (Exception e) {
28 e.printStackTrace();
29 }finally{
30
31 }
32 return null;
33
34 }
35 }
主程序入口:XmlSaxTest
1 /**
2 * 程序入口
3 */
4 package com.xml.sax;
5
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.Iterator;
9 import java.util.List;
10 import java.util.Map;
11
12 import com.xml.service.SaxService;
13
14 public class XmlSaxTest {
15
16 /**
17 * @param args
18 */
19 public static void main(String[] args) {
20 // TODO Auto-generated method stub
21 ArrayList<Map<String, String>> list=(ArrayList<Map<String, String>>) SaxService.ReadXML("M:\\XML\\Demo\\myClass.xml","class");
22 /*for(int i=0;i<list.size();i++){
23 HashMap<String, String> temp=(HashMap<String, String>) list.get(i);
24 Iterator<String> iterator=temp.keySet().iterator();
25 while(iterator.hasNext()){
26 String key=iterator.next().toString();
27 String value=temp.get(key);
28 System.out.print(key+" "+value+"--");
29 }
30 }*/
31 System.out.println(list.toString());
32 }
33
34 }
執(zhí)行結(jié)果:
1 --startDocument()--
2 --startElement()--class
3 --characters()--
4 --startElement()--stu
5 --characters()--
6 --startElement()--name
7 --characters()--
8 -----name Allen
9 --endElement()--name
10 --characters()--
11 --startElement()--sex
12 --characters()--
13 -----sex 男
14 --endElement()--sex
15 --characters()--
16 --startElement()--age
17 --characters()--
18 -----age 20
19 --endElement()--age
20 --characters()--
21 --endElement()--stu
22 --characters()--
23 --startElement()--stu
24 --characters()--
25 --startElement()--name
26 --characters()--
27 -----name namy
28 --endElement()--name
29 --characters()--
30 --startElement()--sex
31 --characters()--
32 -----sex 女
33 --endElement()--sex
34 --characters()--
35 --startElement()--age
36 --characters()--
37 -----age 18
38 --endElement()--age
39 --characters()--
40 --endElement()--stu
41 --characters()--
42 --startElement()--stu
43 --characters()--
44 --startElement()--name
45 --characters()--
46 -----name lufy
47 --endElement()--name
48 --characters()--
49 --startElement()--sex
50 --characters()--
51 -----sex 男
52 --endElement()--sex
53 --characters()--
54 --startElement()--age
55 --characters()--
56 -----age 18
57 --endElement()--age
58 --characters()--
59 --endElement()--stu
60 --characters()--
61 --endElement()--class
62 --endDocument()--
63 [{id=001, sex=男, age=20, name=Allen}, {id=002, sex=女, age=18, name=namy}, {id=003, sex=男, age=18, name=lufy}]
分析:用SAX解析XML采用的是從上而下的基于事件驅(qū)動(dòng)的解析方式,在解析過(guò)程中會(huì)視情況自動(dòng)調(diào)用startDocument()、startElement()、characters()、endElement()、endDocument()等相關(guān)的方法。
由編譯執(zhí)行的結(jié)果來(lái)看:
startDocument()方法只會(huì)在文檔開始解析的時(shí)候被調(diào)用,每次解析只會(huì)調(diào)用一次。
startElement()方法每次在開始解析一個(gè)元素,即遇到元素標(biāo)簽開始的時(shí)候都會(huì)調(diào)用。
characters()方法也是在每次解析到元素標(biāo)簽攜帶的內(nèi)容時(shí)都會(huì)調(diào)用,即使該元素標(biāo)簽的內(nèi)容為空或換行。而且如果元素內(nèi)嵌套元素,在父元素結(jié)束標(biāo)簽前, characters()方法會(huì)再次被調(diào)用,此處需要注意。
endElement()方法每次在結(jié)束解析一個(gè)元素,即遇到元素標(biāo)簽結(jié)束的時(shí)候都會(huì)調(diào)用。
endDocument() startDocument()方法只會(huì)在文檔解析結(jié)束的時(shí)候被調(diào)用,每次解析只會(huì)調(diào)用一次。