標籤:
由於之前的項目使用過xml檔案的解析,但是在使用的時候都是從網上找到的代碼,稍作修改就使用了,然而對其中的原理並不知所以然,所以再次想使用的時候,感覺還是空空的,不知道如何下手,為了更加深入的理解xml檔案的解析,我從代碼實現的角度做一些理解,但是我在看代碼的時候,有些代碼的實現還是沒有辦法讀懂,還是太深奧。下面我就以我之見,寫一些東西,作為記錄。
在android中XML的解析有三種,分別為:SAX(Simple API XML)、DOM(document object model)、以及今天我們要說的PULL類型,也是android官方提倡的使用方式。
在講之前,我先寫出一般的使用方式,比如解析以下的XML文檔:
<?xml version="1.0" encoding="UTF-8"?><students> <student id="1"> <name>cc</name> <age>10</age> <grade>100</grade> </student> <student id="2"> <name>cy</name> <age>11</age> <grade>89</grade> <student></students>
一般的解析手段,java邏輯代碼如下(代碼截取與網路):
public class TestPullXml { public List<Person> getPersons(InputStream instream) throws Exception { List<Person> persons = null; Person person = null; XmlPullParser parser = Xml.newPullParser();//得到Pull解析器 parser.setInput(instream, "UTF-8");//設定下輸入資料流的編碼 int eventType = parser.getEventType();//得到第一個事件類型 while (eventType != XmlPullParser.END_DOCUMENT) { //如果事件類型不是文檔結束的話則不斷處理事件 switch (eventType) { case XmlPullParser.START_DOCUMENT://如果是文檔開始事件 persons = new ArrayList<Person>();建立一個person集合 break; case (XmlPullParser.START_TAG)://如果遇到標籤開始 String tagName = parser.getName();// 獲得解析器當前元素的名稱 if ("person".equals(tagName)) {//如果當前標籤名稱是 <person> person = new Person();//建立一個person //將元素的屬性值賦值給id person.setId(new Integer(parser.getAttributeValue(0))); } if (person != null) {//如果person已經建立完成 if ("name".equals(tagName))//如果當前節點標記是name person.setName(new String(parser.nextText())); else if ("age".equals(tagName))//如果當前元素節點標記是age person.setAge(new Short(parser.nextText())); } break; case (XmlPullParser.END_TAG)://如果遇到標籤結束 if ("person".equals(parser.getName())) {//如果是person標籤結束 persons.add(person);//將建立完成的person加入集合 person = null;//並且置空 } break; } eventType=parser.next();//進入下一個事件處理 } return persons; }
下面,我們對上述代碼,進行分行理解:
XmlPullParser parser = Xml.newPullParser();//得到Pull解析器
首先找到Xml類下的newPullParser方法:
/** * Returns a new pull parser with namespace support. */ public static XmlPullParser newPullParser() { try { KXmlParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); return parser; } catch (XmlPullParserException e) { throw new AssertionError(); } }
通過上面的代碼,我們可以發現,實際上該函數返回了一個實現了XmlPullParser介面的類KXmlParser,並且給該對象設定了命名空間和文檔聲明,所以,對以後的parser對象,我們所需要分析的實現代碼,就要找KXmlParser這個類了。
parser.setInput(instream, "UTF-8");//設定下輸入資料流的編碼
這一步,我們先查看一下,官方文檔是怎麼解釋了:
Set the input source for parser to the given reader and resets the parser. The event type is set to the initial value START_DOCUMENT. Setting the reader to null will just stop parsing and reset parser state, allowing the parser to free internal resources such as parsing buffers.
相信大家可以理解這個方法的作用,但是我們還是看看它的實現代碼吧:
// public part starts here... public void setInput(Reader reader) throws XmlPullParserException { this.reader = reader; line = 1; column = 0; type = START_DOCUMENT; name = null; namespace = null; degenerated = false; attributeCount = -1; encoding = null; version = null; standalone = null; if (reader == null) return; srcPos = 0; srcCount = 0; peekCount = 0; depth = 0; entityMap = new Hashtable<String, String>(); entityMap.put("amp", "&"); entityMap.put("apos", "‘"); entityMap.put("gt", ">"); entityMap.put("lt", "<"); entityMap.put("quot", "\""); }
在這個方法中,初始化了很多在讀取XML過程中需要使用的成員變數,比如type,初始化為START_DOCUMENT,輸入資料流instream,這些都是解析時所必不可少的成員,所以在一開始,一定要調用該方法。設定輸入源。
int eventType = parser.getEventType();//得到第一個事件類型
首先我們要知道,XML的幾種事件類型:
START_DOCUMENT、START_TAG、TEXT、END_TAG、END_DOCUMENT
/******************************明天再寫**************************************/
android-XML解析之pull類型代碼解析