package com.demo.b_sax;
import java.io.File;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.junit.Test;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/*
* XML 解析的两种方式:Dom4J解析 和 SAX解析
*
* DOM4J 解析原理:一次性把文档加载进内存,然后在内存中构建 Document 树。
* 缺点:读取大容量的 xml 文档时,占用的内存过大。
*
* SAX 解析原理:加载一点,读取一点,解析一点。对内存要求比较低。
* SAX 解析内置在 jdk 中,可以直接使用;
*
* DOM 解析和 SAX 解析比较:
* DOM 解析:
* 1、原理:XML 解析器一次性把整个 XML 文档加载进内存,然后在内存中构建一棵 Document 的对象树,
* 通过 Document 对象,得到树上的节点对象,通过节点对象操作 XML 文档的内容。
* 一次性加载 XML 文档,不适合大容量的文件读取,比较占用内存;
* 2、DOM 解析可以任意进行增删改查;
* 3、DOM 解析可以读取任意位置的数据,甚至往回读;
* 4、DOM 解析是面向对象的编程方法(Node、Element、Attribute),开发编码比较简单;
* SAX 解析:
* 1、原理:加载一点,读取一点,解析一点。适合大容量文件的读取。
* 2、SAX 解析只能读取;
* 3、SAX 解析只能从上往下,按顺序读取,不能往回读;
* 4、SAX 解析是基于事件的读取方法,开发编码相对复杂。
*
* 核心 API:
* SAXParser 类:解析器,用于读取和解析 XML 文档;
* parse(File f, DefaultHandler dh) 方法:解析 XML 文件;
* 参数1:File,表示要解析的 xml 文件;
* 参数2:DefaultHandler,SAX 事件处理程序。使用 DefaultHandler 的子类。
*/
public class Demo1 {
@Test
public void test1() throws Exception {
// 1、创建 SAXParser 解析器对象
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
// 2、调用 parse 方法;读取 xml 文档时,会自动执行 MyDefaultHandler 类。
parser.parse(new File("./src/contact.xml"), new MyDefaultHandler());
}
/**
* SAX 处理程序 从上往下,逐部分读取;
*/
class MyDefaultHandler extends DefaultHandler {
/**
* 读到文档开始时调用
*/
@Override
public void startDocument() throws SAXException {
System.out.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
}
/**
* 读到文档结束时调用
*/
@Override
public void endDocument() throws SAXException {
// System.out.println("endDocument");
}
/**
* 读到开始标签时调用;属性在开始标签中。前面两个参数不用;
*
* @param qName
* 表示开始标签的标签名
* @param attributes
* 表示开始标签内包含的属性
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
System.out.print("<" + qName);
// 获取属性
for (int i = 0; i < attributes.getLength(); i++) {
String attrName = attributes.getQName(i); // 获取属性的名称
String attrValue = attributes.getValue(i); // 获取属性的值
System.out.print(" " + attrName + "=\"" + attrValue + "\"");
;
}
System.out.print(">");
}
/**
* 读到 结束标签 时调用
*
* @param qName
* 表示结束标签的名字
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.print("</" + qName + ">");
}
/**
* 读到 文本内容 时调用
*
* @param ch
* 表示读取到的 XML 文档中所有的文本内容
* @param start
* 表示当前文本内容的开始位置
* @param length
* 表示当前文本内容的长度
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
System.out.print(new String(ch, start, length));
}
}
}
package com.demo.b_sax;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.junit.Test;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.demo.a_dom4j.Contact;
/*
* 使用 SAX 方法读取 XML 文档,将数据封装到 Javabean 中
*/
public class Demo2 {
@Test
public void test1() throws Exception{
// 创建 SAXParser 解析器对象
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
// 调用 parse() 方法
parser.parse(new File("./src/contact.xml"), new MyDefaultHandler());
}
class MyDefaultHandler extends DefaultHandler{
/*
* 思路:
* 1、每次读取到 contact 开始标签时,创建一个 contact 对象;
* 2、把每个 contact 标签的内容存储到 contact 对象中;
* 3、每次读到 contact 结束标签时,把 contact 对象放入 list 集合中;
*/
List<Contact> lists = null; // 存储 javabean 对象的集合
Contact contact = null; // javabean 对象
String currTag = ""; // 记录当前标签
/**
* 读到 文档开始 时调用
*/
@Override
public void startDocument() throws SAXException {
lists = new ArrayList<Contact>();
}
/**
* 读到 文档结束 时调用
*/
@Override
public void endDocument() throws SAXException {
for (Contact cont : lists){
System.out.println(cont);
}
}
/**
* 读到 开始标签 时调用
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
// 记录当前 标签的名字
currTag = qName;
// 每次读到 contact 开始标签时创建一个 contact 对象
if (qName.equals("contact")){
contact = new Contact();
// 因为 id 属性在 contact 标签中,所以可以直接获取 id 属性的值,封装进 contact 对象中
contact.setId(attributes.getValue("id"));
}
}
/**
* 读到 结束标签 时调用
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// 设置为空是为了避免把空格换行设置到对象的属性中
currTag = "";
// 读到 contact 结束标签时,将 contact 对象存入集合中
if (qName.equals("contact")){
lists.add(contact);
}
}
/**
* 读到 文本内容 时调用
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// 读取到当前文本的内容
String text = new String(ch, start, length);
if (currTag.equals("name")){
contact.setName(text);
}
if (currTag.equals("age")){
contact.setAge(text);
}
if (currTag.equals("phone")){
contact.setPhone(text);
}
if (currTag.equals("email")){
contact.setEmail(text);
}
if (currTag.equals("qq")){
contact.setQq(text);
}
}
}
}
其中 ./src/contact.xml 为:
<?xml version="1.0" encoding="utf-8"?>
<contactList>
<contact id="001" name="eric">
<name>张三</name>
<age>20</age>
<phone>134222223333</phone>
<email>zhangsan@qq.com</email>
<qq>432221111</qq>
</contact>
<contact id="002">
<name>李四</name>
<age>20</age>
<phone>134222225555</phone>
<email>lisi@qq.com</email>
<qq>432222222</qq>
</contact>
<abc></abc>
</contactList>
其中 Javabean(Contact.java)为:
package com.demo.a_dom4j;
public class Contact {
private String id;
private String name;
private String age;
private String phone;
private String email;
private String qq;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
@Override
public String toString() {
return "Contact [id=" + id + ", name=" + name + ", age=" + age + ", phone=" + phone + ", email=" + email
+ ", qq=" + qq + "]";
}
}