1.XML解析
若想要操作XML文档,首先需要将XML文档解析出来。通常情况下,解析XML文件有三种方式
- DOM解析
DOM(Document Object Mode)解析是一种基于对象的API,它会将XML文件的所有内容以文档树方式存放在内存中,然后允许使用DOM API遍历XML树、检索所需的数据,这样便能根据树的结构以节点的形式来
DOM操作XML代码看起来是比较直观,编码比SAX解析简单,但DOM需要将整个XML文档以文档树的形式存放在内存,消耗内存比较大。
- SAX解析
SAX解析会逐行扫描XML文档,当遇到标签时触发解析处理器,采用事件处理方式解析XML。由于它是边读取边解析,因此不存在内存占用的问题,可以解析超大XML。缺点是SAX解析只能读取XML中的数据,无法进行增删改
- PULL解析
PULL解析器是一个开源的Java项目,既可以用于Android应用,也可以用于JavaEE程序。Android已经集成了PULL解析器,所以在Android中最常用的解析方式是PULL解析。
使用PULL解析XML文档,首先要创建XmlPullParser解析器,该解析器提供了很多属性
XmlPullParser.START_DOCUMENT:XML文档的开始
XmlPullParser.END_DUCUMENT:XML文档的结束
XmlPullParser.START_TAG:开始节点,在XML文件中,带<>的都是开始节点
XmlPullParser.END_TAG:结束节点,带有</>都是结束节点
PULL解析器的用法:
(1)通过调用Xml.newPullParser();得到一个XmlPullParser对象
(2)通过parser.getEventType()获取到当前的事件类型
(3)通过while循环判断当前操作事件类型是否为文档结束,是则跳出while循环
(4)while循环中通过switch语句判断当前事件类型是否为开始标签,是则获取该标签内容
2.案例--天气预报(解析XML文件)
第一步,编写主布局(activity_main.xml)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/weather"
tools:context=".MainActivity" >
<LinearLayout
android:id="@+id/ll_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:orientation="horizontal" >
<Button
android:id="@+id/city_bj"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="北京" />
<Button
android:id="@+id/city_sh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上海" />
<Button
android:id="@+id/city_Harbin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="吉林" />
</LinearLayout>
<TextView
android:id="@+id/select_city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="34dp"
android:layout_toLeftOf="@+id/icon"
android:text="上海"
android:textSize="20sp" />
<ImageView
android:id="@+id/icon"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_alignLeft="@+id/ll_btn"
android:layout_below="@+id/select_city"
android:layout_marginTop="25dp"
android:paddingBottom="5dp"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/select_weather"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/icon"
android:layout_below="@+id/icon"
android:layout_marginRight="15dp"
android:layout_marginTop="18dp"
android:gravity="center"
android:text="多云"
android:textSize="18sp" />
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/select_weather"
android:layout_alignRight="@+id/ll_btn"
android:layout_marginBottom="10dp"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="@+id/temp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:text="-7℃"
android:textSize="22sp" />
<TextView
android:id="@+id/wind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="风力:3级"
android:textSize="18sp" />
<TextView
android:id="@+id/pm"
android:layout_width="73dp"
android:layout_height="wrap_content"
android:text="pm"
android:textSize="18sp" />
</LinearLayout>
</RelativeLayout>
显示效果如图
第二步,创建weather,xml文件
在src根目录中创建一个weather.xml文件,该文件包含三个城市的天气信息
<?xml version="1.0" encoding="utf-8"?>
<infos>
<city id="1">
<temp>20℃/30℃</temp>
<weather>晴天多云</weather>
<name>上海</name>
<pm>80</pm>
<wind>1级</wind>
</city>
<city id="2">
<temp>26℃/32℃</temp>
<weather>晴天</weather>
<name>北京</name>
<pm>98</pm>
<wind>3级</wind>
</city>
<city id="3">
<temp>15℃/24℃</temp>
<weather>多云</weather>
<name>哈尔滨</name>
<pm>30</pm>
<wind>5级</wind>
</city>
</infos>
第三步,创建WeatherInfo类
每个城市天气信息都包含id,temp,weather,name,pm和wind属性
public class WeatherInfo {
private int id;
private String name;
private String weather;
private String temp;
private String pm;
private String wind;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getWeather() {
return weather;
}
public void setWeather(String weather) {
this.weather = weather;
}
public String getTemp() {
return temp;
}
public void setTemp(String temp) {
this.temp = temp;
}
public String getPm() {
return pm;
}
public void setPm(String pm) {
this.pm = pm;
}
public String getWind() {
return wind;
}
public void setWind(String wind) {
this.wind = wind;
}
}
第四步,创建WeatherService工具类
为了避免大量代码都在一个类中,因此创建了一个的工具类,类中定义了一个getWeatherInfo()方法,用来解析XML文件
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import android.util.Xml;
public class WeatherService {
//返回天气信息的集合
public static List<WeatherInfo> getWeatherInfos(InputStream is)
throws Exception {
//得到pull解析器
XmlPullParser parser = Xml.newPullParser();
// 初始化解析器,第一个参数代表包含xml的数据
parser.setInput(is, "utf-8");
List<WeatherInfo> weatherInfos = null;
WeatherInfo weatherInfo = null;
//得到当前事件的类型
int type = parser.getEventType();
// END_DOCUMENT文档结束标签
while (type != XmlPullParser.END_DOCUMENT) {
switch (type) {
//一个节点的开始标签
case XmlPullParser.START_TAG:
//解析到全局开始的标签 infos 根节点
if("infos".equals(parser.getName())){
weatherInfos = new ArrayList<WeatherInfo>();
}else if("city".equals(parser.getName())){
weatherInfo = new WeatherInfo();
String idStr = parser.getAttributeValue(0);
weatherInfo.setId(Integer.parseInt(idStr));
}else if("temp".equals(parser.getName())){
//parset.nextText()得到该tag节点中的内容
String temp = parser.nextText();
weatherInfo.setTemp(temp);
}else if("weather".equals(parser.getName())){
String weather = parser.nextText();
weatherInfo.setWeather(weather);
}else if("name".equals(parser.getName())){
String name = parser.nextText();
weatherInfo.setName(name);
}else if("pm".equals(parser.getName())){
String pm = parser.nextText();
weatherInfo.setPm(pm);
}else if("wind".equals(parser.getName())){
String wind = parser.nextText();
weatherInfo.setWind(wind);
}
break;
//一个节点结束的标签
case XmlPullParser.END_TAG:
//一个城市的信息处理完毕,city的结束标签
if("city".equals(parser.getName())){
//一个城市的信息 已经处理完毕了.
weatherInfos.add(weatherInfo);
weatherInfo = null;
}
break;
}
//只要不解析到文档末尾,就解析下一个条目。得到下一个节点的事件类型
//注意,这个一定不能忘,否则会成为死循环
type = parser.next();
}
return weatherInfos;
}
}
注意的是,type=parser.next()这行代码不能忘记,因为在while循环中,当一个节点信息解析完毕,会继续解析下一个节点,只有type的类型为END_DOCUMENT时才会结束循环。
第五步,编写界面交互代码(MainActivity类)
public class MainActivity extends Activity implements OnClickListener {
private TextView select_city, select_weather, select_temp, select_wind,select_pm;
private Map<String, String> map;
private List<Map<String, String>> list;
private String temp, weather, name, pm, wind;
private ImageView icon;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化文本控件
select_city = (TextView) findViewById(R.id.select_city);
select_weather = (TextView) findViewById(R.id.select_weather);
select_temp = (TextView) findViewById(R.id.temp);
select_wind = (TextView) findViewById(R.id.wind);
select_pm = (TextView) findViewById(R.id.pm);
icon = (ImageView) findViewById(R.id.icon);
findViewById(R.id.city_sh).setOnClickListener(this);
findViewById(R.id.city_bj).setOnClickListener(this);
findViewById(R.id.city_Harbin).setOnClickListener(this);
try {
// 调用上边写好的解析方法,weather.xml就在类的目录下,使用类加载器进行加载
// infos就是每个城市的天气信息集合,里边有我们所需要的所有数据。
List<WeatherInfo> infos = WeatherService
.getWeatherInfos(MainActivity.class.getClassLoader()
.getResourceAsStream("weather.xml"));
// 循环读取infos中的每一条数据
list = new ArrayList<Map<String, String>>();
for (WeatherInfo info : infos) {
map = new HashMap<String, String>();
map.put("temp", info.getTemp());
map.put("weather", info.getWeather());
map.put("name", info.getName());
map.put("pm", info.getPm());
map.put("wind", info.getWind());
list.add(map);
}
// 显示天气信息到文本控件中
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "解析信息失败", 0).show();
}
getMap(1, R.drawable.sun);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.city_sh:
getMap(0, R.drawable.cloud_sun);
break;
case R.id.city_bj:
getMap(1, R.drawable.sun);
break;
case R.id.city_Harbin:
getMap(2, R.drawable.clouds);
break;
}
}
private void getMap(int number, int iconNumber) {
Map<String, String> bjMap = list.get(number);
temp = bjMap.get("temp");
weather = bjMap.get("weather");
name = bjMap.get("name");
pm = bjMap.get("pm");
wind = bjMap.get("wind");
select_city.setText(name);
select_weather.setText(weather);
select_temp.setText("" + temp);
select_wind.setText("风力 : " + wind);
select_pm.setText("pm: " + pm);
icon.setImageResource(iconNumber);
}
}
第六步,运行程序查看天气
运行当前程序,分别选择,能看到图中所示结果,代表着程序成功地解析了存储在weather.xml文件中的天气信息