在 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 + '\'' + '}'; } }
效果圖: