Android(安卓)XML解析之SAX解析 简单示例讲解
Android开发里,解析xml是很常见的场景了,其中SAX解析与PULL解析是两种比较常用的解析方式。
PULL方式解析xml的文章可点这里:Android XML解析之PULL解析 简单示例讲解
除此之外还有DOM解析,这个不太常用,因为它需一次性把xml文件加载到内存里,如果是大文件的话,很占内存,影响性能。
而SAX(Simple API for XML)解析是事件驱动的流式解析方式,并不是把xml全部加载到内存,而是一边读取一边解析,不可暂停或者倒退,直到结束。在解析过程中,会判断当前的节点及内容,而触发不同的方法被调用。我们需要重写这些回调方法,实现自己的处理。
SAX解析的优点:占用内存少,速度快,如果对性能要求比较高,推荐使用。
缺点:不像DOM解析一样将文档长期驻留在内存中,数据不是持久的。如果事件过后没有保存数据,数据就会丢失。
本篇文章,会用一个简单的例子示例下SAX解析的用法。
一、先准备一个简单的xml文件。
路径:res/raw/person_data.xml:
<?xml version="1.0" encoding="UTF-8"?><data> <person id="5"> <name>Jackname> <age>25age> person> <person id="20"> <name>Rosename> <age>80age> person>data>
二、新建一个Person类。
我们的目标是把上面的xml数据(两个person)转换成一个Person列表。
Person类如下,和xml里的属性一一对应:
public class Person { private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; }}
下面先看看如何用SAX方式解析上面的xml:
三、定义解析处理器。
我们需要继承自org.xml.sax.helpers.DefaultHandler类,实现一个解析处理器类。这个DefaultHandler类里比较重要的方法是下面几个,可以选择性的重写:
startDocument() —— 开始解析的时候被调用,可以在此方法里做一些初始化的准备工作。
startElement(String uri, String localName, String qName, Attributes attributes) —— 此方法在每次解析到一个开始节点的时候被调用。其中uri表示元素的命名空间;localName表示元素的本地名称(不带前缀);qName表示元素的限定名(带前缀);attrs表示元素的属性集合。
characters(char[] ch, int start, int length) —— 接收字符数据的通知。改方法用来处理在XML文件中读到的内容,第一个参数用来存放文件的内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度。使用newSreing(ch,start,length)就可以获取内容。这个方法被调用的次数最多,包括换行符也会被当做内容而传进这个方法里。
endElement(String uri, String localName, String qName) —— 在每次遇到结束节点的时候被调用。其中uri表示元素的命名空间;localName表示元素的本地名称(不带前缀);name表示元素的限定名(带前缀)。
endDocument() —— 解析结束的时候被调用。
下面看代码:
import android.util.Log;import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;import java.util.ArrayList;import java.util.List;public class MyContentHandler extends DefaultHandler { private static final String TAG = "TAG"; private String currentNodeName; //当前的节点名称 private List<Person> personList; private Person person; // 当前正在解析的Person// 这里定义这个方法是为了把解析结果提供出去 public List<Person> getPersonList() { return personList; } @Override public void startDocument() throws SAXException { Log.d(TAG, "startDocument() called"); personList = new ArrayList<>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { Log.d(TAG, "startElement() called with: uri = [" + uri + "], localName = [" + localName + "], qName = [" + qName + "]"); // 记录当前节点名称 currentNodeName = localName; // 每次开始节点为“person”的话,就要开始解析一个新的person对象了 if (localName.equals("person")) { person = new Person(); // 获取person节点的id属性 person.setId(Integer.parseInt(attributes.getValue("id"))); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { Log.d(TAG, "characters() called with: ch = [" + String.valueOf(ch) + "], start = [" + start + "], length = [" + length + "]"); if (currentNodeName != null) { String data = new String(ch, start, length); if (currentNodeName.equals("name")) { person.setName(data); } else if (currentNodeName.equals("age")) { person.setAge(Integer.parseInt(data)); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { Log.d(TAG, "endElement() called with: uri = [" + uri + "], localName = [" + localName + "], qName = [" + qName + "]"); // 每次结束节点为“person”的话,则一个person对象的解析结束了 if (localName.equals("person")) { personList.add(person); person = null; } // 把当前节点重置 currentNodeName = null; } @Override public void endDocument() throws SAXException { Log.d(TAG, "endDocument() called"); }}
接下来,我们就可以使用这个解析处理器进行解析了。
四、使用解析处理器进行xml解析。
怎么用呢?如下面的方法:
public static void saxParseXml(Context context) { try { SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); XMLReader reader = saxParser.getXMLReader(); // 这里用到了我们自定义的解析执行器 MyContentHandler contentHandler = new MyContentHandler(); reader.setContentHandler(contentHandler); // 读取xml文件,执行解析 reader.parse(new InputSource(context.getResources().openRawResource(R.raw.person_data))); // 得到解析结果 List<Person> personList = contentHandler.getPersonList(); Log.d("TAG", "parse result: " + personList); } catch (SAXException e){ } catch (ParserConfigurationException e) { } catch (IOException e) { } }
调用上面的方法即可解析res/raw/person_data.xml文件并得到Person类列表了。
为了更直观地查看解析的流程及解析类的几个方法的参数,我都加上了log。
我是在某个按钮的点击事件里调用这个方法的,运行后打印如下。可对照看到各个方法的执行顺序。
D/TAG: startDocument() calledD/TAG: startElement() called with: uri = [], localName = [data], qName = [data] characters() called with: ch = [ ], start = [0], length = [1] characters() called with: ch = [ ], start = [0], length = [4]D/TAG: startElement() called with: uri = [], localName = [person], qName = [person] characters() called with: ch = [ ], start = [0], length = [1] characters() called with: ch = [ ], start = [0], length = [8] startElement() called with: uri = [], localName = [name], qName = [name] characters() called with: ch = [Jack ], start = [0], length = [4]D/TAG: endElement() called with: uri = [], localName = [name], qName = [name] characters() called with: ch = [ ack ], start = [0], length = [1] characters() called with: ch = [ ], start = [0], length = [8] startElement() called with: uri = [], localName = [age], qName = [age] characters() called with: ch = [25 ], start = [0], length = [2]D/TAG: endElement() called with: uri = [], localName = [age], qName = [age] characters() called with: ch = [ 5 ], start = [0], length = [1] characters() called with: ch = [ ], start = [0], length = [4] endElement() called with: uri = [], localName = [person], qName = [person] characters() called with: ch = [ ], start = [0], length = [1] characters() called with: ch = [ ], start = [0], length = [4] startElement() called with: uri = [], localName = [person], qName = [person]D/TAG: characters() called with: ch = [ ], start = [0], length = [1] characters() called with: ch = [ ], start = [0], length = [8] startElement() called with: uri = [], localName = [name], qName = [name] characters() called with: ch = [Rose ], start = [0], length = [4] endElement() called with: uri = [], localName = [name], qName = [name] characters() called with: ch = [ ose ], start = [0], length = [1] characters() called with: ch = [ ], start = [0], length = [8] startElement() called with: uri = [], localName = [age], qName = [age] characters() called with: ch = [80 ], start = [0], length = [2] endElement() called with: uri = [], localName = [age], qName = [age]D/TAG: characters() called with: ch = [ 0 ], start = [0], length = [1] characters() called with: ch = [ ], start = [0], length = [4] endElement() called with: uri = [], localName = [person], qName = [person] characters() called with: ch = [ ], start = [0], length = [1] endElement() called with: uri = [], localName = [data], qName = [data]D/TAG: endDocument() called
当然最后也得到了Person列表,打印如下:
parse result: [Person{id=5, name='Jack', age=25}, Person{id=20, name='Rose', age=80}]
这是PULL方式解析xml的文章链接,可以对照查看:
Android XML解析之PULL解析 简单示例讲解
更多相关文章
- 手把手带你搭建 Elasticsearch 集群
- Android(安卓)微信支付成功后返回App没有走回调
- Android(安卓)IntentService的使用和源码分析
- Android使用C/C++来保存密钥
- 百度地图(1)
- Android4.0 x86试玩
- 异步AsyncTask的使用与原理分析
- Android(安卓)通过JNI C++进行MD5加密
- Handler消息机制深入学习