DOM:文档驱动。DOM在解析文件之前把整个文档装入内存,处理大型文件时其性能很差,是由于DOM的树结构所造成的,此结构占用的内存较多。
SAX(simple API for XML)采用事件驱动的方式解析文档。简单点说,如同在电影院看电影一样,从头到尾看一遍就完了,不能回退(DOM可来来回回读取)在看电影的过程中,每遇到一个情节,一段泪水,一次擦肩,你都会调动大脑和神经去接收或处理这些信息。同样,在SAX的解析过程中,读取到文档开头、结尾,元素的开头和结尾都会触发一些回调方法,你可以在这些回调方法中进行相应事件处理。这四个方法是:
startDocument() 、 endDocument()、 startElement()、 endElement()
此外,光读取到节点处是不够的,我们还需要characters()方法来仔细处理元素内包含的内容。将这些回调方法集合起来,便形成了一个类,这个类也就是我们需要的触发器。
一般从main()方法中读取文档,却在触发器中处理文档,这就是所谓的事件驱动解析方法。
如上图,在触发器中,首先开始读取文档,然后开始逐个解析元素,每个元素中的内容会回调characters()方法,接着结束元素读取,所有元素读取完后,结束文档解析。
SAX解析原理:
通过自己创建的Handler处理类去逐个分析(从最外层到最里层依次去遍历每一个节点)遇到的每一个节点(通过startElement()方法解析开始标记,通过endElement方法解析结束标记)。
SAX方式解析XML文件的步骤:
- 通过SAXParserFactory的静态方法newInstance()方法获取SAXParserFactory的实例factory;
- 通过SAXParserFactory实例的newSAXParser()方法返回一个SAXParser实例parser;
- 创建一个类继承自DefaultHandler,重写其中的一些方法进行业务处理并创建这个类的实例handler;
- 通过SAXParser对象的parse(String uri,DefaultHandler dh)方法解析xml文件。
关于XML文件的解析开始和解析结束:
- 解析开始:当handler指向XML声明;
<?xml version = "1.0" encoding = "utf-8"?>
</bookstore>
实现如下:
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
public class SAXTest {
public static void main(String[] args) {
// 1.获取一个SAXParserFactory的实例
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// 2.通过factory获取SAXParser实例
SAXParser parser = factory.newSAXParser();
//3.创建一个SAXParserHandler对象
SAXParserHandler handler = new SAXParserHandler();
//4.通过SAXParser对象的parse(String uri,DefaultHandler dh)方法解析xml文件
parser.parse("books.xml",handler);
} catch (ParserConfigurationException e) {
e.printstacktrace();
} catch (SAXException e) {
e.printstacktrace();
} catch (IOException e) {
e.printstacktrace();
}
}
}
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/** * 创建一个类继承自DefaultHandler,重写其中的一些方法用来进行业务处理 * */
public class SAXParserHandler extends DefaultHandler {
int bookIndex = 0;// 定义一个全局变量用于保存当前遍历的书的索引(当前正在遍历第几本书)
/** * 用来标志解析开始 */
@Override
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("=============== SAX解析开始 ===============\n");
}
/** * 用来标志解析结束 */
@Override
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("=============== SAX解析结束 ===============");
}
/** * 解析XML文件的开始标签,uri-名称空间,localName-名称空间的标签,如果没有名称空间,则为空 * qName-标签名,attributes-属性集合 */
@Override
public void startElement(String uri,String localName,String qName,Attributes attributes) throws SAXException {
super.startElement(uri,localName,qName,attributes);
System.out.println(">>>>>>>>>>>开始解析元素:" + qName);
// 仅仅book节点有属性
if ("book".equals(qName)) {
bookIndex++;
System.out.println("***********开始遍历第" + (bookIndex)
+ "本书***********");
// 已知book元素有属性名称id,根据属性名获取属性值
// String attrValue = attributes.getValue("id");
// System.out.println("book的属性值是:"+attrValue);
// 不知道book元素的属性名以及属性的个数
int numberOfAttributes = attributes.getLength();// 获取属性个数
for (int i = 0; i < numberOfAttributes; i++) {
System.out.print("book元素的第" + (i + 1) + "个属性名:"
+ attributes.getQName(i));
System.out.println(",属性值:" + attributes.getValue(i));
}
} else if (!"bookstore".equals(qName)) {
System.out.print("节点名:" + qName);
}
}
/** * 字符数组ch-元素中的内容,start-开始位置,length-长度 */
@Override
public void characters(char[] ch,int start,int length)
throws SAXException {
super.characters(ch,start,length);
String value = new String(ch,length);
if (!"".equals(value.trim())) {// 过滤空白文本(和DOM类似)
System.out.println("-节点值:" + value);
}
}
/** * 解析XML文件的结束标签 */
@Override
public void endElement(String uri,String qName)
throws SAXException {
super.endElement(uri,qName);
System.out.println("<<<<<<<<<<<结束解析" + qName);
// 判断是否一本书遍历结束(handler指向</book>)
if ("book".equals(qName)) {
System.out.println("***********结束遍历第" + (bookIndex)
+ "本书***********\n");
}
}
}
运行结果:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。