xml 數(shù)據(jù)解析
xml 是一種標(biāo)記擴(kuò)展語言(Extension Mark-up Language),學(xué)到這里大家對(duì) xml 語言一定不陌生,但是它在 Android 中的運(yùn)用其實(shí)只是冰山一角。拋開 Android,XML 也被廣泛運(yùn)用于各種數(shù)據(jù)結(jié)構(gòu)中。在運(yùn)用 xml 編寫 Android 布局的過程中,大家有沒有好奇我們寫的 LinearLayout 或者 RelativeLayout 等布局是怎么變系統(tǒng)解析成 UI 樣式的?這一節(jié)我們來揭曉謎底。
1. xml 的優(yōu)勢(shì)
XML 是一種標(biāo)記語言,我們目前接觸最多的用法就是用來寫布局文件。但其實(shí),xml 被廣泛用于網(wǎng)絡(luò)數(shù)據(jù)傳輸中,它是一種非常流行的網(wǎng)絡(luò)數(shù)據(jù)格式。比如我們可以使用上一節(jié)學(xué)到的 HttpURLConnect 去向 Service 發(fā)起一個(gè) Http 請(qǐng)求,那么 Service 就可以將數(shù)據(jù)用 xml 的形式下發(fā),無論是從保存還是從解析的角度,xml 都提供了極大的便利。
2. xml 的解析方式
Android 提供了 3 種類型的解析器:DOM、SAX、XMLPullParser。在這三種類型中,唯 XMLPullParser 以其高效易用兩大優(yōu)點(diǎn)被 Android 官方推薦,在實(shí)際開發(fā)中絕大多數(shù)場(chǎng)景都是使用 XMLPullParser,所以本節(jié)主要介紹 XMLPullParser 的使用方法。
3. XMLPullParser 的組成部分
雖然寫過很多 xml 布局,但是還是來系統(tǒng)的看一下 xml 的組成部分,一個(gè) xml 文件通常由 4 個(gè)部分組成:
- **prolog :**通常在 xml 文件的第一行,包含一些文件的描述信息,比如版本號(hào)、編碼格式等
- **Events:**以各個(gè) Tag 開頭和結(jié)尾的部分
- **Text:**介于兩個(gè) Tag 之間的內(nèi)容
- **Attributes:**用來描述每個(gè) Tag 的屬性
4. XML 解析示例
4.1 XML 樣本
下面我們來解析一個(gè)非常簡(jiǎn)單的 XML,如下:
<?xml version="1.0" encoding="utf-8"?>
<heros>
<hero id="1">
<name>
馬超
</name>
<description>
刺客
</description>
</hero>
<hero id="2">
<name>
妲己
</name>
<description>
法師
</description>
</hero>
<hero id="3">
<name>
魯班
</name>
<description>
射手
</description>
</hero>
</heros>
4.2 XML 解析
以上 xml 是一個(gè)英雄列表,包含了 3 個(gè)英雄對(duì)象,每個(gè)英雄對(duì)象包含名字和描述,下面開始進(jìn)行解析。
private ArrayList<Hero> parseXML(XmlPullParser parser) throws XmlPullParserException, IOException {
ArrayList<Hero> heros = null;
int eventType = parser.getEventType();
Hero hero = null;
// 判斷是否結(jié)束
while (eventType != XmlPullParser.END_DOCUMENT) {
String name;
switch (eventType) {
case XmlPullParser.START_DOCUMENT:
// 處理開始標(biāo)簽,在開始的時(shí)候創(chuàng)建英雄List
heros = new ArrayList();
break;
case XmlPullParser.START_TAG:
// 處理tag開始,在這里接收英雄及英雄屬性
name = parser.getName();
if (name.equals("hero")) {
hero = new Hero();
hero.id = parser.getAttributeValue(null, "id");
} else if (hero != null) {
if (name.equals("name")) {
hero.name = parser.nextText();
} else if (name.equals("description")) {
hero.description = parser.nextText();
}
}
break;
case XmlPullParser.END_TAG:
// 標(biāo)簽結(jié)束,將英雄添加到英雄列表
name = parser.getName();
if (name.equalsIgnoreCase("hero") && hero != null) {
heros.add(hero);
}
}
// 處理下一個(gè)標(biāo)簽
eventType = parser.next();
}
return heros;
}
在parseXML
方法中,首先解析 prelog,在這里創(chuàng)建英雄列表 List,然后一次解析英雄標(biāo)簽及內(nèi)部屬性,最后解析完一個(gè)英雄立即存入 List 中。
4.3 MainActivity 主邏輯
現(xiàn)在已經(jīng)寫好了 XML 解析方法,那么 MainActivity 的邏輯就非常簡(jiǎn)單了,我們只需寫一個(gè)帶有一個(gè) Button 的布局,用于觸發(fā) XML 的解析,然后在onCreate()
中調(diào)用設(shè)置監(jiān)聽器,并在監(jiān)聽器中調(diào)用解析邏輯即可,最后將解析完的內(nèi)容輸入到 Logcat:
package com.emercy.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.parse_xml).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
XmlPullParserFactory pullParserFactory = null;
try {
try {
pullParserFactory = XmlPullParserFactory.newInstance();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
XmlPullParser parser = pullParserFactory.newPullParser();
InputStream in_s = getApplicationContext().getAssets().open("heros.xml");
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(in_s, null);
ArrayList<Hero> heros = parseXML(parser);
String text = "";
for (Hero hero : heros) {
text += "id : " + hero.getId() + " name : " + hero.getName() + " description : " + hero.getDescription() + "\n";
}
Log.d("\nXML Parser", text);
} catch (XmlPullParserException | IOException e) {
e.printStackTrace();
}
}
});
}
}
編譯運(yùn)行,點(diǎn)擊“解析 xml”,查看 Logcat 的輸出:
可以看到 log 的輸出和 XML 的定義一模一樣,到這里 XML 的內(nèi)容就被解析到 heros 的 list 中了。
5. 小結(jié)
本節(jié)介紹了一個(gè)以前經(jīng)常接觸的數(shù)據(jù)格式,在 Andorid 中我們的布局可以很方便的用 XML 來編寫,重新回到本節(jié)開頭的問題,Android 系統(tǒng)是如何將我們寫好的 XML 布局轉(zhuǎn)換成 UI 樣式的呢?是否也可以通過XmlPullParser
來完成?
當(dāng)然,除了編寫 Android 布局之外,XML 也是網(wǎng)絡(luò)傳輸中常用的數(shù)據(jù)格式,我們可以將需要的數(shù)據(jù)通過 XML 格式存儲(chǔ),然后通過上一節(jié)學(xué)習(xí)的 HttpURLConnection 來進(jìn)行傳輸。除了 XML,還有另一種數(shù)據(jù)格式非常實(shí)用,我們將在下一節(jié)揭曉。