昨天由于时间比较匆忙只写了Android中的XML解析的Dom方式,这种方式比较方便,很容易理解,最大的不足就是内容多的时候,会消耗内存。SAX(Simple API for XML)是一个解析速度快并且占用内存少的xml解析器,非常适合用于Android等移动设备。这次使用SAX解析XML文件接着我们来看看另一种解析xml的方式,通过sax来对xml文档进行解析。
SAX解析XML文件采用的是事件驱动,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。所谓事件,实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口。Android中Default已经封装了这些方法,继承DefaultHandler一般来说需要重写的方法有四个:
//用于处理文档解析开始事件 public void startDocument()throws SAXException //处理元素开始事件,从参数中可以获得元素所在名称空间的uri,元素名称,属性类表等信息 public void startElement(String namespacesURI , String localName , String qName , Attributes atts) throws SAXException //处理元素结束事件,从参数中可以获得元素所在名称空间的uri,元素名称等信息 public void endElement(String namespacesURI , String localName , String qName) throws SAXException //处理元素的字符内容,从参数中可以获得内容 public void characters(char[] ch , int start , int length) throws SAXException
自定义的BookHandler:
public class BookHandler extends DefaultHandler { private static List<Book> bookList = null; private static String tagName; private Book book = null; public List<Book> getBooks() { return bookList; } @Override public void startDocument() throws SAXException { // TODO Auto-generated method stub super.startDocument(); } public BookHandler() { super(); bookList = new ArrayList<Book>(); } @Override public void endDocument() throws SAXException { // TODO Auto-generated method stub super.endDocument(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // 读取Book tagName = localName; if (localName.equals("Book")) { book = new Book(); book.setName(attributes.getValue("name")); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (localName.equals("Book")) { bookList.add(book); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String value = new String(ch, start, length).trim(); if(value != null && !"".equals(value) && !"\n".equals(value)) { switch (tagName) { case "Title": Log.i("titleString", value); book.setTitle(value); } } } }
看下效果图,跟上次一样:
Book.xml中的内容:
<?xml version="1.0" encoding="utf-8"?> <Books> <Book name="康师傅的亿万帝国" > <Title> 据周元根的小学同学回忆,大约7岁那年,周元根开始读小学,由于和别人重名,于是改了名字。但他在村里一直沿用“周元根”这个名字,周家祖坟的5块墓碑上,刻的也是“周元根”这个名字。 </Title> <Picture> http://p.qpic.cn/ninja/0/ninja1406636943/0 </Picture> </Book> <Book name="徐才厚受贿额特别巨大" > <Title> 根据最高人民检察院授权,军事检察院对中央军委原副主席徐才厚以涉嫌受贿犯罪立案侦查。2014年10月27日,对该案侦查终结,移送审查起诉。 </Title> <Picture> http://www.sinaimg.cn/dy/slidenews/1_img/2014_44/2841_506865_709392.jpg </Picture> </Book> <Book name="发改委副司长魏鹏远" > <Title> 最高人民检察院反贪污贿赂总局局长徐进辉今日表示,煤炭司副司长魏鹏远家中搜查发现现金折合人民币2亿余元,成为建国以来检察机关一次起获赃款现金数额最大的案件。 </Title> <Picture> http://img1.cache.netease.com/catchpic/D/DC/DCB2315FD0F50C665BB1474768192642.jpg </Picture> </Book> </Books>
获取XML文件中的内容:
public List<Book> getBooksBySAX(String fileName){ //实例一个SAX工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); try { //实例一个解析器对象 SAXParser parser = factory.newSAXParser(); //实例化一个XML解析流 XMLReader reader = parser.getXMLReader(); //自定义的Handler BookHandler bookHandler=new BookHandler(); reader.setContentHandler(bookHandler); reader.parse( new InputSource(this.getResources().getAssets().open("Book.xml"))); list=bookHandler.getBooks(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return list; }
Activity中的调用:
list=getBooksBySAX("Book.xml"); Log.i("test",String.valueOf(list.size())); View view = getLayoutInflater().inflate(R.layout.activity_book_sax, null); ListView listView = (ListView) findViewById(R.id.list_sax); listView.setAdapter(new saxAdapter());
自定义的Adapter:
class saxAdapter extends BaseAdapter { @Override public int getCount() { // TODO Auto-generated method stub return list.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { Book book = (Book) list.get(position); View view = null; if (convertView == null) { LayoutInflater layoutInflater = getLayoutInflater(); view = layoutInflater.inflate(R.layout.book, null); } else { view = convertView; }; TextView titleView = (TextView) view.findViewById(R.id.itemTitle); titleView.setText(book.getName()); TextView contentView = (TextView) view.findViewById(R.id.itemText); contentView.setText(book.getTitle()); return view; } }
这里面最重要的就是自定义Handler,里面需要注意的是startElement,endElement,characters执行顺序的问题,顺序是startElement=>characters=>endElement,先解析标签,直到找到内容之后才开始endElement。