Java中使用jaxp進(jìn)行sax解析_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
SAX解析XML文件采用事件驅(qū)動(dòng)的方式進(jìn)行,也就是說(shuō),SAX是逐行掃描文件,遇到符合條件的設(shè)定條件后就會(huì)觸發(fā)特定的事件,回調(diào)你寫(xiě)好的事件處理程序。使用SAX的優(yōu)勢(shì)在于其解析速度較快,相對(duì)于DOM而言占用內(nèi)存較少。而且SAX在解析文件的過(guò)程中得到自己需要的信息后可以隨時(shí)終止解析,并不一定要等文件全部解析完畢。凡事有利必有弊,其劣勢(shì)在于SAX采用的是流式處理方式,當(dāng)遇到某個(gè)標(biāo)簽的時(shí)候,它并不會(huì)記錄下以前所遇到的標(biāo)簽,也就是說(shuō),在處理某個(gè)標(biāo)簽的時(shí)候,比如在startElement方法中,所能夠得到的信息就是標(biāo)簽的名字和屬性,至于標(biāo)簽內(nèi)部的嵌套結(jié)構(gòu),上層標(biāo)簽、下層標(biāo)簽以及其兄弟節(jié)點(diǎn)的名稱(chēng)等等與其結(jié)構(gòu)相關(guān)的信息都是不得而知的。實(shí)際上就是把XML文件的結(jié)構(gòu)信息丟掉了,如果需要得到這些信息的話(huà),只能你自己在程序里進(jìn)行處理了。所以相對(duì)DOM而言,SAX處理XML文檔沒(méi)有DOM方便,SAX處理的過(guò)程相對(duì)DOM而言也比較復(fù)雜。
SAX采用事件處理的方式解析XML文件,利用 SAX 解析 XML 文檔,涉及兩個(gè)部分:解析器和事件處理器:
解析器可以使用JAXP的API創(chuàng)建,創(chuàng)建出SAX解析器后,就可以指定解析器去解析某個(gè)XML文檔。
解析器采用SAX方式在解析某個(gè)XML文檔時(shí),它只要解析到XML文檔的一個(gè)組成部分,都會(huì)去調(diào)用事件處理器的一個(gè)方法,解析器在調(diào)用事件處理器的方法時(shí),會(huì)把當(dāng)前解析到的xml文件內(nèi)容作為方法的參數(shù)傳遞給事件處理器。
事件處理器由程序員編寫(xiě),程序員通過(guò)事件處理器中方法的參數(shù),就可以很輕松地得到sax解析器解析到的數(shù)據(jù),從而可以決定如何對(duì)數(shù)據(jù)進(jìn)行處理。
備注說(shuō)明:SAX API中主要有四種處理事件的接口,它們分別是ContentHandler,DTDHandler, EntityResolver 和 ErrorHandler

這里使用最多的就是ContentHandler,仔細(xì)閱讀 API文檔,了解常用方法:startElement、endElement、characters等
1.startElement方法說(shuō)明
void startElement(String uri,
String localName,
String qName,
Attributes atts)
throws SAXException
方法說(shuō)明:
解析器在 XML 文檔中的每個(gè)元素的開(kāi)始調(diào)用此方法;對(duì)于每個(gè) startElement 事件都將有相應(yīng)的 endElement 事件(即使該元素為空時(shí))。所有元素的內(nèi)容都將在相應(yīng)的 endElement 事件之前順序地報(bào)告。
參數(shù)說(shuō)明:
uri - 名稱(chēng)空間 URI,如果元素沒(méi)有名稱(chēng)空間 URI,或者未執(zhí)行名稱(chēng)空間處理,則為空字符串
localName - 本地名稱(chēng)(不帶前綴),如果未執(zhí)行名稱(chēng)空間處理,則為空字符串
qName - 限定名(帶有前綴),如果限定名不可用,則為空字符串
atts - 連接到元素上的屬性。如果沒(méi)有屬性,則它將是空 Attributes 對(duì)象。在 startElement 返回后,此對(duì)象的值是未定義的
2.endElement方法說(shuō)明
void endElement(String uri,
String localName,
String qName)
throws SAXException接收元素結(jié)束的通知。
SAX 解析器會(huì)在 XML 文檔中每個(gè)元素的末尾調(diào)用此方法;對(duì)于每個(gè) endElement 事件都將有相應(yīng)的 startElement 事件(即使該元素為空時(shí))。
參數(shù):
uri - 名稱(chēng)空間 URI,如果元素沒(méi)有名稱(chēng)空間 URI,或者未執(zhí)行名稱(chēng)空間處理,則為空字符串
localName - 本地名稱(chēng)(不帶前綴),如果未執(zhí)行名稱(chēng)空間處理,則為空字符串
qName - 限定的 XML 名稱(chēng)(帶前綴),如果限定名不可用,則為空字符串
3.characters方法
void characters(char[] ch,
int start,
int length)
throws SAXException
接收字符數(shù)據(jù)的通知,可以通過(guò)new String(ch,start,length)構(gòu)造器,創(chuàng)建解析出來(lái)的字符串文本.
參數(shù):
ch - 來(lái)自 XML 文檔的字符
start - 數(shù)組中的開(kāi)始位置
length - 從數(shù)組中讀取的字符的個(gè)數(shù)
其它方法請(qǐng)參考api數(shù)據(jù)
下面我們就具體講解sax解析的操作.
一.我們通過(guò)XMLReaderFactory、XMLReader完成,步驟如下
1.通過(guò)XMLReaderFactory創(chuàng)建XMLReader對(duì)象
XMLReader reader = XMLReaderFactory.createXMLReader();
2. 設(shè)置事件處理器對(duì)象
reader.setContentHandler(new MyDefaultHandler());
3.讀取要解析的xml文件
FileReader fileReader =new FileReader(new File("src\\sax\\startelement\\web.xml"));
4.指定解析的xml文件
reader.parse(new InputSource(fileReader));
案例:通過(guò)案例對(duì)uri、localName、qName和attribute參數(shù)有更加深入的了解
1.首先創(chuàng)建要解析的web.xml文件,內(nèi)容如下
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns:csdn="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <csdn:display-name></csdn:display-name> </web-app> <!-- uri - 名稱(chēng)空間 URI,如果元素沒(méi)有任何名稱(chēng)空間 URI,或者沒(méi)有正在執(zhí)行名稱(chēng)空間處理,則為空字符串。 xml namespace-xmlns localName - 本地名稱(chēng)(不帶前綴),如果沒(méi)有正在執(zhí)行名稱(chēng)空間處理,則為空字符串。 qName - 限定的名稱(chēng)(帶有前綴),如果限定的名稱(chēng)不可用,則為空字符串。 attributes - 附加到元素的屬性。如果沒(méi)有屬性,則它將是空的 Attributes 對(duì)象。 -->
2.創(chuàng)建解析測(cè)試類(lèi)及事件處理的內(nèi)部類(lèi)代碼如下
package sax.startelement;
import java.io.File;
import java.io.FileReader;
import org.junit.Test;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
public class Demo3 {
@Test
public void test() throws Exception {
// 通過(guò)XMLReaderFactory創(chuàng)建XMLReader對(duì)象
XMLReader reader = XMLReaderFactory.createXMLReader();
// 設(shè)置事件處理器對(duì)象
reader.setContentHandler(new MyDefaultHandler());
// 讀取要解析的xml文件
FileReader fileReader = new FileReader(new File(
"src\\sax\\startelement\\web.xml"));
// 指定解析的xml文件
reader.parse(new InputSource(fileReader));
}
// 自定義的解析類(lèi),通過(guò)此類(lèi)中的startElement了解uri,localName,qName,Attributes的含義
class MyDefaultHandler extends DefaultHandler {
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
System.out
.println("--------------startElement開(kāi)始執(zhí)行--------------------------");
System.out.println("uri:::" + uri);
System.out.println("localName:::" + localName);
System.out.println("qName:::" + qName);
for (int i = 0; i < attributes.getLength(); i++) {
String value = attributes.getValue(i);// 獲取屬性的value值
System.out.println(attributes.getQName(i) + "-----" + value);
}
System.out
.println("------------------startElement執(zhí)行完畢---------------------------");
}
}
}
3.程序運(yùn)行的結(jié)果如下:

通過(guò)運(yùn)行結(jié)果,希望你對(duì)uri,localName,qName有更加深入的了解.
二.我們通過(guò)SAXParserFactory、SAXParser、XMLReader完成,步驟如下
1.使用SAXParserFactory創(chuàng)建SAX解析工廠(chǎng)
SAXParserFactory spf = SAXParserFactory.newInstance();
2.通過(guò)SAX解析工廠(chǎng)得到解析器對(duì)象
SAXParser sp = spf.newSAXParser();
3.通過(guò)解析器對(duì)象得到一個(gè)XML的讀取器
XMLReader xmlReader = sp.getXMLReader();
4.設(shè)置讀取器的事件處理器
xmlReader.setContentHandler(new BookParserHandler());
5.解析xml文件
xmlReader.parse("book.xml");
說(shuō)明:如果只是使用SAXParserFactory、SAXParser他們完成只需要如下3步驟
1.獲取sax解析器的工廠(chǎng)對(duì)象
SAXParserFactory factory = SAXPar
serFactory.newInstance();
2.通過(guò)工廠(chǎng)對(duì)象 SAXParser創(chuàng)建解析器對(duì)象
SAXParser saxParser = factory.newSAXParser();
3.通過(guò)解析saxParser的parse()方法設(shè)定解析的文件和自己定義的事件處理器對(duì)象
saxParser.parse(new File("src//sax//sida.xml"), new MyDefaultHandler());
案例:解析出"作者"元素標(biāo)簽中的文本內(nèi)容
1.需要解析的sida.xml文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE 四大名著[ <!ELEMENT 四大名著 (西游記,紅樓夢(mèng))> <!ATTLIST 西游記 id ID #IMPLIED> ]> <四大名著> <西游記 id="x001"> <作者>吳承恩</作者> </西游記> <紅樓夢(mèng) id="x002"> <作者>曹雪芹</作者> </紅樓夢(mèng)> </四大名著>
2.解析測(cè)試類(lèi)和事件處理器類(lèi)的實(shí)現(xiàn)代碼
package sax;
import java.io.File;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.junit.Test;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SaxTest {
@Test
public void test() throws Exception {
// 1.獲取sax解析器的工廠(chǎng)對(duì)象
SAXParserFactory factory = SAXParserFactory.newInstance();
// 2.通過(guò)工廠(chǎng)對(duì)象 SAXParser創(chuàng)建解析器對(duì)象
SAXParser saxParser = factory.newSAXParser();
// 3.通過(guò)解析saxParser的parse()方法設(shè)定解析的文件和自己定義的事件處理器對(duì)象
saxParser.parse(new File("src//sax//sida.xml"), new MyDefaultHandler());
}
// 自己定義的事件處理器
class MyDefaultHandler extends DefaultHandler {
// 解析標(biāo)簽開(kāi)始及結(jié)束的的標(biāo)識(shí)符
boolean isOk = false;
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
// 當(dāng)解析作者元素開(kāi)始的時(shí)候,設(shè)置isOK為true
if ("作者".equals(qName)) {
isOk = true;
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
// 當(dāng)解析的標(biāo)識(shí)符為true時(shí),打印元素的內(nèi)容
if (isOk) {
System.out.println(new String(ch, start, length));
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
// 當(dāng)解析作者元素的結(jié)束的時(shí)候,設(shè)置isOK為false
if ("作者".equals(qName)) {
isOk = false;
}
}
}
}
3.程序運(yùn)行結(jié)果如下:

相關(guān)文章
Spring AOP訪(fǎng)問(wèn)目標(biāo)方法的參數(shù)操作示例
這篇文章主要介紹了Spring AOP訪(fǎng)問(wèn)目標(biāo)方法的參數(shù)操作,結(jié)合實(shí)例形式詳細(xì)分析了spring面向切面AOP訪(fǎng)問(wèn)目標(biāo)方法的參數(shù)相關(guān)實(shí)現(xiàn)步驟與操作注意事項(xiàng),需要的朋友可以參考下2020-01-01
SpringBoot使用hutool操作FTP的詳細(xì)過(guò)程
在使用SpringBoot結(jié)合hutool操作FTP時(shí),遇到防火墻導(dǎo)致上傳文件大小為0kb的問(wèn)題,通過(guò)設(shè)置FTP為被動(dòng)模式解決,本文詳細(xì)解析了FTP的主動(dòng)模式和被動(dòng)模式的工作原理、安全性及適用場(chǎng)景,幫助理解FTP的連接方式和解決網(wǎng)絡(luò)限制問(wèn)題2024-09-09
SpringCloud微服務(wù)多應(yīng)用腳手架的搭建與部署方式
這篇文章主要介紹了SpringCloud微服務(wù)多應(yīng)用腳手架的搭建與部署方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
SpringBoot實(shí)現(xiàn)加載yml文件中字典數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何實(shí)現(xiàn)加載yml文件中字典數(shù)據(jù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-04-04
Spring如何基于Proxy及cglib實(shí)現(xiàn)動(dòng)態(tài)代理
這篇文章主要介紹了Spring如何基于Proxy及cglib實(shí)現(xiàn)動(dòng)態(tài)代理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
java中的Reference和引用類(lèi)型實(shí)例精講
這篇文章主要為大家介紹了java中的Reference和引用類(lèi)型示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Springboot詳解整合SpringSecurity實(shí)現(xiàn)全過(guò)程
Spring Security基于Spring開(kāi)發(fā),項(xiàng)目中如果使用Springboot作為基礎(chǔ),配合Spring Security做權(quán)限更加方便,而Shiro需要和Spring進(jìn)行整合開(kāi)發(fā)。因此作為spring全家桶中的Spring Security在java領(lǐng)域很常用2022-07-07

