SAX解析
SAX解析介绍
由于DOM解析XML的弊端,一种替代的技术就是使用SAX解析。
SAX是基于事件模型的XML解析方式,不需要将整个XML文档加载到内存中,只需加载一部分即可开始解析,在处理过程中不会在内存中记录XML中的数据,占用的资源比较少,当程序处理满足一定条件时,可以立即停止解析,这样不必解析剩余的XML内容。
SAX处理机制
SAX解析主要涉及两个部分:解析器和事件处理器。解析器负责读取XML文档,并向事件处理器发送事件,如元素开始和结束事件;事件处理器则负责对事件做出响应,对传递的XML数据进行处理。
当SAX解析器解析到某类型节点时,会触发注册在该类型节点上的回调函数,继承SAX提供的DefaultHandler来重写相应事件的处理方法并进行注册即可。(事件是由解析器产生并通过回调函数发送给应用程序的,这种模式称为推模式)。
SAX接口介绍
- SAXParserFactory 获取SAX解析器的工厂类
- SAXParser SAX解析器的标准接口
监听器
SAX解析事件一共有四种监听器
EntityResolver 监听实体处理时间的监听器
1
2
3
4
5
6
7public interface EntityResolver {
public abstract InputSource resolveEntity (String publicId,
String systemId)
throws SAXException, IOException;
}DTDHandler 监听DTD处理事件的监听器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public interface DTDHandler {
// 解析DTD符号时触发
public abstract void notationDecl (String name,
String publicId,
String systemId)
throws SAXException;
// 解析DTD中的未解析实体时触发
public abstract void unparsedEntityDecl (String name,
String publicId,
String systemId,
String notationName)
throws SAXException;
}ContentHandler 监听XML文档内容处理事件的监听器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58public interface ContentHandler
{
public void setDocumentLocator (Locator locator);
// 开始处理文档时触发
public void startDocument ()
throws SAXException;
// 处理文档结束时触发
public void endDocument()
throws SAXException;
// 开始处理元素中的命名空间属性时触发(xmlns:prefix属性)
public void startPrefixMapping (String prefix, String uri)
throws SAXException;
// 处理元素中的命名空间属性结束时触发(xmlns:prefix属性)
public void endPrefixMapping (String prefix)
throws SAXException;
// 开始处理元素时触发
public void startElement (String uri, String localName,
String qName, Attributes atts)
throws SAXException;
// 处理元素结束时触发
public void endElement (String uri, String localName,
String qName)
throws SAXException;
// 处理字符数据时触发
public void characters (char ch[], int start, int length)
throws SAXException;
// 处理元素内容中可忽略的空白时触发
public void ignorableWhitespace (char ch[], int start, int length)
throws SAXException;
// 处理指令时触发
public void processingInstruction (String target, String data)
throws SAXException;
// 跳过实体时触发
public void skippedEntity (String name)
throws SAXException;
}ErrorHandler 监听解析错误的监听器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public interface ErrorHandler {
public abstract void warning (SAXParseException exception)
throws SAXException;
public abstract void error (SAXParseException exception)
throws SAXException;
public abstract void fatalError (SAXParseException exception)
throws SAXException;
}
这么多接口都进行实现那是不是太麻烦了呢,瞬间就不想用SAX来进行解析了,不过JAXP提供了一个类来很好的解决这个问题DefaultHandler,该类实现了这四个接口
1 | public class DefaultHandler implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler |
并对这些方法提供了空实现,通常只需要继承该类来重写我们需要关心的监听方法即可
1 | public static SAXParser createDefaultParser(InputStream stream,DefaultHandler handler) throws ParserConfigurationException, SAXException, IOException { |
SAX的缺点
- 由于不存储XML文档结构,需要开发人员自己负责维护多层节点之间的关系
- 由于是流式处理,只能单向处理,无法回到之前处理过的节点
- 不提供写文档的功能
DOM和SAX比较
- 速度 DOM需要一次性装载整份文档,并将xml文档转为DOM树,速度较慢;SAX顺序解析XML文档,无需一次装载整份文档,速度较快
- 重复访问 DOM转换为DOM树后,整个解析阶段DOM树常驻内存,非常适合重复访问,效率较高;SAX顺序解析XML文档,不会保存已访问的数据,不适合重复访问,如果需要重复访问需要再次开始解析
- 内存要求 DOM整个解析阶段DOM树常驻内存,内存占用较多;SAX不保存已访问数据,内存占用低
- 修改 DOM既可以读取节点内容,也可以修改节点内容;SAX只能用来读取,不可修改
- 复杂度 DOM完全采用面向对象的思想,整份XML转为DOM树后,以面向对象的方式来操作各个Node对象即可;SAX采用事件驱动的方式,SAX解析器只负责触发事件,程序负责监听事件,并通过事件获取XML中的内容,比较麻烦