SAX解析XML
1.XML(Extensible Markup Language 可扩展标记语言),XML是一个以文本来描述数据的文档。
XML文档示例:
<?xml version="1.0" encoding="UTF-8" ?> <people> <person personId="E01"> <name>Tony Blair</name> <address>10 Downing Street,London,UK</address> <tel>(061) 98765</tel> <fax>(061) 98765</fax> <email>qijingjing01@126.com</email> </person> <person personId="E02"> <name>Tony Blair</name> <address>10 Downing Street,London,UK</address> <tel>(061) 98765</tel> <fax>(061) 98765</fax> <email>qijingjing01@126.com</email> </person> </people>
2.XML的用途
(1)充当显示数据(以XML充当显示层)
(2)存储数据(存储层)的功能
(3)以XML描述数据,并在联系服务器与系统的其余部分之间传递
从某种角度讲,XML是数据封装和信息传递技术。
3.什么是SAX?
SAX是Simple Apl for XML的缩写
SAX是读取和操作XML数据更快捷,更轻量的方法,SAX允许你在读取文档时处理它,从而不必等待整个文档被存储后才采取操作,它不涉及DOM所必须得开销和概念跳跃,SAX api是一个基于事件的API ,适用于处理数据流,即随着数据的流动而一依次处理数据。SAX API在其解析你的文档时发生一定事件的时候会通知你,在你对其响应时,你不作保存的数据会被抛弃
SAX API中主要有四种处理事件的接口,ContenHandler、DTDHandler、EntiyResolver和ErrorHandler,由于DefaultHandler实现了这四个事件处理器接口。所以我们只需要继承DefaultHandler类就可以。
4.解析步骤
- 首先,我们把XML文件对应的Person写出来
package com.lili.xmlAndJson; /** * @author: QiJingJing * @create: 2021/7/17 */ public class Person { private String personId; private String name; private String address; private String tel; private String fax; private String email; public Person(){} public Person(String personId, String name, String address, String tel, String fax, String email) { this.personId = personId; this.name = name; this.address = address; this.tel = tel; this.fax = fax; this.email = email; } public String getPersonId() { return personId; } public void setPersonId(String personId) { this.personId = personId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public String getFax() { return fax; } public void setFax(String fax) { this.fax = fax; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "Person{" + "personId='" + personId + '\'' + ", name='" + name + '\'' + ", address='" + address + '\'' + ", tel='" + tel + '\'' + ", fax='" + fax + '\'' + ", email='" + email + '\'' + '}'; } }
- 在测试类里面创建SAX解析器工厂对象
// 1.创建一个SAX解析器工厂对象 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
- 使用解析器工厂创建解析器实例
//2.通过工厂对象创建SAX解析器 SAXParser saxParser = saxParserFactory.newSAXParser();
- 写一个事件侦听器类,需要继承DefaultHandler类,然后重写其中五个方法,每个方法的用途我已经标注
package com.lili.xmlAndJson; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import java.util.ArrayList; import java.util.List; /** * @author: QiJingJing * @create: 2021/7/17 */ public class PersonHandler extends DefaultHandler { private List<Person> personList; private Person p; // 当前正在解析的对象 private String tag;//用于记录当前正在解析的标签名 public List<Person> getPersonList() { return personList; } // 开始解析文档时调用 @Override public void startDocument() throws SAXException { super.startDocument(); personList = new ArrayList<>(); System.out.println("开始解析文档"); } @Override public void endDocument() throws SAXException { super.endDocument(); System.out.println("解析文档结束"); } // 解析开始元素时使用 /** * @param uri 命名空间 * @param localName 不带前缀的标签名 * @param qName 带前缀的标签名 * @param attributes 当前标签的属性集合 * @return: void * @author: QijingJing * @date: 2021/7/17 */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { super.startElement(uri, localName, qName, attributes); if ("person".equals(qName)) { p = new Person(); String personId = attributes.getValue("personId"); p.setPersonId(personId); } tag = qName; } // 解析结束元素时使用 @Override public void endElement(String uri, String localName, String qName) throws SAXException { super.endElement(uri, localName, qName); if ("person".equals(qName)) { personList.add(p); } tag = null; } // 解析文本内容时调用 @Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); if (tag != null) { if ("name".equals(tag)) { p.setName(new String(ch, start, length)); } else if ("address".equals(tag)) { p.setAddress(new String(ch, start, length)); } else if ("tel".equals(tag)) { p.setTel(new String(ch, start, length)); } else if ("fax".equals(tag)) { p.setFax(new String(ch, start, length)); } else if ("email".equals(tag)) { p.setEmail(new String(ch, start, length)); } } } }
- 在测试类里面创建一个侦听器对象,给出XML的地址,然后开始解析
package com.lili.xmlAndJson; import org.junit.Test; import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; import java.io.InputStream; import java.util.List; /** * @author: QiJingJing * @create: 2021/7/17 */ public class XmlTest { @Test public void test() throws ParserConfigurationException, SAXException, IOException { // 1.创建一个SAX解析器工厂对象 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); //2.通过工厂对象创建SAX解析器 SAXParser saxParser = saxParserFactory.newSAXParser(); //3.创建一个数据处理器(需要我们自己来编码) PersonHandler personHandler = new PersonHandler(); // 4.开始解析 InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/lili/xmlAndJson/person.xml"); saxParser.parse(is,personHandler); List<Person> personList = personHandler.getPersonList(); personList.forEach(System.out::println); } }
输出如下:
开始解析文档 解析文档结束 Person{personId='E01', name='Tony Blair', address='10 Downing Street,London,UK', tel='(061) 98765', fax='(061) 98765', email='qijingjing01@126.com'} Person{personId='E02', name='Tony Blair', address='10 Downing Street,London,UK', tel='(061) 98765', fax='(061) 98765', email='qijingjing01@126.com'} Process finished with exit code 0
SAX解析的特点:
1.基于事件驱动
2.顺序读取,速度快
3.不能任意读取节点(灵活性差)
4.解析占用内存小
5.SAX更适用于在性能要求更高的设备上使用(Android开发中)