怎样将xml文件形式的信息最终以友好的形式显示在界面上呢?
以如下的一份xml文件为例,内容是关于天气情况的
<?xml version="1.0" encoding="UTF-8"?> <xml_api_reply version="1"> <weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0"> <forecast_information> <city data="Jiaozuo, Henan"/> <postal_code data="jiaozuo"/> <latitude_e6 data=""/> <longitude_e6 data=""/> <forecast_date data="2011-08-07"/> <current_date_time data="2011-08-07 16:00:00 +0000"/> <unit_system data="SI"/> </forecast_information> <current_conditions> <condition data="阴"/> <temp_f data="77"/> <temp_c data="25"/> <humidity data="湿度: 78%"/> <icon data="/ig/images/weather/cn_overcast.gif"/> <wind_condition data="风向: 东北、风速:4 米/秒"/> </current_conditions> <forecast_conditions> <day_of_week data="周日"/> <low data="21"/> <high data="29"/> <icon data="/ig/images/weather/chance_of_storm.gif"/> <condition data="可能有暴风雨"/> </forecast_conditions> <forecast_conditions> <day_of_week data="周一"/> <low data="22"/> <high data="33"/> <icon data="/ig/images/weather/chance_of_storm.gif"/> <condition data="可能有暴风雨"/> </forecast_conditions> <forecast_conditions> <day_of_week data="周二"/> <low data="21"/> <high data="34"/> <icon data="/ig/images/weather/sunny.gif"/> <condition data="晴"/> </forecast_conditions> <forecast_conditions> <day_of_week data="周三"/> <low data="21"/> <high data="33"/> <icon data="/ig/images/weather/chance_of_storm.gif"/> <condition data="可能有暴风雨"/> </forecast_conditions> </weather> </xml_api_reply>怎样将该xml文件的天气信息形如
-----------------------------------------------------------
今日周二
图片 最低温度23度 最高温度35度
可能有暴风雨
-----------------------------------------------------------
以“图文并茂”的友好形式展现在手机界面上呢?
其实这个过程就是改变了数据的形式和位置,而保持了数据的含义不变。
在android中,数据是以java对象的形式传递的,因而首先需要将xml文件转变为java对象(如本例,可将文件先转变为具有week,low,high,pic,message属性的Weather对象),再将java数据提供给布局文件使用,从而最终能以友好的形式出现在界面上。
其中“将xml文件转变为java对象”的过程就是xml解析。
在android中,有三种,sax,pull,dom。但常用的是前两种(它们较相似,都是事件触发,边读取边解析),而dom解析则是先将xml文件全部读入内存,在进行解析-----这势必会对手机的内存开销很大,因而通常不采用它。
大体上,解析都需要三个参与者:xml文件(数据源,要解析的对象)、目标对象(要解析成的数据格式),解析处理程序
我们开发人员在这里主要需要做的就是 【根据解析的具体目标和选择的解析方式编写出能控制解析流程的代码】
①SAX解析
public class WeatherService { public List<Weather> getWeather(InputStream stream) throws Exception { WeatherHandler w = new WeatherHandler(); SAXParserFactory factory = SAXParserFactory.newInstance();//先获得sax解析工厂 SAXParser parser = factory.newSAXParser();//获得工厂生产的sax解析器 parser.parse(stream, w);//调用解析器的解析方法 return w.getWeatherList(); } public List<Weather> getWeather(String xml) throws Exception { WeatherHandler w = new WeatherHandler(); SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse(new InputSource(new StringReader(xml)), w); return w.getWeatherList(); } //内部类 private class WeatherHandler extends DefaultHandler { private List<Weather> weatherList; private Weather weather; private String target;//用来跟踪当前的解析的是哪个结点(主要为了避免不同的结点有相同名称的子节点) public List<Weather> getWeatherList() { return weatherList; } @Override public void startDocument() throws SAXException { weatherList = new ArrayList<Weather>();//解析前先new出一个用来存放解析结果的集合List<Object> }//uri表示命名空间的名称,localName表示冒号后的名称,如k:state k表示uri,state表示localName
//qName 则表示全名,attributes 表示属性@Overridepublic void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if("forecast_conditions".equals(localName)) { weather = new Weather(); target = "forecast_conditions"; } else if("day_of_week".equals(localName) && "forecast_conditions".equals(target)) {//加上后一个条件是为了避免不同的结点有相同名称的子节点
weather.setDate(attributes.getValue("data") );
} else if("low".equals(localName) && "forecast_conditions".equals(target)) {weather.setLow(attributes.getValue("data"));} else if("high".equals(localName) && "forecast_conditions".equals(target)) { weather.setHign(attributes.getValue("data")); } else if("icon".equals(localName) && "forecast_conditions".equals(target)) { weather.setWeatherPic(attributes.getValue("data")); } else if("condition".equals(localName) && "forecast_conditions".equals(target)) { weather.setMessage(attributes.getValue("data")); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if("forecast_conditions".equals(localName)) {//解析完一个目标结点,就招收成果,也就是将对象添加到对象集合中 weatherList.add(weather); target = null;//将target置为null是符合实际的,因为在解析两个目标节点之间是存在空档期的 } } @Override public void characters(char[] ch, int start, int length) throws SAXException { } @Override public void endDocument() throws SAXException { System.out.println("xml解析结束"); } } }
②Pull解析
public List<Weather> getWeatherWithPull(String xml) throws Exception { List<Weather> list = null; Weather w = null; XmlPullParser parser = Xml.newPullParser(); parser.setInput(new StringReader(xml));//对解析器设置数据源 int event = parser.getEventType(); //与SAX解析相比,event用来表示事件类型,有相关的常量,对应于SAX中的documentStart方法等 while(event != XmlPullParser.END_DOCUMENT) {//解析直至结束 switch(event) { case XmlPullParser.START_DOCUMENT: list = new ArrayList<Weather>(); //初始化用于盛放结果的对象集合 break; case XmlPullParser.START_TAG : String tagName = parser.getName(); if("forecast_conditions".equals(tagName)) { //tag w = new Weather(); } else if("day_of_week".equals(tagName) && w != null) { w.setDate(parser.getAttributeValue(null,"data"));//null 表示没有命名空间 } else if("low".equals(tagName) && w != null) { w.setLow(parser.getAttributeValue(null, "data")); } else if("high".equals(tagName) && w != null) { w.setHign(parser.getAttributeValue(null, "data")); } else if("icon".equals(tagName) && w != null) { w.setWeatherPic(parser.getAttributeValue(null, "data")); } else if("condition".equals(tagName) && w != null) { w.setMessage(parser.getAttributeValue(null, "data"));// } break; case XmlPullParser.END_TAG: String endTagName = parser.getName(); if("forecast_conditions".equals(endTagName)) { list.add(w); w = null; } break; } event = parser.next(); } return list; }
③DOM解析
public List<Weather> getWeatherWithDom(String xml) throws Exception { List<Weather> weatherList = null; DocumentBuilder dom = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = dom.parse(new InputSource(new StringReader(xml))); Element root = doc.getDocumentElement(); NodeList list = root.getElementsByTagName("forecast_conditions"); for(int i = 0;i<list.getLength();i++) { if(weatherList == null) { weatherList = new ArrayList<Weather>(); } Weather w = new Weather(); Node node = list.item(i); NodeList child= node.getChildNodes(); for(int j = 0;j<child.getLength();j++) { Element childNode = (Element) child.item(j); //获取节点名称 String nodeName = childNode.getNodeName(); if("day_of_week".equals(nodeName)) { w.setDate(childNode.getAttribute("data")); } else if("low".equals(nodeName)) { w.setLow(childNode.getAttribute("data")); } else if("high".equals(nodeName)) { w.setHign(childNode.getAttribute("data")); } else if("icon".equals(nodeName)) { w.setWeatherPic(childNode.getAttribute("data")); } else if("condition".equals(nodeName)) { w.setMessage(childNode.getAttribute("data")); } } weatherList.add(w); } return weatherList; }