android网络编程--xml解析

简单记录一下xml的三种解析方式,主要介绍sax和pull,dom解析方式就不去在demo中体现了。

DOM方式

DOM方式解析xml是先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据。DOM解析的方式可以知道,如果XML文件很大的时候,处理效率就会变得比较低,这也是DOM方式的一个缺点。

现在我们来解析上文中提到的有关天气预报信息相关的xml文件。什么是解析呢?说的通俗一点,就是将这个带标签的XML文件识别出来,并抽取一些相关的,对我们有用的信息来给我们使用。那在这个文件里,时间,天气,温度,以及图标对我们来说是需要得到的。我们要对其做解析。

解析的具体思路是:

1.   XML文件加载进来。

2.   获取文档的根节点

3.   获取文档根节点中所有子节点的列表

4.   获取子节点列表中需要读取的节点信息

SAX方式

相比于 DOM 而言 SAX 是一种速度更快,更有效,占用内存更少的解析 XML 文件的方法。它是逐行扫描,可以做到边扫描边解析,因此 SAX 可以在解析文档的任意时刻停止解析。非常适用于 Android 等移动设备。SAX是基于事件驱动的。所谓事件驱动就是说,它不用解析完整个文档,在按内容顺序解析文档过程中,SAX会判断当前读到的字符是否符合XML文件语法中的某部分。如果符合某部分,则会触发事件。所谓触发事件,就是调用一些回调方法。当然android的事件机制是基于回调方法的,在用SAX解析xml文档时候,在读取到文档开始和结束标签时候就会回调一个事件,在读取到其他节点与内容时候也会回调一个事件。

使用SAX解析XML文件一般有以下五个步骤:

1、创建一个SAXParserFactory对象;
2
、调用SAXParserFactory中的newSAXParser方法创建一个SAXParser对象;
3
、然后在调用SAXParser中的getXMLReader方法获取一个XMLReader对象;

4、实例化一个DefaultHandler对象

5、连接事件源对象XMLReader到事件处理类DefaultHandler

6、调用XMLReaderparse方法从输入源中获取到的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);
	}

PULL方式

(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();
		}

	}


这三种解析器各有优点,但是在android设备中最常用的就是使用pull解析方法,dom解析方式对于安卓设备不是很试用,sax解析方式编码起来不是很灵活。


下面是两个具体的demo:

http://download.csdn.net/detail/lanhuzi9999/7598331

http://download.csdn.net/detail/lanhuzi9999/7598335


你可能感兴趣的:(android,sax,parse,pull)