在上篇文章里,我介绍了如何通过DOM的方法解析XML文件,但是呢,用DOM解析XML太过繁琐,这里我们用另外一种更简洁的方式——SAX,来解析XML文件
通过SAX方式解析XML步骤如下:
1,获取SAXParserFactory实例
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
2,通过SAXParserFactory实例获取SAXParser实例
SAXParser parser= saxFactory.newSAXParser();
3,创建一个handler对象,通过parse(uri, dh)方法传入一个handler对象来解析xml
parser.parse("books.xml",new DefaultHandler);
这里传入的handler是一个DefaultHandler对象,在本实例中我们自己写一个类(MySAXParserHandler)通过继承DefaultHandler并实现其中的一些必要的方法来解析XML
再解析的同时,我们再写一个Book实体类,用来保存xml数据的结构
Book类
package xml.sax.entity;
/**
* Book实体类,用来保存xml数据的结构
* @author Lowp
*
*/
public class Book {
private String id;
private String name;
private String author;
private String year;
private String price;
private String language;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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 getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
}
MySAXParserHandler类代码:
package xml.sax.handler;
import java.util.ArrayList;
import java.util.List;
import javax.xml.stream.events.StartElement;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import xml.sax.entity.Book;
public class MySAXParserHandler extends DefaultHandler {
int bookIndex = 0; //用来记录book标签中属性的索引值
String nodeValue = null;
Book book = new Book();
private ArrayList<Book> bookList = new ArrayList<Book>();
/**
* 用来标识解析开始
*/
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("SAX解析XML开始");
}
/**
* 用来标识解析结束
*/
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("SAX解析XML结束");
}
/**
* 用来遍历xml的开始标签
* qName:标签名(节点名)
*
*/
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
//如果解析到book标签,开始解析book标签的属性
if(qName.equals("book")){
System.out.println("================第"+ bookIndex + "本书遍历开始================" );
bookIndex++;
//创建一个book对象
book = new Book();
// /**
// * 【1】已知book标签下属性的名称和个数,通过属性名获取对应的属性值
// */
// String value = attributes.getValue("id");
// System.out.println("book标签“id”属性的属性值是" + value);
/**
* 【2】不知道book标签下属性的名称和个数,
*/
//获取book标签中,属性的个数
int valueSum = attributes.getLength();
for (int i = 0; i < valueSum; i++) {
//通过索引值获取对应的属性名
String valueName = attributes.getQName(i);
System.out.print("book标签的第" + (i+1) + "个属性名是:" + valueName);
//通过索引值获取对应的属性值
String value = attributes.getValue(i);
System.out.println("--->属性值为:" + value);
//将数据保存到Book实体类中
if(valueName.equals("id")){
book.setId(value);
}
}
//
}else if(!qName.equals("bookstore") && !qName.equals("book")){
System.out.print("节点名:" + qName);
}
}
/**
* 用来遍历xml的结束标签
*/
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
if(qName.equals("book")){
//将遍历完的书保存到list中
bookList.add(book);
//清空book,开始下一次遍历
book = null;
System.out.println("================第"+ bookIndex + "本书遍历结束================" + "\n");
}else if(qName.equals("name")){
book.setName(nodeValue);
}
else if(qName.equals("author")){
book.setAuthor(nodeValue);
}
else if(qName.equals("year")){
book.setYear(nodeValue);
}
else if(qName.equals("price")){
book.setPrice(nodeValue);
}
else if(qName.equals("language")){
book.setLanguage(nodeValue);
}
}
/**
*
* char[] ch:整个xml文本内容
* int start:开始标签后的第一个位置
* int length:开始标签后的第一个位置到结束标签间的片段
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
//获取节点值
nodeValue = new String(ch, start, length);
//去空格换行
if(!nodeValue.trim().equals("")){
System.out.println("--->节点值:" + nodeValue);
}
}
public ArrayList<Book> getBookList() {
return bookList;
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<sax></sax>
......
public void characters(char[] ch, int start, int length)
throws SAXException {
System.out.println("run.....");
System.out.print(new String(ch,start,length));
}
......
(2)sax 标签的内容为一个空字符串
.......
<sax> </sax>
......
运行结果:
run ......
characters方法执行一次
(3)有嵌套子标签
<sax>
<name>123</name>
</sax>
分析:
当解析到<sax> 时候,
遇到一个位于 sax 与 name 标签之间的“回车符”
characters 被执行,输出 run ...
遇到“123”的时候被执行 输出 “run .... 123”
遇到</name> 与 </sax> 之间的回车符 输出 “run..... ”
运行结果:
run .....
run ..... 123
run ......
characters 方法执行三次
总结:<></> 之间遇到任何 "回车符" "空格符"或其他"不为空"的字符都将触发characters 方法
测试类:
package xml.sax.test;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.sun.xml.internal.ws.api.ha.HaInfo;
import xml.sax.entity.Book;
import xml.sax.handler.MySAXParserHandler;
/**
* 通过SAX方式解析xml文件
*/
public class SAXTest {
public static void main(String[] args) {
/**
* 1.获取SAXParserFactory实例
*/
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
try {
/**
* 2.通过SAXParserFactory实例获取SAXParser实例(工厂模式)
*/
SAXParser parser= saxFactory.newSAXParser();
/**
* 3.创建一个handler对象,通过parse(uri, dh)方法传入一个handler对象来解析xml
*/
MySAXParserHandler handler = new MySAXParserHandler();
parser.parse("books.xml",handler);
parser.parse(uri,new DefaultHandler())
System.out.println("共有" + handler.getBookList().size() + "本书" + "\n");
for (Book book : handler.getBookList()) {
System.out.println("Id:" + book.getId());
System.out.println("Language:" + book.getLanguage());
System.out.println("Name:" + book.getName());
System.out.println("Price:" + book.getPrice());
System.out.println("Year:" + book.getYear());
System.out.println("Author:" + book.getAuthor());
System.out.println("======finish======");
}
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
================第0本书遍历开始================
book标签的第1个属性名是:id--->属性值为:1
节点名:name--->节点值:冰与火之歌
节点名:author--->节点值:乔治马丁
节点名:year--->节点值:2014
节点名:price--->节点值:89
================第1本书遍历结束================
book标签的第1个属性名是:id--->属性值为:2
节点名:name--->节点值:安徒生童话
节点名:year--->节点值:2004
节点名:price--->节点值:77
节点名:language--->节点值:English
================第2本书遍历结束================
共有2本书
Language:null
Name:冰与火之歌
Price:89
Year:2014
Author:乔治马丁
======finish======
Id:2
Language:English
Name:安徒生童话
Price:77
Year:2004
Author:null
======finish======