Android利用SAX對XML進行增刪改查操作詳解
前言
解析XML的方式有很多種,大家比較熟悉的可能就是DOM解析。
DOM(文件對象模型)解析:解析器讀入整個文檔,然后構建一個駐留內(nèi)存的樹結(jié)構,然后代碼就可以根據(jù)DOM接口來操作這個樹結(jié)構了。
優(yōu)點:整個文檔讀入內(nèi)存,方便操作:支持修改、刪除和重現(xiàn)排列等多種功能。
缺點:將整個文檔讀入內(nèi)存中,保留了過多的不需要的節(jié)點,浪費內(nèi)存和空間。
使用場合:一旦讀入文檔,還需要多次對文檔進行操作,并且在硬件資源充足的情況下(內(nèi)存,CPU)。
為了解決DOM解析存在的問題,就出現(xiàn)了SAX解析。其特點為:
優(yōu)點:不用實現(xiàn)調(diào)入整個文檔,占用資源少。尤其在嵌入式環(huán)境中,如android,極力推薦使用SAX解析。
缺點:不像DOM解析一樣將文檔長期駐留在內(nèi)存中,數(shù)據(jù)不是持久的。如果事件過后沒有保存數(shù)據(jù),數(shù)據(jù)就會丟失。
使用場合:機器有性能限制。
本文將給大家詳細介紹關于Android利用SAX對XML增刪改查的相關內(nèi)容,分享出來供大家參考學習價值,下面話不多說了,來一起看看詳細的介紹吧。
1.概述
SAX是一中事件驅(qū)動類型的XML解析方式。說白了,就是通過復寫一個Default類去告知,解析的結(jié)果。SAX并不會想DOM那樣把整個的XML加載到內(nèi)存中,而它會像IO流那樣,一個一個標簽地去解析。
簡單地說就是對文檔進行順序掃描,當掃描到文檔(document)開始與結(jié)束、元素(element)開始與結(jié)束、文檔(document)結(jié)束等地方時通知事件處理函數(shù),由事件處理函數(shù)做相應動作,然后繼續(xù)同樣的掃描,直至文檔結(jié)束。
為了方便說明,先約定好一個XML如下:
<?xml version="1.0" encoding="UTF-8"?> <persons> <person id="1" key="33" type="type"> <name>zhangsan</name> <age>21</age> </person> </persons>
2.基本讀?。ú椋?/strong>
代碼如下
SAXParserFactory factory = SAXParserFactory.newInstance();//創(chuàng)建SAX解析工廠 SAXParser saxParser; try { File file = new File(xmlFilePath); InputStream inputStream = new FileInputStream(file);//得到輸入流 saxParser = factory.newSAXParser();//創(chuàng)建解析器 saxParser.parse(inputStream,new DefaultHandler(){//開始解析 //文檔開始標記 @Override public void startDocument() throws SAXException { super.startDocument(); Log.i("loadWithSax","startDocument"); } //文檔結(jié)束標記 @Override public void endDocument() throws SAXException { super.endDocument(); FileUtils.closeIO(inputStream); Log.i("loadWithSax","endDocument"); } //解析到標簽 @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SA super.startElement(uri, localName, qName, attributes); Log.i("loadWithSax","startElement"+",uri:"+uri+",localName:"+localName+",qName:"+qName); if (attributes!=null) { for (int i = 0; i < attributes.getLength(); i++) { Log.i("loadWithSax",attributes.getLocalName(i)+","+attributes.getValue(i)+","+attributes. } } } //標簽解析結(jié)束 @Override public void endElement(String uri, String localName, String qName) throws SAXException { super.endElement(uri, localName, qName); Log.i("loadWithSax","endElement"+",uri:"+uri+",localName:"+localName+",qName:"+qName); } /** * 文本 * 該方法中的ch把所解析的xml的所有數(shù)據(jù)都保存進來,且ch初始化為2K數(shù)據(jù)。 start是一個節(jié)點">"的位置。length就是">"到下一個"<"的長度。 * <namesList> * <name>michael</name> * </namesList> * 執(zhí)行namesList節(jié)點時,因為沒有文本, * 不會執(zhí)行到該方法。 */ @Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); Log.i("loadWithSax","characters"+",start:"+start+",length:"+length); for (int i = 0; i < ch.length; i++) { Log.i("loadWithSax","char:"+ch[i]+",ASCII:"+(int)ch[i]); } } //警告回調(diào) @Override public void warning(SAXParseException e) throws SAXException { super.warning(e); Log.i("loadWithSax","warning"+","+e.getMessage()); } //錯誤回調(diào) @Override public void error(SAXParseException e) throws SAXException { super.error(e); Log.i("loadWithSax","error1"+","+e.getMessage()); } }); } catch (ParserConfigurationException | SAXException | IOException e) { e.printStackTrace(); Log.i("loadWithSax","error2"+","+e.getMessage()); }
- 傳入:DefaultHandler的實體,通過復寫其中的方法,查詢到文檔,標簽的內(nèi)容:
- startDocument 和 endDocument是掃描文檔的開始和結(jié)束
- startElement,是解析到了標簽,localName就是標簽的名稱,如本文所示例的,當解析到第一個人名的時候,
<person id="1" key="33" type="type"> <name>zhangsan</name> <age>21</age> </person>
解析到<person></person>回調(diào):startElement,標簽內(nèi)的參數(shù)是Attributes attributes,一個for循環(huán)就可以遍歷讀取。
characters,解析到標簽的內(nèi)容時候回調(diào),接著上面例子,解析<person></person>,回調(diào)startElement,然后不會回調(diào)此方法,因為內(nèi)容不是文本,而是包含了標簽,所以,解析到其子標簽:<name>zhangsan</name>的時候,又會先回調(diào)回調(diào)startElement,然后,才回調(diào)characters,告訴你,這個標簽里面有文本內(nèi)容!參數(shù)說明如下:
- char[] : 內(nèi)容字符數(shù)組里面。如:<name>zhangsan</name>,char[]就是:{'z','h','a','n','g','s','a','n'}
- start :0,文本的開始
- length :文本的長度。
- endElement,標簽結(jié)束。
使用上面的代碼,得到的部分log如下:
I/loadWithSax: startDocument I/loadWithSax: startElement,uri:,localName:persons,qName:persons I/loadWithSax: characters,start:0,length:1 I/loadWithSax: char: ,ASCII:10 I/loadWithSax: characters,start:0,length:1 I/loadWithSax: char: ,ASCII:9 I/loadWithSax: startElement,uri:,localName:person,qName:person I/loadWithSax: id,1,CDATA I/loadWithSax: key,33,CDATA I/loadWithSax: type,type,CDATA I/loadWithSax: characters,start:0,length:1 I/loadWithSax: char: ,ASCII:10 I/loadWithSax: characters,start:0,length:2 I/loadWithSax: char: ,ASCII:9 I/loadWithSax: char: ,ASCII:9 I/loadWithSax: startElement,uri:,localName:name,qName:name I/loadWithSax: characters,start:0,length:8 I/loadWithSax: char:z,ASCII:122 I/loadWithSax: char:h,ASCII:104 I/loadWithSax: char:a,ASCII:97 I/loadWithSax: char:n,ASCII:110 I/loadWithSax: char:g,ASCII:103 I/loadWithSax: char:s,ASCII:115 I/loadWithSax: char:a,ASCII:97 I/loadWithSax: char:n,ASCII:110 I/loadWithSax: endElement,uri:,localName:name,qName:name
startDocument,開始解析xml
解析到第一個標簽的開始:<persons>
然后解析到了內(nèi)容???characters?按照我上面的分析,<persons>標簽內(nèi)沒有文字內(nèi)容,應該不會回調(diào)。其實,這里回調(diào)的是換行符。log中打出了ASCII碼,10就是換行。然后,還有一個tab符。
然后就是<persons>里面的<person>,有三個參數(shù):id,key,type,巴拉巴拉。。。
3.保存
sax的保存有點麻煩。具體是XmlSerializer的使用。
初始化一個XmlSerializer:
StringWriter stringWriter = new StringWriter(); XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlSerializer xmlSerializer = factory.newSerializer(); xmlSerializer.setOutput(stringWriter);
聲明文檔的開始和結(jié)束:
xmlSerializer.startDocument("utf-8", false);//false,是聲明:standalone的值。 xmlSerializer.endDocument();
標簽的開始結(jié)束,和寫入內(nèi)容:
xmlSerializer.startTag(null, "name");//開始,第一個參數(shù)是namespace,命名空間。 xmlSerializer.text(person.name);//寫入內(nèi)容 xmlSerializer.endTag(null, "name");
實戰(zhàn):
假如,我們需要構建如下的XML:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <persons> <person id="1" key="33" type="type"> <name>zhangsan</name> <age>21</age> </person> <person> <name>lisi</name> <age>12</age> </person> <person> <name>wangwu</name> <age>23</age> </person> </persons>
首先你得定義好一個Bean類,Person:
public class Person { public int id = -1; public String key = null; public String type = null; public String name; public int age; public Person(String name, int age) { this.name = name; this.age = age; } }
然后開擼:最后的stringWriter就是你想要的數(shù)據(jù),注意就是,一些換行和tab符。
StringWriter stringWriter = new StringWriter(); try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlSerializer xmlSerializer = factory.newSerializer(); xmlSerializer.setOutput(stringWriter); //制造假數(shù)據(jù): ArrayList<Person> personArrayList = new ArrayList<>(); Person person1 = new Person("zhangsan",21); person1.id=1; person1.key="33"; person1.type="type"; Person person2 = new Person("lisi",12); Person person3 = new Person("wangwu",23); personArrayList.add(person1); personArrayList.add(person2); personArrayList.add(person3); //star document xmlSerializer.startDocument("utf-8", true); xmlSerializer.text("\n"); xmlSerializer.startTag(null, "persons"); for(Person person:personArrayList){ //star tag xmlSerializer.text("\n"); xmlSerializer.text("\t"); xmlSerializer.startTag(null, "person"); //添加參數(shù) if (person.id!=-1) { xmlSerializer.attribute(null,"id",String.valueOf(person.id)); } if (person.key!=null) { xmlSerializer.attribute(null,"key",person.key); } if (person.type!=null) { xmlSerializer.attribute(null,"type",person.type); } //添加內(nèi)容:name xmlSerializer.text("\n"); xmlSerializer.text("\t"); xmlSerializer.text("\t"); xmlSerializer.startTag(null, "name"); xmlSerializer.text(person.name); xmlSerializer.endTag(null, "name"); //添加內(nèi)容:age xmlSerializer.text("\n"); xmlSerializer.text("\t"); xmlSerializer.text("\t"); xmlSerializer.startTag(null, "age"); xmlSerializer.text(String.valueOf(person.age)); xmlSerializer.endTag(null, "age"); //end tag xmlSerializer.text("\n"); xmlSerializer.text("\t"); xmlSerializer.endTag(null, "person"); } //end document xmlSerializer.text("\n"); xmlSerializer.endTag(null, "persons"); xmlSerializer.endDocument(); } catch (Exception e) { e.printStackTrace(); }
XmlSerializer的初始化需要傳入一個write對象,你可以傳入一個FileWrite,寫到文件里面:
// 創(chuàng)建文件對象 File fileText = new File(saveFilePath); // 向文件寫入對象寫入信息 FileWriter stringWriter; xmlSerializer.setOutput(stringWriter); //...同上 //記得close if (stringWriter != null) { stringWriter.close(); }
4.增刪
增加和刪除,那么你需要先對XML進行映射,映射成一堆的Bean,然后增加刪除Bean,再保存即可。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
詳解Android Activity中的幾種監(jiān)聽器和實現(xiàn)方式
這篇文章主要介紹了Activity中的幾種監(jiān)聽器和實現(xiàn)方式的相關資料,幫助大家更好的理解和學習使用Android,感興趣的朋友可以了解下2021-04-04android開發(fā)教程之framework增加字符串資源和圖片等resource資源
這篇文章主要介紹了android開發(fā)中framework增加字符串資源和圖片等resource資源方法,需要的朋友可以參考下2014-02-02Android開發(fā)實現(xiàn)拍照功能的方法實例解析
這篇文章主要介紹了Android開發(fā)實現(xiàn)拍照功能的方法,結(jié)合實例形式較為詳細的分析了Android拍照功能的具體實現(xiàn)步驟與相關操作技巧,需要的朋友可以參考下2017-10-10Android編程實現(xiàn)仿iphone抖動效果的方法(附源碼)
這篇文章主要介紹了Android編程實現(xiàn)仿iphone抖動效果的方法,結(jié)合實例形式分析了仿iphone抖動效果的頁面布局及功能實現(xiàn)技巧,并附帶實例源碼供讀者下載,需要的朋友可以參考下2015-11-11Android 實現(xiàn)永久保存數(shù)據(jù)的方法詳解
本篇文章是對Android實現(xiàn)永久保存數(shù)據(jù)的方法進行了詳細的分析介紹,需要的朋友參考下2013-06-06Android中極簡的js與java的交互庫(SimpleJavaJsBridge)
本文主要介紹了Android中極簡的js與java的交互庫--SimpleJavaJsBridge,它可以讓js與java之間的通信更簡單。 具有很好的參考價值,下面跟著小編一起來看下吧2017-01-01Intellij IDEA + Android SDK + Genymotion Emulator打造最佳Android
本文介紹Lorinnn在開發(fā)Android過程不斷跌打滾爬中安裝的一套開發(fā)環(huán)境,相信你在使用后同樣有不錯的體會。2014-07-07