在 Android中解析XML文主要有三种方式,分别为SAX、DOM和Android附带的PULL解析器。其中SAX是一个解析速度非常快并且占用内存少的XML解析器,非常适合Android手机等移动设备。
SAX解析XML文件采用事件驱动的方式进行,也就是说,SAX是逐行扫描文件,遇到符合条件的设定条件后就会触发特定的事件,回调你写好的事件处理程序。使用SAX的优势在于其解析速度较快,占用内存较少(相对于DOM而言)。而且SAX在解析文件的过程中得到自己需要的信息后可以随时终止解析,并不一定要等文件全部解析完毕。凡事有利必有弊,其劣势在于SAX采用的是流式处理方式,当遇到某个标签的时候,它并不会记录下以前所遇到的标签,也就是说,在处理某个标签的时候,比如在 startElement方法中,所能够得到的信息就是标签的名字和属性,至于标签内部的嵌套结构,上层标签、下层标签以及其兄弟节点的名称等等与其结构相关的信息都是不得而知的。实际上就是把XML文件的结构信息丢掉了,如果需要得到这些信息的话,只能你自己在程序里进行处理了。所以相对DOM而言,SAX处理XML文档没有DOM方便,SAX处理的过程相对DOM而言也比较复杂。
SAX解析XML文件一般有以下五个步骤:
1、创建一个SAXParserFactory对象(通过类名很容易得知它利用工厂方法模式实现的);
2、调用SAXParserFactory中的newSAXParser方法创建一个SAXParser对象;
3、然后在调用SAXParser中的getXMLReader方法获取一个XMLReader对象;
4、在XMLReader中注册事件处理接口,一般有ContentHandler、ErrorHandler、DTDHandler、EntityHandler四种;
5、调用XMLReader中的parse方法解析指定的XML字符串对象;
步骤四中提到的四个Handler是事件处理接口,解析XML文件需要重写接口中的方法,最常用的是ContentHandler这个接口,下面是该接口中的一些常用方法:
//文档开头会调用此方法,可以在这个方法做一些预处理操作
startDocument()
//当文档结束的时候,调用这个方法,可以在其中做一些善后的工作
endDocument()
//当读到一个开始标签的时候,会触发这个方法
startElement(String uri, String localName, String qName, Attributes atts)
//在遇到结束标签的时候,调用这个方法。
endElement(String uri, String localName, String name)
// 这个方法用来处理在XML文件中读到的内容,第一个参数为文件的字符串内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。
characters(char[] ch, int start, int length)
下面是利用SAX解析XML文件的DEMO程序,首先先在Assets目录下创建file.xml 加入如下的内容
<?xml version="1.0"?> <employees> <employee> <name sex="man">张飞</name> <surname>张</surname> <salary>50000</salary> </employee> <employee> <name sex="woman">李小敏 </name> <surname>李</surname> <salary>60000</salary> </employee> <employee> <name sex="man">鲁智深</name> <surname>鲁</surname> <salary>70000</salary> </employee> </employees>
编写activity代码
package com.example.abc.xmlpaserdemo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; public class SAXActivity extends AppCompatActivity { private static final String TAG =SAXActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sax); InputStream is = null; try { is = getAssets().open("file.xml"); List<Employee> employees=sax2xml(is); for(Employee employee:employees){ Log.i(TAG, "onCreate: " +employee.toString()); } } catch (IOException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } } private List<Employee> sax2xml(InputStream is) throws ParserConfigurationException, SAXException, IOException { SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); //初始化Sax解析器 SAXParser saxParser = saxParserFactory.newSAXParser(); //新建解析处理器 MyHandler handler = new MyHandler(); //将解析交给处理器 saxParser.parse(is, handler); //返回List return handler.getList(); } public class MyHandler extends DefaultHandler { private List<Employee> list; private Employee employee; //用于存储读取的临时变量 private String content; /** * 解析到文档开始调用,一般做初始化操作 * * @throws SAXException */ @Override public void startDocument() throws SAXException { list = new ArrayList<>(); super.startDocument(); } /** * 解析到文档末尾调用,一般做回收操作 * * @throws SAXException */ @Override public void endDocument() throws SAXException { super.endDocument(); } /** * 每读到一个元素就调用该方法 * * @param uri * @param localName * @param qName * @param attributes * @throws SAXException */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("employee".equals(qName)) { //读到student标签 employee = new Employee(); } else if ("name".equals(qName)) { //获取name里面的属性 String sex = attributes.getValue("sex"); employee.setSex(sex); } super.startElement(uri, localName, qName, attributes); } /** * 读到元素的结尾调用 * * @param uri * @param localName * @param qName * @throws SAXException */ @Override public void endElement(String uri, String localName, String qName) throws SAXException { if ("employee".equals(qName)) { list.add(employee); } if ("name".equals(qName)) { employee.setName(content); } else if ("surname".equals(qName)) { employee.setSurName(content); }else if ("salary".equals(qName)) { employee.setSalary(Integer.parseInt(content)); } super.endElement(uri, localName, qName); } /** * 读到属性内容调用 * * @param ch * @param start * @param length * @throws SAXException */ @Override public void characters(char[] ch, int start, int length) throws SAXException { content = new String(ch, start, length); super.characters(ch, start, length); } /** * 获取该List * * @return */ public List<Employee> getList() { return list; } } }
Employee 代码:
package com.example.abc.xmlpaserdemo; /** * Created by abc on 2020/3/14. */ public class Employee { private String name ; private String surName; private int salary; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurName() { return surName; } public void setSurName(String surName) { this.surName = surName; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", surName='" + surName + '\'' + ", salary=" + salary + ", sex='" + sex + '\'' + '}'; } }
效果图: