1. Java解析XML簡(jiǎn)介
Java庫(kù)中提供了兩種XML解析器:
- 像文檔對(duì)象模型(Document Object Model,DOM)解析器這的
樹型解析器(tree parse),它們將讀入的XML文檔轉(zhuǎn)換成樹結(jié)構(gòu)。 - 像XML簡(jiǎn)單API(Simple API for XML,SAX)解析器這樣的
流機(jī)制解析器(streaming parser),它們?cè)谧x入XML文檔時(shí)生成相應(yīng)的事件。
2. SAX簡(jiǎn)介
SAX解析器在解析XML輸入數(shù)據(jù)的各個(gè)組成部分時(shí)會(huì)報(bào)告事件,但不會(huì)以任何方式存儲(chǔ)文檔,而是由事件處理器建立相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。實(shí)際上DOM解析器是在SAX解析器的基礎(chǔ)上構(gòu)建的,它在接收到解析器事件時(shí)構(gòu)建DOM樹。
3. 使用SAX解析器

在使用SAX解析器時(shí),需要一個(gè)處理器來為各種解析器事件定義事件動(dòng)作。DefaultHandler接口定義了若干個(gè)在解析文檔時(shí)解析器會(huì)調(diào)用的回調(diào)方法。下面是最重要的幾個(gè)方法:
- startElement和endElement在每當(dāng)遇到起始或終止標(biāo)簽時(shí)調(diào)用。
- characters在每當(dāng)遇到字符數(shù)據(jù)時(shí)調(diào)用。
- startDocument和endDocument分別在文檔開始和結(jié)束時(shí)各調(diào)用一次。
例如,在解析以下片段時(shí):
<person>
<name type="string">韓信</name>
<age>25</age>
</person>
解析器會(huì)產(chǎn)生以下回調(diào):
1)startElement,元素名:person
2)startElement,元素名:name ,屬性:type="string"
3)characters,內(nèi)容:韓信
4)endElement,元素名:name
5)startElement,元素名:age
6)characters,內(nèi)容:25
7)endElement,元素名:age
8)endElement,元素名:person
處理器必須覆蓋這些方法,讓它們執(zhí)行在解析文件時(shí)我們想讓它們執(zhí)行的動(dòng)作。
下面通過一個(gè)簡(jiǎn)單的demo體會(huì)SAX解析XML的過程。
3.1 準(zhǔn)備xml
首先準(zhǔn)備person.xml,內(nèi)容如下
<?xml version="1.0" encoding="UTF-8" ?>
<persons>
<person>
<name>韓信</name>
<age>25</age>
</person>
<person>
<name>李白</name>
<age>23</age>
</person>
</persons>
3.2 解析代碼
- 獲取解析工廠
- 從解析工廠獲取解析器
- 得到解讀器
- 設(shè)置內(nèi)容處理器
- 讀取xml的文檔內(nèi)容
package cn.lastwhisper.javabasic.Sax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
/**
* @author lastwhisper
* @desc SAX方式解析xml文件
* @email gaojun56@163.com
*/
public class SaxTest {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
// SAX解析
// 1.獲取解析工廠
SAXParserFactory factory = SAXParserFactory.newInstance();
// 2.從解析工廠獲取解析器
SAXParser parse = factory.newSAXParser();
// 3.得到解讀器
XMLReader reader=parse.getXMLReader();
// 4.設(shè)置內(nèi)容處理器
reader.setContentHandler(new PHandler());
// 5.讀取xml的文檔內(nèi)容
reader.parse("src/main/java/cn/lastwhisper/javabasic/Sax/person.xml");
}
}
class PHandler extends DefaultHandler {
/**
* @author lastwhisper
* @desc 文檔解析開始時(shí)調(diào)用,該方法只會(huì)調(diào)用一次
* @param
* @return void
*/
@Override
public void startDocument() throws SAXException {
System.out.println("----解析文檔開始----");
}
/**
* @author lastwhisper
* @desc 每當(dāng)遇到起始標(biāo)簽時(shí)調(diào)用
* @param uri xml文檔的命名空間
* @param localName 標(biāo)簽的名字
* @param qName 帶命名空間的標(biāo)簽的名字
* @param attributes 標(biāo)簽的屬性集
* @return void
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println("標(biāo)簽<"+qName + ">解析開始");
}
/**
* @author lastwhisper
* @desc 解析標(biāo)簽內(nèi)的內(nèi)容的時(shí)候調(diào)用
* @param ch 當(dāng)前讀取到的TextNode(文本節(jié)點(diǎn))的字節(jié)數(shù)組
* @param start 字節(jié)開始的位置,為0則讀取全部
* @param length 當(dāng)前TextNode的長(zhǎng)度
* @return void
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String contents = new String(ch, start, length).trim();
if (contents.length() > 0) {
System.out.println("內(nèi)容為-->" + contents);
} else {
System.out.println("內(nèi)容為-->" + "空");
}
}
/**
* @author lastwhisper
* @desc 每當(dāng)遇到結(jié)束標(biāo)簽時(shí)調(diào)用
* @param uri xml文檔的命名空間
* @param localName 標(biāo)簽的名字
* @param qName 帶命名空間的標(biāo)簽的名字
* @return void
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println("標(biāo)簽</"+qName + ">解析結(jié)束");
}
/**
* @author lastwhisper
* @desc 文檔解析結(jié)束后調(diào)用,該方法只會(huì)調(diào)用一次
* @param
* @return void
*/
@Override
public void endDocument() throws SAXException {
System.out.println("----解析文檔結(jié)束----");
}
}
運(yùn)行main函數(shù),查看運(yùn)行結(jié)果

3.3 分析解析過程
----解析文檔開始---- 調(diào)用startDocument
標(biāo)簽<persons>解析開始 調(diào)用startElement
內(nèi)容為-->空 調(diào)用characters,因?yàn)?lt;persons></persons>之間只有標(biāo)簽沒有內(nèi)容,所以為空。
標(biāo)簽<person>解析開始 調(diào)用startElement
內(nèi)容為-->空 調(diào)用characters,因?yàn)?lt;person></person>之間只有標(biāo)簽沒有內(nèi)容,所以為空。
標(biāo)簽<name>解析開始 調(diào)用startElement
內(nèi)容為-->韓信 調(diào)用characters,<name>韓信</name>之間內(nèi)容為:韓信
標(biāo)簽</name>解析結(jié)束 調(diào)用endElement
內(nèi)容為-->空 調(diào)用characters,每次執(zhí)行完調(diào)用endElement之后會(huì)調(diào)用一次characters
標(biāo)簽<age>解析開始 調(diào)用startElement
內(nèi)容為-->25 調(diào)用characters,<age>25</age>之間內(nèi)容為:25
標(biāo)簽</age>解析結(jié)束 調(diào)用endElement
內(nèi)容為-->空 調(diào)用characters,每次執(zhí)行完調(diào)用endElement之后會(huì)調(diào)用一次characters
標(biāo)簽</person>解析結(jié)束 調(diào)用endElement
內(nèi)容為-->空 調(diào)用characters,每次執(zhí)行完調(diào)用endElement之后會(huì)調(diào)用一次characters
...
標(biāo)簽<person>解析開始
內(nèi)容為-->空
標(biāo)簽<name>解析開始
內(nèi)容為-->李白
標(biāo)簽</name>解析結(jié)束
內(nèi)容為-->空
標(biāo)簽<age>解析開始
內(nèi)容為-->23
標(biāo)簽</age>解析結(jié)束
內(nèi)容為-->空
標(biāo)簽</person>解析結(jié)束
內(nèi)容為-->空
標(biāo)簽</persons>解析結(jié)束
----解析文檔結(jié)束---- 調(diào)用endDocument,xml解析結(jié)束
4. 解析xml到pojo對(duì)象
待解析的xml,person.xml
<?xml version="1.0" encoding="UTF-8" ?>
<persons>
<person>
<name>韓信</name>
<age>25</age>
</person>
<person>
<name>李白</name>
<age>23</age>
</person>
</persons>
xml轉(zhuǎn)換為pojo的代碼
package cn.lastwhisper.javabasic.Sax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @author lastwhisper
* @desc 將xml數(shù)據(jù)解析到pojo中
*
* @email gaojun56@163.com
*/
public class SaxXmlToPojo {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
// SAX解析
// 1.獲取解析工廠
SAXParserFactory factory = SAXParserFactory.newInstance();
// 2.從解析工廠獲取解析器
SAXParser parse = factory.newSAXParser();
// 3.得到解讀器
XMLReader reader = parse.getXMLReader();
// 4.設(shè)置內(nèi)容處理器
PersonHandler personHandler = new PersonHandler();
reader.setContentHandler(personHandler);
// 5.讀取xml的文檔內(nèi)容
reader.parse("src/main/java/cn/lastwhisper/javabasic/Sax/person.xml");
List<Person> persons = personHandler.getPersons();
for (Person person : persons) {
System.out.println("姓名:" + person.getName() + " 年齡:" + person.getAge());
}
}
}
class PersonHandler extends DefaultHandler {
private List<Person> persons;
private Person person;
private String tag; // 存儲(chǔ)操作標(biāo)簽
/**
* @author lastwhisper
* @desc 文檔解析開始時(shí)調(diào)用,該方法只會(huì)調(diào)用一次
* @param
* @return void
*/
@Override
public void startDocument() throws SAXException {
persons = new ArrayList<Person>();
}
/**
* @author lastwhisper
* @desc 標(biāo)簽(節(jié)點(diǎn))解析開始時(shí)調(diào)用
* @param uri xml文檔的命名空間
* @param localName 標(biāo)簽的名字
* @param qName 帶命名空間的標(biāo)簽的名字
* @param attributes 標(biāo)簽的屬性集
* @return void
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
tag = qName;
if ("person".equals(tag)) {
person = new Person();
}
}
/**
* @author lastwhisper
* @desc 解析標(biāo)簽的內(nèi)容的時(shí)候調(diào)用
* @param ch 字符
* @param start 字符數(shù)組中的起始位置
* @param length 要從字符數(shù)組使用的字符數(shù)
* @return void
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String contents = new String(ch, start, length).trim();
if ("name".equals(tag)) {
person.setName(contents);
} else if ("age".equals(tag)) {
if (contents.length() > 0) {
person.setAge(Integer.valueOf(contents));
}
}
}
/**
* @author lastwhisper
* @desc 標(biāo)簽(節(jié)點(diǎn))解析結(jié)束后調(diào)用
* @param uri xml文檔的命名空間
* @param localName 標(biāo)簽的名字
* @param qName 帶命名空間的標(biāo)簽的名字
* @return void
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("person".equals(qName)) {
persons.add(person);
}
tag = null; //tag丟棄了
}
/**
* @author lastwhisper
* @desc 文檔解析結(jié)束后調(diào)用,該方法只會(huì)調(diào)用一次
* @param
* @return void
*/
@Override
public void endDocument() throws SAXException {
}
public List<Person> getPersons() {
return persons;
}
}
運(yùn)行結(jié)果:
