快捷搜索:

android解析xml文件的方式(其二)

上一节中,我们应用DOM要领解析xml文档,该要领对拍照符我们日常思维要领,轻易上手,然则它直接把文档调入内存中,对照耗内存。在这里我们可以用别的一种要领解析xml,这个便是SAX要领。

SAX等于:Simple API for XML

SAX是基于事故驱动的。当然android的事故机制是基于回调函数的,在用SAX解析xml文档时刻,在读取到文档开始和停止标签时刻就会回调一个事故,在读取到其他节点与内容时刻也会回调一个事故。

既然涉及到事故,就有事故源,事故处置惩罚器。在SAX接口中,事故源是org.xml.sax包中的XMLReader,它经由过程parser()措施来解析XML文档,并孕育发肇事故。事故处置惩罚器是org.xml.sax包中ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口

XMLReader经由过程响应事故处置惩罚器注册措施setXXXX()来完成的与ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口的连接,具体先容请见下表:

然则我们无需都承袭这4个接口,SDK为我们供给了DefaultHandler类来处置惩罚,DefaultHandler类的一些主要事故回调措施如下:

由以上可知,我们必要XmlReader 以及DefaultHandler来共同解析xml。

处置惩罚思路是:

1:创建SAXParserFactory工具

2: 根据SAXParserFactory.newSAXParser()措施返回一个SAXParser解析器

3:根据SAXParser解析器获取事故源工具XMLReader

4:实例化一个DefaultHandler工具

5:连接事故源工具XMLReader到事故处置惩罚类DefaultHandler中

6:调用XMLReader的parse措施从输入源中获取到的xml数据

7:经由过程DefaultHandler返回我们必要的数据聚拢。

代码如下:

public ListRiver> parse(String xmlPath){

ListRiver> rivers=null;

SAXParserFactory factory=SAXParserFactory.newInstance();

try {

SAXParser parser=factory.newSAXParser();

//获取事故源

XMLReader xmlReader=parser.getXMLReader();

//设置处置惩罚器

RiverHandler handler=new RiverHandler();

xmlReader.setContentHandler(handler);

//解析xml文档

//xmlReader.parse(new InputSource(new URL(xmlPath).openStream()));

xmlReader.parse(new InputSource(this.context.getAssets().open(xmlPath)));

rivers=handler.getRivers();

} catch (ParserConfigurationException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (SAXException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return rivers;

}

重点在于DefaultHandler工具中对每一个元素节点,属性,文本内容,文档内容进行处置惩罚。

前面说过DefaultHandler是基于事故处置惩罚模型的,基础处置惩罚要领是:当SAX解析器导航到文档开始标签时回调startDocument措施,导航到文档停止标签时回调endDocument措施。当SAX解析器导航到元素开始标签时回调startElement措施,导航到其文本内容时回调characters措施,导航到标签停止时回调endElement措施。

根据以上的解释,我们可以得出以下处置惩罚xml文档逻辑:

1:当导航到文档开始标签时,在回调函数startDocument中,可以不做处置惩罚,当然你可以验证下UTF-8等等。

2:当导航到rivers开始标签时,在回调措施startElement中可以实例化一个聚拢用来存贮list,不过我们这里不用,由于在构造函数中已经实例化了。

3:导航到river开始标签时,就阐明必要实例化River工具了,当然river标签中还有name ,length属性,是以实例化River后还必须掏出属性值,attributes.getValue(NAME),同时付与river工具中,同时添加为导航到的river标签添加一个boolean为真的标识,用来阐明导航到了river元素。

4:当然有river标签内还有子标签(节点),然则SAX解析器是不知道导航到什么标签的,它只相识开始,停止而已。那么若何让它认得我们的各个标签呢?当然必要判断了,于是可以应用回调措施startElement中的参数String localName,把我们的标具名符串与这个参数对照下,就可以了。我们还必须让SAX知道,现在导航到的是某个标签,是以添加一个true属性让SAX解析器知道。是以

5:它还会导航到文本内标签,(便是里面的内容),回调措施characters,我们一样平常在这个措施中掏出便是里面的内容,并保存。

6:当然它是必然会导航到停止标签 或者的,假如是标签,记得把river工具添加进list中。假如是river中的子标签,就把前面设置标记导航到这个标签的boolean标记设置为false.

按照以上实现思路,可以实现如下代码:

/**导航到开始标签触发**/

public void startElement (String uri, String localName, String qName, Attributes attributes){

String tagName=localName.length()!=0?localName:qName;

tagName=tagName.toLowerCase().trim();

//假如读取的是river标签开始,则实例化River

if(tagName.equals(RIVER)){

isRiver=true;

river=new River();

/**导航到river开始节点后**/

river.setName(attributes.getValue(NAME));

river.setLength(Integer.parseInt(attributes.getValue(LENGTH)));

}

//然后读取其他节点

if(isRiver){

if(tagName.equals(INTRODUCTION)){

xintroduction=true;

}else if(tagName.equals(IMAGEURL)){

ximageurl=true;

}

}

}

/**导航到停止标签触发**/

public void endElement (String uri, String localName, String qName){

String tagName=localName.length()!=0?localName:qName;

tagName=tagName.toLowerCase().trim();

//假如读取的是river标签停止,则把River添加进聚拢中

if(tagName.equals(RIVER)){

isRiver=true;

rivers.add(river);

}

//然后读取其他节点

if(isRiver){

if(tagName.equals(INTRODUCTION)){

xintroduction=false;

}else if(tagName.equals(IMAGEURL)){

ximageurl=false;

}

}

}

//这里是读取到节点内容时刻回调

public void characters (char[] ch, int start, int length){

//设置属性值

if(xintroduction){

//办理null问题

river.setIntroduction(river.getIntroduction()==null?"":river.getIntroduction()+new String(ch,start,length));

}else if(ximageurl){

//办理null问题

river.setImageurl(river.getImageurl()==null?"":river.getImageurl()+new String(ch,start,length));

}

}

您可能还会对下面的文章感兴趣: