注意:使用sax編程只能進(jìn)行查詢操作蹋嵌。
1暇屋、在使用DOM解析XML文檔時加匈,需要讀取整個XML文檔,在內(nèi)存中構(gòu)架代表整個DOM樹的Document對象淋叶,從而再對XML文檔進(jìn)行操作阎曹。此中情況下,如果XML文檔特別大,就會消耗計(jì)算機(jī)大量內(nèi)存芬膝,并且容易導(dǎo)致內(nèi)存溢出望门。
2、 SAX解析允許在讀取文檔的時候锰霜,立即對文檔進(jìn)行處理筹误,而不必等到整個文檔裝載完才會對文檔進(jìn)行操作。
3癣缅、SAX采用事件處理的方式解析XML文件厨剪,利用SAX解析XML文檔,涉及兩個部分:解析器和事件處理器友存。
3.1 解析器可以使用JAXP的API創(chuàng)建祷膳,創(chuàng)建出SAX解析器后,就可以指定解析器去解析某個XML文檔屡立。
3.2 解析器采用SAX方式在解析某個XML文檔時直晨,它只要解析到文檔的一個組成部分,都會去調(diào)用事件處理器的一個方法膨俐,解析器在調(diào)用事件處理器的方法時勇皇,會把當(dāng)前解析到的xml文件內(nèi)容作為方法的參數(shù)傳遞給事件處理器。
3.3 事件處理器由程序員編寫焚刺,程序員通過事件處理器中方法的參數(shù)敛摘,就可以很輕松地得到SAX解析器解析到的數(shù)據(jù),從而可以決定如何對數(shù)據(jù)進(jìn)行處理乳愉。
操作步驟:
(1)使用SAXParserFactory創(chuàng)建sax解析工廠:
SAXParserFactory spf = SAXParserFactory.newInstance();
(2)通過sax解析工廠得到解析器對象
SAXParser sp = spf.newSAXParser();
(3)通過解析器對象得到一個xml的讀取器
XMLReader xmlReader = sp.getXMLReader();
(4)設(shè)置讀取器的事件處理器兄淫,這個事件處理器需要程序員自己實(shí)現(xiàn)
xmlReader.setContentHandler(new BookParserHandler());
(5)解析xml文件
xmlReader.parse("book.xml");
例子:這里我們還是解析之前的book.xml文檔
xml/book.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<書架>
<書 name="yyy">
<售價>109</售價>
<售價>39元</售價>
<書名>Java就業(yè)培訓(xùn)教程</書名>
<作者>張孝祥</作者>
<售價>120</售價></書>
</書架>
測試類:
src/sax.Demo1.java
package sax;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class Demo1 {
public static void main(String[] args) throws Exception {
//創(chuàng)建一個sax解析器工廠
SAXParserFactory factory = SAXParserFactory.newInstance();
//得到一個解析器對象
SAXParser parser = factory.newSAXParser();
//通過解析器得到一個xml的讀取器
XMLReader reader = parser.getXMLReader();
//在解析xml文檔之前,設(shè)置好事件處理器
//我們一般不使用繼承ContentHandler接口的這種方式蔓姚,因?yàn)樾枰獙?shí)現(xiàn)的方法太多了
//reader.setContentHandler(new MyContentHandler());
reader.setContentHandler(new MyContentHandler2());
//利用reader讀取xml文檔
reader.parse("xml/book.xml");
}
}
//繼承ContentHandler這個接口的方法只需要了解
class MyContentHandler implements ContentHandler{
//這里我們先看繼承ContentHandler的情況捕虽,這個接口中需要實(shí)現(xiàn)的方法很多,但是
//只用到下面前面三個方法赂乐。
//此方法主要是進(jìn)行文本處理薯鳍,數(shù)組中得到文本,就是用來得到標(biāo)簽中的值
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
System.out.println("當(dāng)前解析到了:" + new String(ch, start, length));
}
//接收元素開始的通知挨措,主要處理開始標(biāo)簽
//uri:名稱空間URI,如果元素沒有名稱空間URI崩溪,如果未執(zhí)行名稱空間處理浅役,則為空字符串
//localName:本地名稱(不帶前綴),如果未執(zhí)行命名空間處理伶唯,則為空字符串
//qName:元素名(帶有前綴)觉既,如果元素名不可用,則為空字符串
//atts:該元素的屬性。如果沒有屬性瞪讼,則它將是空Attributes對象钧椰。在startElement返回后,
//此對象的值是未定義的
@Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
System.out.println("當(dāng)前解析到了:" + qName + "符欠, 這個標(biāo)簽是開始標(biāo)簽");
for(int i = 0; i < atts.getLength(); i++){
//下面是得到標(biāo)簽中屬性和屬性的值
String attname = atts.getQName(i);
String attvalue = atts.getValue(i);
System.out.println(attname + "=" + attvalue);
}
}
//主要處理結(jié)束標(biāo)簽
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("當(dāng)前解析到了:" + qName + "嫡霞, 這個標(biāo)簽是結(jié)束標(biāo)簽");
}
@Override
public void setDocumentLocator(Locator locator) {
// TODO Auto-generated method stub
}
//接收文檔開始的通知,SAX解析器僅調(diào)用該方法一次
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
}
//接收文檔結(jié)尾的通知希柿,SAX解析器僅調(diào)用該方法一次诊沪,并且它將是解析期間最后調(diào)用的方法。
//直到解析器放棄解析(由于不可恢復(fù)的錯誤)或到達(dá)輸入的結(jié)尾時曾撤,該方法才會被調(diào)用
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void endPrefixMapping(String prefix) throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void processingInstruction(String target, String data)
throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void skippedEntity(String name) throws SAXException {
// TODO Auto-generated method stub
}
}
//鑒于繼承ContentHandler接口需要實(shí)現(xiàn)的方法太多端姚,這里我們繼承DefaultHandler類
class MyContentHandler2 extends DefaultHandler{
@Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
System.out.println("當(dāng)前解析到了:" + qName + ", 這個標(biāo)簽是開始標(biāo)簽");
for(int i = 0; i < atts.getLength(); i++){
//下面是得到標(biāo)簽中屬性和屬性的值
String attname = atts.getQName(i);
String attvalue = atts.getValue(i);
System.out.println(attname + "=" + attvalue);
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("當(dāng)前解析到了:" + qName + "挤悉, 這個標(biāo)簽是結(jié)束標(biāo)簽");
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
System.out.println("當(dāng)前解析到了:" + new String(ch, start, length));
}
}
這里我們可能已經(jīng)注意到了渐裸,繼承ContentHandler接口 和繼承DefaultHandler類所需要實(shí)現(xiàn)的方法都是一樣的,也完全可以寫成一樣的實(shí)現(xiàn)装悲,但是由于繼承ContentHandler所需要實(shí)現(xiàn)的類太多昏鹃,我們一般使用繼承DefaultHandler類完成對xml的解析。