Android 使用SAX读取XML文件

SAX是一个解析速度快并且占用内存少的xml解析器,非常适合用于Android等移动设备。关于它的详细介绍请参考http://www.saxproject.org/

 SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口。

下面是一些ContentHandler接口常用的方法:

  • startDocument()  当遇到文档的开头的时候,调用这个方法,可以在其中做一些预处理的工作。
  • endDocument()    和上面的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。 
  • startElement(String namespaceURI, String localName, String qName, Attributes atts)    当读到一个开始标签的时候,会触发这个方法。namespaceURI就是命名空间,localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名。通过atts可以得到所有的属性名和相应的值。要注意的是SAX中一个重要的特点就是它的流式处理,当遇到一个标签的时候,它并不会纪录下以前所碰到的标签,也就是说,在startElement()方法中,所有你所知道的信息,就是标签的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元属等等其它与结构相关的信息,都是不得而知的,都需要你的程序来完成。这使得SAX在编程处理上没有DOM来得那么方便。
  • endElement(String uri, String localName, String name)   这个方法和上面的方法相对应,在遇到结束标签的时候,调用这个方法。
  • characters(char[] ch, int start, int length)    这个方法用来处理在XML文件中读到的内容,第一个参数用于存放文件的内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。
假设我们要解析的xml文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<persons>

	<person id="23">

		<name>李明</name>

		<age>30</age>

	</person>

	<person id="20">

		<name>李向梅</name>

		<age>25</age>

	</person>

</persons>


解析itcast.xml触发的事件为:

读到的标签及内容       触发事件 

{文档开始}          startDocument() 

<persons>           startElement(, "persons", null, "{Attributes}")

"\n\t"              characters("<persons>...</persons>", "12", "2")

<person>            startElement(, "person", null, "{Attributes}")

"\n\t\t"            characters("<persons>...</persons>", "31", "3")

<name>              startElement(, "name", null, "{Attributes}")

"李明"              characters("<persons>...</persons>", "40", "2")

</name>             endElement("", "name", null)

"\n\t\t"            characters("<persons>...</persons>", "50", "3")

<age>               startElement(, "age", null, "{Attributes}")

"30"                characters("<persons>...</persons>", "58", "2")

</age>              endElement("", "age", null)

"\n\t"              characters("<persons>...</persons>", "67", "2")

</person>           endElement("", "person", null)

"\n\t"              characters("<persons>...</persons>", "79", "2")

<person>            startElement(, "person", null, "{Attributes}")

"\n\t\t"            characters("<persons>...</persons>", "98", "3")

<name>              startElement(, "name", null, "{Attributes}")

"李向梅"            characters("<persons>...</persons>", "107", "3")

</name>             endElement("", "name", null)

"\n\t\t"            characters("<persons>...</persons>", "118", "3")

<age>               startElement(, "age", null, "{Attributes}")

"25"                characters("<persons>...</persons>", "126", "2")

</age>              endElement("", "age", null)

"\n\t"              characters("<persons>...</persons>", "135", "2")

</person>           endElement("", "person", null)

"\n"                characters("<persons>...</persons>", "147", "1")

</persons>          endElement("", "persons", null)

{文档结束}          endDocument() 

下面我们给出一个读取xml文件的实例:
首先新建一个person类,用来存放xml结构的数据
person.java
package com.example.xmlparsedemo;

public class Person {
	private Integer id;

	private String name;

	private Short age;

	public Integer getId() {

	return id;

	}

	public void setId(Integer id) {

	this.id = id;

	}

	public String getName() {

	return name;

	}

	public void setName(String name) {

	this.name = name;

	}

	public Short getAge() {

	return age;

	}

	public void setAge(Short age) {

	this.age = age;

	}

}

然后继承 ContentHandler,并重载用到的函数:
XMLContentHandler.java
package com.example.xmlparsedemo;

import java.util.ArrayList;
import java.util.List;
 

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class XMLContentHandler extends DefaultHandler {
 
	
	private List<Person> persons = null;

	private Person currentPerson;

	private String tagName = null;//当前解析的元素标签
	
	public List<Person> getPersons() {

		return persons;
	}
	
	/*
	* 接收文档的开始的通知。
	*/
	@Override public void startDocument() throws SAXException {
		
		persons = new ArrayList<Person>();
		
	}
	
	/*
	* 接收字符数据的通知。
	*/

	@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("name")){

				this.currentPerson.setName(data);

		   }else if(tagName.equals("age")){

			this.currentPerson.setAge(Short.parseShort(data));

		   }
	  }
	}
	
	/*
	* 接收元素开始的通知。
	* 参数意义如下:
	*    namespaceURI:元素的命名空间
	*    localName :元素的本地名称(不带前缀)
	*    qName :元素的限定名(带前缀)
	*    atts :元素的属性集合
	*/

	@Override public void startElement(String uri, String localName, String qName,Attributes attributes)throws SAXException {

		if(localName.equals("person")){

		currentPerson = new Person();

		currentPerson.setId(Integer.parseInt(attributes.getValue("id")));

		}

		this.tagName = localName;

		}
	
	
	/*

	* 接收文档的结尾的通知。
	* 参数意义如下:
	*    uri :元素的命名空间
	*    localName :元素的本地名称(不带前缀)
	*    name :元素的限定名(带前缀)
	* 
	*/

	@Override public void endElement(String uri, String localName, String name) throws SAXException {

	if(localName.equals("person")){

		persons.add(currentPerson);

		currentPerson = null;

		}

	this.tagName = null;

	}
}


然后在mianAcitvity里添加一个解析xml的API readXml

public static List<Person> readXML(InputStream inStream) {

		   try {

		SAXParserFactory spf = SAXParserFactory.newInstance();

		SAXParser saxParser = spf.newSAXParser(); //创建解析器

		//设置解析器的相关特性,http://xml.org/sax/features/namespaces = true 表示开启命名空间特性  

		//saxParser.setProperty("http://xml.org/sax/features/namespaces",true);

		XMLContentHandler handler = new XMLContentHandler();

		saxParser.parse(inStream, handler);

		inStream.close();

		return handler.getPersons();

		   } catch (Exception e) {

			   e.printStackTrace();

		   }

		  return null;

		}
}

最终须有在mainAcitvity里测试该接口能否完成任务:


MainActivity.java
package com.example.xmlparsedemo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity {

	private List<Person> persons = null;
	private Person p=null;
	public static List<Person> readXML(InputStream inStream) {

		try {

		SAXParserFactory spf = SAXParserFactory.newInstance();

		SAXParser saxParser = spf.newSAXParser(); //创建解析器

		//设置解析器的相关特性,http://xml.org/sax/features/namespaces = true 表示开启命名空间特性  

		//saxParser.setProperty("http://xml.org/sax/features/namespaces",true);

		XMLContentHandler handler = new XMLContentHandler();

		saxParser.parse(inStream, handler);

		inStream.close();

		return handler.getPersons();
		
		} catch (Exception e) {
			   e.printStackTrace();
		   }

		return null;

		}
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		InputStream r =null;
		r=  getClass().getResourceAsStream("test.xml");
		if (r==null)
		{
			Log.v("com.example.exlparsedemo", "file not found");
			return;
		}
		URL url = getClass().getResource("test.xml");
		String path= url.getPath();

		
		persons=readXML(r);
		
		if(null!=persons)
		{
			
			for(int i=0;i<persons.size();i++)
			{
				p=persons.get(i);
				Log.v("id", p.getId().toString());
				Log.v("name", p.getName());
				Log.v("age", p.getAge().toString());
				
			}
		}
		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}
	
}


至此,基本完成使用SAX解析xml的完整例子。
该demo运行的结果是可以从log中看到 xml里保存的两个person 的in、name、 age。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值