SAX方式
- 使用 DOM解析XML文檔時,需要讀取整個XML文檔,在內(nèi)存中構(gòu)架生成代表整個 DOM樹的Doucment對象,才能再對XML文檔進(jìn)行操作。如果 XML 文檔特別大,就會消耗計(jì)算機(jī)的大量內(nèi)存,并且容易導(dǎo)致內(nèi)存溢出。
- SAX解析采用事件處理的方式解析XML文件,允許在讀取文檔的時候,即對文檔進(jìn)行處理,而不必等到整個文檔裝載完才會文檔進(jìn)行操作
SAX解析原理
解析器和事件處理器
- 使用JAXP的API創(chuàng)建出SAX解析器后,可以指定解析器去解析某個XML文檔。 在解析某個XML文檔時,每解析到XML文檔的一個組成部分,都會去調(diào)用事件處理器的一個方法,該方法會把當(dāng)前解析到的XML文件內(nèi)容作為方法的參數(shù)傳遞給事件處理器
- 事件處理器由程序員編寫,程序員通過事件處理器中方法的參數(shù),就可以很輕松地得到sax解析器解析到的數(shù)據(jù),從而可以決定如何對數(shù)據(jù)進(jìn)行處理
SAX解析模型.png
解析流程
使用SAXParserFactory創(chuàng)建SAX解析工廠
SAXParserFactory spf = SAXParserFactory.newInstance();
通過SAX解析工廠得到解析器對象
SAXParser sp = spf.newSAXParser();
通過解析器對象得到一個XML的讀取器
XMLReader xmlReader = sp.getXMLReader();
設(shè)置讀取器的事件處理器
xmlReader.setContentHandler(new BookParserHandler());
解析xml文件
xmlReader.parse("book.xml");
SAX解析編程
xml文檔:
<?xml version="1.0" encoding="utf-8"?>
<書架>
<書>
<書名>浪潮之巔</書名>
<作者>吳軍</作者>
<售價>50</售價>
<個人信息><age>50</age></個人信息>
</書>
<書>
<書名>數(shù)學(xué)之美</書名>
<作者 title='ADS'>陸奇</作者>
<售價>29</售價>
<個人信息><age>50</age></個人信息>
</書>
</書架>
SAX解析代碼
import java.util.ArrayList;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
// sax 只用于解析數(shù)據(jù),不用于修改xml數(shù)據(jù)。
public class MySaxParserDemo
{
public static void main(String[] args) throws Exception, SAXException
{
// 使用SAXParserFactory創(chuàng)建SAX解析工廠
SAXParserFactory spf = SAXParserFactory.newInstance();
// 通過SAX解析工廠得到解析器對象
SAXParser sp = spf.newSAXParser();
// 通過解析器對象得到一個XML的讀取器
XMLReader xmlReader = sp.getXMLReader();
// 設(shè)置讀取器的事件處理器
xmlReader.setContentHandler(new MySaxHanlder());
// 解析xml文件
xmlReader.parse("book.xml");
}
}
事件處理器
//要用sax解析xml文檔 需要自己去實(shí)現(xiàn)一個事件處理器
// 事件處理器會有一些事件的callback函數(shù),需要我們?nèi)ブ貙?
class MySaxHanlder extends DefaultHandler
{
//用來標(biāo)識區(qū)分相同標(biāo)簽的節(jié)點(diǎn)
boolean flag = false;
int booknum = 0;
//集合用來存放書對象
ArrayList<Book> booklist = new ArrayList<>();
Book book;
//全局變量用來記錄每一次查找解析到的標(biāo)簽 方便清空
String previousTagName;
@Override
/* startElement(String uri,String localName,String qName,Attributes attributes)
* qName - 限定的名稱(帶有前綴),如果限定的名稱不可用,則為空字符串。
* attributes - 元素的屬性。如果沒有屬性,則它將是空的 Attributes 對象
* */
// 每解析到 一個元素(element)的時候都會觸發(fā)這個函數(shù),并且將這個element的屬性attributes和值value當(dāng)作參數(shù)傳進(jìn)來
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException
{
// 找到第二本書的書名
if (qName.equals("書名"))
{
booknum++;
if (booknum==2)
{
flag=true;
}
}
//找到了“書”開始標(biāo)簽
if (qName.equals("書"))
{//創(chuàng)建對象 準(zhǔn)備接收其屬性
book = new Book();
}//找到“作者”標(biāo)簽
else if (qName.equals("作者"))
{//獲取title屬性
String value = attributes.getValue("title");
if (book != null)
{//設(shè)置title
book.setTitle(value);
}
}
//本次查找完成 需要的屬性值已經(jīng)傳給對象
previousTagName = qName;
}
// 當(dāng)解析到一個元素標(biāo)簽的結(jié)束的時候 會調(diào)用
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException
{
// System.out.println("endElement: "+qName);
//找到了“書”結(jié)束標(biāo)簽
if (qName.equals("書"))
{//把書對象加入集合中 同時并將其清空 用于下一次查找
booklist.add(book);
book = null;
}//本標(biāo)簽內(nèi)的查找 結(jié)束 清空tag
previousTagName = "";
}
// 當(dāng)解析到一個文本節(jié)點(diǎn)的時候會調(diào)用
@Override
public void characters(char[] ch, int start, int length)
throws SAXException
{
if (flag)
{//找到了第二個書名節(jié)點(diǎn) 獲取其內(nèi)容
System.out.println("文本節(jié)點(diǎn):" + new String(ch, start, length));
flag = false;
}
//獲取文本節(jié)點(diǎn)內(nèi)容
String text = new String(ch, start, length);
switch (previousTagName)
{//標(biāo)簽值如果匹配<書名> 把書名標(biāo)簽的文本內(nèi)容傳給book對象
case "書名":
book.setName(text);
break;
case "作者":
book.setAuthor(text);
break;
case "售價":
book.setPrice(text);
break;
case "age":
//標(biāo)簽匹配age text中存的是字符串
book.setAge(Integer.parseInt(text));
break;
default:
break;
}
}
// 當(dāng)解析到一個document文檔的開始的時候會調(diào)用
@Override
public void startDocument() throws SAXException
{
System.out.println("startDocument:");
}
// 當(dāng)解析到一個document文檔的結(jié)尾的時候 會調(diào)用
@Override
public void endDocument() throws SAXException
{
System.out.println("endDocument:" + booklist);
}
}
BOOK類
package com.cskaoyan.saxparser;
public class Book
{
String name;
String author;
String price;
int age;
String title;
public Book(String name, String author, String price, int age, String title)
{
super();
this.name = name;
this.author = author;
this.price = price;
this.age = age;
this.title = title;
}
public Book()
{
super();
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAuthor()
{
return author;
}
public void setAuthor(String author)
{
this.author = author;
}
public String getPrice()
{
return price;
}
public void setPrice(String price)
{
this.price = price;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
@Override
public String toString()
{
return "Book [name=" + name + ", author=" + author + ", price=" + price
+ ", age=" + age + ", title=" + title + "]";
}
}
控制臺輸出集合:
startDocument:
文本節(jié)點(diǎn):數(shù)學(xué)之美
endDocument:[Book [name=浪潮之巔, author=吳軍, price=50, age=50, title=null], Book [name=數(shù)學(xué)之美, author=陸奇, price=29, age=50, title=ADS]]
