简单记录一下xml的三种解析方式,主要介绍sax和pull,dom解析方式就不去在demo中体现了。
DOM方式解析xml是先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据。由DOM解析的方式可以知道,如果XML文件很大的时候,处理效率就会变得比较低,这也是DOM方式的一个缺点。
现在我们来解析上文中提到的有关天气预报信息相关的xml文件。什么是解析呢?说的通俗一点,就是将这个带标签的XML文件识别出来,并抽取一些相关的,对我们有用的信息来给我们使用。那在这个文件里,时间,天气,温度,以及图标对我们来说是需要得到的。我们要对其做解析。
解析的具体思路是:
1. 将XML文件加载进来。
2. 获取文档的根节点
3. 获取文档根节点中所有子节点的列表
4. 获取子节点列表中需要读取的节点信息
使用SAX解析XML文件一般有以下五个步骤:
1、创建一个SAXParserFactory对象;
2、调用SAXParserFactory中的newSAXParser方法创建一个SAXParser对象;
3、然后在调用SAXParser中的getXMLReader方法获取一个XMLReader对象;
4、实例化一个DefaultHandler对象
5、连接事件源对象XMLReader到事件处理类DefaultHandler中
6、调用XMLReader的parse方法从输入源中获取到的xml数据
7、通过DefaultHandler返回我们需要的数据集合。
具体的代码实现如下所示:
//创建一个解析器工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); //通过工厂创建解析器 SAXParser saxParser =factory.newSAXParser(); //创建所需要的handler对象 XMLContentHandler handler=new XMLContentHandler(); //开始解析 saxParser.parse(inputStream, handler); //关闭输入流 inputStream.close(); //得到返回的citylist结果 CityArray = handler.getList();这里比较重要的一点就是实现ContentHandler类,主要分为如下几个步骤:
1、声明一个类,继承DefaultHandler。DefaultHandler是一个基类,这个类里面简单实现了一个ContentHandler。我们只需要重写里面的方法即可。
2、重写 startDocument() 和 endDocument(),一般解析将正式解析之前的一些初始化工资放到startDocument()里面,收尾的工作放到endDocument()里面。
3、重写startElement(String uri, String localName, String qName, Attributes attributes),XML解析器遇到XML里面的tag时就会调用这个函数。经常在这个函数内是通过localName俩进行判断而操作一些数据。
4、重写characters(char[] ch,int start,int length)方法,这是一个回调方法。解析器执行完startElement()后,解析完节点的内容后就会执行这个方法,并且参数ch[]就是节点的内容。第一个参数用于存放文件的内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。
5、重写endElement(String uri, String localName, String qName)方法,这个方法与startElement()相对应,解析完一个tag节点后,执行这个方法。
具体代码示例如下:
// 解析到xml文档结束的时候,调用这个方法,可以在其中做一些善后的工作 @Override public void endDocument() throws SAXException { super.endDocument(); } // 解析到结束标签的时候,调用这个方法 @Override public void endElement(String uri, String localName, String qName) throws SAXException { /* * 当结束标签为item的时候 把cityInfo加入到citylist列表中,同时设置cityInfo为空 */ if ("item".equals(qName) && cityInfo != null) { cityList.add(cityInfo); cityInfo = null; } this.tagName = null; super.endElement(uri, localName, qName); } // 解析到xml文档开头的时候,调用这个方法,可以在其中做一些预处理的工作 @Override public void startDocument() throws SAXException { // 实例化cityList集合 cityList = new ArrayList<City>(); super.startDocument(); } /* * 1.当读到一个开始标签的时候,会触发这个方法 * 2.localName参数代表不带命名空间前缀的标签的名称 * 3.qName参数代表带命名空间前缀的标签的名称 * 4.attributes参数表示元素内部属性名和属性值的集合 */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // 解析到province的时候, if ("province".equals(localName)) { provinceId = Integer.parseInt(attributes.getValue("id")); } // 解析到item的时候,实例City,用来保存城市信息 if ("item".equals(localName)) { cityInfo = new City(); cityInfo.setProvinceId(provinceId); } this.tagName = localName; super.startElement(uri, localName, qName, attributes); } /* * 用于处理xml文件中读到的内容 */ @Override public void characters(char[] ch, int start, int length) throws SAXException { if (tagName != null) { String data = new String(ch, start, length); if (tagName.equals("id")) { this.cityInfo.setCityId(Integer.parseInt(data)); } else if (tagName.equals("name")) { this.cityInfo.setCityName(data); } } super.characters(ch, start, length); }
(1)pull方式解析xml
PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。
具体代码如下:
public static ArrayList<City> Parse(String CityString){ ArrayList<City> CityArray = new ArrayList<City>(); try { //定义工厂 XmlPullParserFactory XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); //定义解析器 XmlPullParser XmlPullParser parser = factory.newPullParser(); //获取xml输入数据 parser.setInput(new StringReader(CityString)); CityArray = ParseXml(parser); } catch (XmlPullParserException e) { // TODO Auto-generated catch block e.printStackTrace(); } return CityArray; } public static ArrayList<City> ParseXml(XmlPullParser parser){ ArrayList<City> CityArray = new ArrayList<City>(); City CityTemp = null; int provinceId = 0; int cityId; String cityName; try { //开始解析事件 int eventType = parser.getEventType(); //处理事件,不碰到文档结束就一直处理 while (eventType != XmlPullParser.END_DOCUMENT) { //因为定义了一堆静态常量,所以这里可以用switch switch (eventType) { case XmlPullParser.START_DOCUMENT: break; case XmlPullParser.START_TAG: //给当前标签起个名字 String tagName = parser.getName(); // Log.d("", "====XmlPullParser.START_TAG=== tagName: " + tagName); if(tagName.equals("province")){ provinceId = Integer.parseInt(parser.getAttributeValue(0)); }else if(tagName.equals("item")){ CityTemp = new City(); }else if(tagName.equals("id")){ cityId = Integer.parseInt(parser.nextText()); parser.next(); cityName = parser.nextText(); Log.v("", "id getText: "+cityId); Log.v("", "name getText: "+cityName); Log.e("", "========================="); CityTemp.setProvinceId(provinceId); CityTemp.setCityId(cityId); CityTemp.setCityName(cityName); CityArray.add(CityTemp); } break; case XmlPullParser.END_TAG: break; case XmlPullParser.END_DOCUMENT: break; } //别忘了用next方法处理下一个事件,忘了的结果就成死循环 eventType = parser.next(); } } catch (XmlPullParserException e) { // TODO Auto-generated catch block e.printStackTrace(); }catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return CityArray; }
(2)pull方式生成xml
protected void PullGenerateXML() throws CustomException { File dir = new File(XML_PATH);
//这一部分可以忽略,为了测试自定义异常写的,跟pull解析没有关系 if (dir.exists()) { CustomException customException = new CustomException("如果路径存在" + "抛出自定义异常"); Toast.makeText(MainActivity.this, "抛出自定义异常:你要创建的保存xml的文件夹已经存在(just for test)", Toast.LENGTH_LONG) .show(); throw customException; } dir.mkdir(); File file = new File(dir, XML_NAME); FileWriter writer; try { //创建一个输出流 writer = new FileWriter(file); //new一个XmlSerializer XmlSerializer serializer = XmlPullParserFactory.newInstance() .newSerializer(); //设置outputstream serializer.setOutput(writer); //生成xml的具体内容 serializer.startTag(null, "student").startTag(null, "name") .text("robin").endTag(null, "name") .startTag(null, "gender").text("男").endTag(null, "gender") .startTag(null, "age").text("25").endTag(null, "age") .endTag(null, "student"); //flush,关闭流 serializer.flush(); writer.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (XmlPullParserException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
下面是两个具体的demo:
http://download.csdn.net/detail/lanhuzi9999/7598331
http://download.csdn.net/detail/lanhuzi9999/7598335