SAX(simpleAPIforXML)是一种XML解析的替代方法。相比于DOM,SAX是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。而且相比于DOM,SAX可以在解析文档的任意时刻停止解析,但任何事物都有其相反的一面,对于SAX来说就是操作复杂。
SAX解析XML文档采用事件驱动模式。什么是事件驱动模式?它将XML文档转换成一系列的事件,由单独的事件处理器来决定如何处理。
基于事件驱动的处理模式主要是基于事件源和事件处理器(或者叫监听器)来工作的。一个可以产生事件的对象叫做事件源,而一个可以针对事件作出响应的对象就被叫做事件处理器。
SAX技术在处理XMl文件时并不一次性把XML文件装入内存,而是一边读一边解析。因此,这就需要处理如下5个分析点,也可称为分析事件。
- 开始分析XML文件。该分析点表示SAX引擎刚开始处理XML文件,还没有读取XML文件中的内容。该分析点对应于DefaultHandler类中的startDocument事件方法。可以在该方法中做一些初始化的工作。
- 开始处理每一个XML元素,也就是遇到<product>、<item>这样的起始标记。SAX引擎每次扫描到新的XML元素的其实标记时会触发这个分析事件,对应的事件方法是startElement。在该方法中可以获得当前元素的名称,元素属性的相关信息。
- 处理完一个XML元素,也就是遇到</product>、</item>这样的结束标记。该分析点对应的事件方法是endElement。在该事件中可以获得当前处理完的元素的全部信息。
- 处理完XML文件。如果SAX引擎将整个XML文件的内容都扫描完了就到了这个分析点,该分析点对应的事件方法是endDocument。该事件方法可能不是必需的,如果最后有一些收尾工作,如释放一些资源,可以在该方法中完成。
- 读取字符分析点。这是最重要的分析点。如果没有这个分析点,前4
步的处理相当于白跑了一遍,虽然读取了XML文件中的所有内容,但并未保存这些内容。而这个分析点所对应的characters事件方法的主要作用就是保存SAX引擎读取的XMl文件中的内容。更准确地说是保存XML元素的文本,也就是<product>abc</product>中的abc.
在SAX接口中,事件源是org.xml.sax包中的XMLReader,他通过parse()方法开始解析XML文档,并根据文档内容产生事件。而事件处理器则是org.xml.sax包中的ContentHandler、DTDHandler、ErrorHandler,以及EntityResolver这四个接口。他们分别处理事件源在解析过程中产生不同类的事件(其中DTDHandler为解析文档DTD时所用)。详细介绍如下表:
XML文件:
<?xml version="1.0" encoding="utf-8"?>
<products>
<product>
<id>10</id>
<name>电脑</name>
<price>2067.25</price>
</product>
<product>
<id>20</id>
<name>微波炉</name>
<price>520</price>
</product>
</products>
Product类的代码:
package com.sax.xml;
public class Product {
private int id;
private String name;
private float price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
}
上面XML文件<product>标签中的3个子标签的值与Product类的3个属性对应。
SAXParseXML解析类,该类是DefaultHandler的子类,代码如下:
package com.sax.xml;
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 SAXParseXML extends DefaultHandler {
private List<Product> products;
private Product product;
private StringBuffer buffer = new StringBuffer();
public List<Product> getProducts() {
return products;
}
@Override
public void startDocument() throws SAXException {
products = new ArrayList<Product>();
super.startDocument();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if (localName.equals("product")) {
product = new Product();
}
super.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (localName.equals("product")) {
products.add(product);
}else if (localName.equals("id")) {
product.setId(Integer.parseInt(buffer.toString().trim()));
buffer.setLength(0);
}else if (localName.equals("name")) {
product.setName(buffer.toString().trim());
}else if (localName.equals("price")) {
product.setPrice(Float.parseFloat(buffer.toString().trim()));
buffer.setLength(0);
}
super.endElement(uri, localName, qName);
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
buffer.append(ch, start, length);
super.characters(ch, start, length);
}
}
- startDocument:第一个分析点 事件方法。在该方法中创建了用于保存转换结果的List<Product>对象。
- startElement:第二个分析点事件方法。SAX引擎分析到每一个<product>元素时,在该方法中都创建一个Product对象。
- endElement: 第三个分析点事件方法。该方法中的代码最复杂,但仔细看一下,其实很简单。当SAX引擎分析完每一个XML元素后,会将该元素中的文本保存在Product对象的响应属性中。
- endDocument:第四个分析点事件方法。在该方法中什么都没有做,也没有覆盖这个方法。
- characters:第五个分析点事件方法。虽然该方法中的代码有开发人员编写的只有一行,但十分关键。在该方法中将SAX引擎扫描到的内容保存在buffer变量中。而在endElement方法中要使用该变量中的内容为Product对象中的属相赋值。
最后去调用这个解析类:
package com.sax.xml;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;
import com.sax.xml.Product;
import com.sax.xml.SAXParseXML;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.util.Xml;
public class Main extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
FileInputStream fis = new FileInputStream("/mnt/sdcard/product.xml");
SAXParseXML saxParseXML = new SAXParseXML();
android.util.Xml.parse(fis, Xml.Encoding.UTF_8, saxParseXML);
List<Product> products = saxParseXML.getProducts();
System.out.println("共"+products.size()+"个产品");
for (Product product : products) {
System.out.println("id: "+product.getId()+" 产品名: "+product.getName()+" 价格: "+product.getPrice());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果如下: