SAX(simple API for XML)是一种XML解析的替代方法。不需要从外界导入包,它属于JAVA类库中类。
相比于DOM,SAX是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。而且相比于DOM,SAX可以在解析文档的任意时刻停止解析,但任何事物都有其相反的一面,对于SAX来说就是操作复杂。
在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。
SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:
解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
sax解释方式的步骤:
1. 先要创建sax解释器的工厂对象。
2. 可以使用sax解释器的工厂对象生产一个sax解释器。
3. 创建事件处理器类,编写对应的读取方式
4. 使用sax解释器解释xml文件
下面通介绍下相关方法的使用和说明
package demo1;
import java.io.File;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class Demo1 {
public static void main(String[] args) throws Exception {
//创建sax解释器的工厂对象
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
//使用sax解释器的工厂对象生产一个sax解释器
SAXParser saxParser = parserFactory.newSAXParser();
//使用sax解释器解释xml文件了。
saxParser.parse(new File("person.xml"), new MyHandler());
}
}
package demo1;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* 定义事件处理器,需要继承DefaultHandler类
* 需要重写startElement、characters、endElement 3个方法。
*
* @author mChenys
*
*/
public class MyHandler extends DefaultHandler {
/**
* 当sax解释器读到了开始标签的时候会调用该方法。
* localName:当前的标签名字
* attributes:把这个标签的所有属性存储到这个集合中。
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
System.out.println("startElement->"+localName);
}
/**
* 当sax解释器读到了文本内容的时候会调用该方法 ch: 读取到的字符存储到了这个字符数组中。
* start :从字符串数组中的指定索引值开始存储内容。
* length : 存储了多少个字符到字符数组中。
* 注意的细节:
* 1.如果标签体文本有很多的文本数据,那么这时候有可能调用一次characters方法无法读取完毕。这时候就会调用多次的characters方法。
* 2.如果标签体内容出现了实体字符,那么这时候也会分多次读取。
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
System.out.println("characters->"+new String(ch,start,length));
}
/**
* 当sax解释器读到结束标签的时候会调用该方法。
* localName : 结束标签名字
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("endElement->"+localName);
}
}
下面做一个例子,通过demo读取如下xml文件
张三
19
[email protected]
广州天河
李四
20
[email protected]
广州番禺
王五
19
[email protected]
广州天河
赵六
20
[email protected]
广州番禺
并将其按如下格式输出到控制台
{编号:100 姓名:张三 年龄:19 邮箱:[email protected] 地址:广州天河}
{编号:200 姓名:李四 年龄:20 邮箱:[email protected] 地址:广州番禺}
{编号:1000 姓名:王五 年龄:19 邮箱:[email protected] 地址:广州天河}
{编号:2000 姓名:赵六 年龄:20 邮箱:[email protected] 地址:广州番禺}
项目工程如下:
demo2
package demo2;
import java.io.File;
import java.util.ArrayList;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class Demo2 {
/**
* @param args
* @throws Exception
* @throws
*/
public static void main(String[] args) throws Exception {
// 创建sax解释器的工厂对象
SAXParserFactory factory = SAXParserFactory.newInstance();
// 通过释器工厂创建一个sax解释器
SAXParser saxParser = factory.newSAXParser();
// 创建事情处理器对象
MyHandler2 handler2 = new MyHandler2();
// 使用sax解释器解释xml文件
saxParser.parse(new File("person.xml"), handler2);
ArrayList list = handler2.list;
for (Person p : list) {
System.out.println(p);
}
}
}
MyHandler2
package demo2;
import java.util.ArrayList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyHandler2 extends DefaultHandler {
ArrayList list = new ArrayList();
Person p = null;
StringBuilder sb = null;
// 读取开始节点
@Override
public void startElement(String uri, String localName, String tagName,
Attributes attributes) throws SAXException {
if ("person".equals(tagName)) {
p = new Person();// 创建一个person对象
// 设置id
String id = attributes.getValue("id");
p.setId(id);
}
// 创建了一个字符串缓冲区
sb = new StringBuilder();
}
// 读取文本内容
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// 先获取到当前文本的所有内容 地址
String text = new String(ch, start, length);
if (sb != null) {
sb.append(text);
}
}
// 读取结束标签
@Override
public void endElement(String uri, String localName, String tagName)
throws SAXException {
if ("name".equals(tagName)) {
p.setName(sb.toString());
} else if ("age".equals(tagName)) {
p.setAge(sb.toString());
} else if ("email".equals(tagName)) {
p.setEmail(sb.toString());
} else if ("address".equals(tagName)) {
p.setAddress(sb.toString());
} else if ("person".equals(tagName)) {
list.add(p); // 将读取到的包含所有信息的person对象存储到集合中
}
// 清空StringBuilder的内容
sb = null;
}
}
Person
package demo2;
public class Person {
private String id;
private String name;
private String age;
private String email;
private String address;
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(String age) {
this.age = age;
}
public void setEmail(String email) {
this.email = email;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "{编号:" + this.id + " 姓名:" + this.name + " 年龄:" + this.age
+ " 邮箱:" + this.email + " 地址:" + this.address + "}";
}
}
DOM解析:一次性把xml文档内容加载进内存,构建成Document树。
1)不适合读取大容量的xml文件
2)Dom解析可以随意读取,甚至往回读
3)Dom解析可以增删改查
解析工具: DOM4j
SAX解析: 读取一点,解析一点。
1)适合读取大容量的xml文件
2)从上往下逐点读取,不能往回读
3)SAX解析通常只读取文件,不修改文件