1. XML SAX解析
1.1 SAX解析器
SAX(Simple API for XML)是一种XML文档解析标准
- 是一个公共的基于事件的解析器
- SAX作为接口,是事件驱动型XML解析的标准接口,对文档进行顺序扫描,当扫描到document开始,element开始与结束,document结束等地方时,通知事件处理函数作出相应的动作。
- 与DOM相比,SAX占用的系统资源更少
1.2 SAX API
事件类型:
- 文档处理事件
- 元素处理事件
- 元数据通常有单独的的事件处理
解析步骤:
- 创建事件处理程序:编写ContenHandler实现类,继承DefaultHandler,采用adapter模式
- 创建SAX解析器
- 将事件处理程序分配到解析器
- 对文档进行解析,将每个事件发送给事件处理程序
关键代码:
常用接口ContentHandler:
- 常用的SAX事件处理的方法:
- void startDocument()
- void endDucument()
- void startElement(String uri,String localName.StringqName,Attibutes atts)
- void endElement(String uri,String localName,StringqName)
- void characters(char[] ch, int start, int length)
- 当XML解析器开始解析文档时,会调用ContentHandler接口中的相应方法来响应事件,这些方法被称为回调方法。
工厂类:SAXParserFactory
- 定义了工厂API接口,供其他程序配置和获取基于SAX的解析器。
- factory=SAXParserFactory.newInstance(): 创建工厂实例
- SAXHandler=factory.newSAXParser():创建SAX解析器。
抽象类:SAXParser
- 该类的实例对象需要同过工厂类SAXParserFactory获取
- 定义了不同参数列表的parse方法将xml文件通过定义好的事件处理器解析成标签元素对象。
类图关系:
Book类是对XML元素面向对象的映射,SAX解析之后,将把元素内容放在Book类的对象book中去。
MySaxHandler是事件处理器,用来识别XML文档中的标签,通过定义标签的事件触发动作完成识别。识别得到的book对象放在List容器中以便管理调用
MySaxParser是对SAX解析器的定制:需要的步骤是:
1. 创建SAXParserFactory工厂类
2. 用工厂对象实例化SAXParse对象parser
3. 将要处理的XML文档和事件处理器交给parser完成XML解析。
上述步骤可以接口的抽象方法parseXML。
4. 编写程序入口:实例化MySaxParser对象,执行其中的parseXml实现方法。
2. 实践分析
我们以bookStore的场景建立一个XML文档,通过SAX解析读取文档内容。
XML文档:
<?xml version="1.0" standalone="yes" encoding="UTF-8"?>
<bookStore>
<book bookNo="001">
<title>Java Coding Language</title>
<author>Jack</author>
<price>40</price>
</book>
<book bookNo="002">
<title>Android Coding Language</title>
<author>Jack</author>
<price>70</price>
</book>
</bookStore>
XML映射的元素类
package xmlSAXDemo;
//从BookStore.xml解析得到的信息会创建成本类的实例对象。
public class Book {
private String bookNo;
private String title;
private String auther;
private double price;
@Override
public String toString() {
return "Book [bookNo=" + bookNo + ", title=" + title + ", auther="
+ auther + ", price=" + price + "]";
}
public Book() {
super();
}
public Book(String bookNo, String title, String auther, double price) {
super();
this.bookNo = bookNo;
this.title = title;
this.auther = auther;
this.price = price;
}
public String getBookNo() {
return bookNo;
}
public void setBookNo(String bookNo) {
this.bookNo = bookNo;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuther() {
return auther;
}
public void setAuther(String auther) {
this.auther = auther;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
创建事件处理程序
package xmlSAXDemo;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MySaxHandler extends DefaultHandler {
private String tag;
private Book book;
private List<Book> bookList;
public List<Book> dump(){
return bookList;
}
/*
* 回调方法的改写
* @see org.xml.sax.helpers.DefaultHandler#startDocument()
*/
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
bookList=new ArrayList<Book>();
}
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
super.startElement(uri, localName, qName, attributes);
//tag内容初始化
tag=qName;
//book对象初始化
if(qName.equals("book")){
book=new Book();
String bookNo=attributes.getValue("bookNo");
book.setBookNo(bookNo);
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
if(qName.equals("book")){
bookList.add(book);
book=null;//book对象格式化
}
tag=null;//tag内容格式化
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
//这些内容的标签解析放在startElement中去做也是可以的。
if(tag!=null){
String str=new String(ch,start,length).trim();
if(tag.equals("title")){
book.setTitle(str);
}if(tag.equals("author")){
book.setTitle(str);
}if(tag.equals("price")){
book.setPrice(Double.parseDouble(str));
}
}
}
}
创建SAX解析器,并将事件处理程序分配到解析器
package xmlSAXDemo;
import java.util.List;
public interface XmlParse {
//从指定的XML文件中返回书的列表
public List<Book> parseXml(String fileName);
}
package xmlSAXDemo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
public class MyParser implements XmlParse {
public List<Book> parseXml(String fileName) {
List<Book> list=new ArrayList<Book>();
SAXParserFactory factory=SAXParserFactory.newInstance();
MySaxHandler handler=null;
//将事件处理程序分配到解析器
try {
SAXParser parser=factory.newSAXParser();
InputStream is=new FileInputStream(fileName);
handler=new MySaxHandler();
parser.parse(is,handler);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} 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();
}
list=handler.dump();
return list;
}
public static void main(String[] args){
XmlParse parser=new MyParser();//接口的引用变量
List<Book> list=parser.parseXml("books.xml");//调用接口实现方法,XML文档要放在当前项目的根目录下。
for(Book book:list){
System.out.println(book.toString());
}
}
}
运行结果: