转载请注明出处:http://blog.csdn.net/yegongheng/article/details/38296207


XML初步

今天我们来学习另一种非常重要的数据交换格式-XML。XML(Extensible Markup Language的缩写,意为可扩展的标记语言),它是一种元标记语言,即定义了用于定义其他特定领域有关语义的、结构化的标记语言,这些标记语言将文档分成许多部件并对这些部件加以标识。XML 文档定义方式有:文档类型定义(DTD)和XML Schema。DTD定义了文档的整体结构以及文档的语法,应用广泛并有丰富工具支持。XML Schema用于定义管理信息等更强大、更丰富的特征。XML能够更精确地声明内容,方便跨越多种平台的更有意义的搜索结果。它提供了一种描述结构数据的格式,简化了网络中数据交换和表示,使得代码、数据和表示分离,并作为数据交换的标准格式,因此它常被称为智能数据文档。
由于XML具有很强的扩展性,致使它需要很强的基础规则来支持扩展,所以在编写XML文件时,我们应该严格遵守XML的语法规则,一般XML语法有如下规则:(1)起始和结束的标签相匹配;(2)嵌套标签不能相互嵌套;(3)区分大小写。下面是给出了一个编写错误的XML文件以及对其的错误说明,如下:
本文只是对XML做了个简单的介绍,要想学习更多有关XML知识,可以访问如下网站:http://bbs.xml.org.cn/index.asp。
XML在实际应用中比较广泛,Android也不例外,作为承载数据的重要角色,如何读写XML称为Android开发中一项重要的技能。

Android中XML数据解析使用实例

在Android开发中,较为常用的XML解析器有SAX解析器、DOM解析器和PULL解析器,下面我们将会一一学习如何使用这些XML解析器。那在介绍这几种XML解析器过程中,我们依然是要通过一个实例来学习它们的实际开发方法,下面是我们Demo实例的程序列表清单,如下:
   
图1-1 客户端                                          图1-2 服务器端
来整理下我们实现的Demo实例思路:客户端通过网络请求读取服务器端的person.xml,person.xml文件中的内容如下:
[html] view plaincopyprint?
  1. <?xml version=“1.0” encoding=“UTF-8”?>
  2. <persons>
  3. <person id=“1”>
  4. <name>Transformers First</name>
  5. <height>7</height>
  6. <imageurl>imagefile/transformers_one.png</imageurl>
  7. </person>
  8. <person id=“2”>
  9. <name>Transformers second</name>
  10. <height>4</height>
  11. <imageurl>imagefile/transformers_two.png</imageurl>
  12. </person>
  13. <person id=“3”>
  14. <name>Transformers third</name>
  15. <height>8.5</height>
  16. <imageurl>imagefile/transformers_three.png</imageurl>
  17. </person>
  18. <person id=“4”>
  19. <name>Transformers fourth</name>
  20. <height>14.5</height>
  21. <imageurl>imagefile/transformers_four.png</imageurl>
  22. </person>
  23. <person id=“5”>
  24. <name>Transformers fifth</name>
  25. <height>27.5</height>
  26. <imageurl>imagefile/transformers_five.png</imageurl>
  27. </person>
  28. <person id=“6”>
  29. <name>Transformers Sixth</name>
  30. <height>8.5</height>
  31. <imageurl>imagefile/transformers_six.png</imageurl>
  32. </person>
  33. <person id=“7”>
  34. <name>Transformers Seventh</name>
  35. <height>5</height>
  36. <imageurl>imagefile/transformers_seven.png</imageurl>
  37. </person>
  38. <person id=“8”>
  39. <name>Transformers Eighth</name>
  40. <height>12.5</height>
  41. <imageurl>imagefile/transformers_eight.png</imageurl>
  42. </person>
  43. </persons>
<?xml version="1.0" encoding="UTF-8"?>
<persons><person id="1"><name>Transformers First</name><height>7</height><imageurl>imagefile/transformers_one.png</imageurl></person><person id="2"><name>Transformers second</name><height>4</height><imageurl>imagefile/transformers_two.png</imageurl></person><person id="3"><name>Transformers third</name><height>8.5</height><imageurl>imagefile/transformers_three.png</imageurl></person><person id="4"><name>Transformers fourth</name><height>14.5</height><imageurl>imagefile/transformers_four.png</imageurl></person><person id="5"><name>Transformers fifth</name><height>27.5</height><imageurl>imagefile/transformers_five.png</imageurl></person><person id="6"><name>Transformers Sixth</name><height>8.5</height><imageurl>imagefile/transformers_six.png</imageurl></person><person id="7"><name>Transformers Seventh</name><height>5</height><imageurl>imagefile/transformers_seven.png</imageurl></person><person id="8"><name>Transformers Eighth</name><height>12.5</height><imageurl>imagefile/transformers_eight.png</imageurl></person>
</persons>

接着将获取到的person.xml的文件流信息分别使用SAX、DOM和PULL解析方式解析成Java对象,然后将解析后获取到的Java对象信息以列表的形式展现在客户端,思路很简单吧。
Demo实例工程的下载地址:
好了,基本了解了Demo实例的整体思路后,接下来我们将学习如何具体实现它们。

SAX解析XML文件实例

SAX(Simple For XML)是一种基于事件的解析器,它的核心是事件处理模式,它主要是围绕事件源和事件处理器来工作的。当事件源产生事件后,会调用事件处理器中相应的方法来处理一个事件,那在事件源调用对应的方法时也会向对应的事件传递一些状态信息,以便我们根据其状态信息来决定自己的行为。
接下来我们将具体地学习一下SAX解析工作的主要原理:在读取XML文档内容时,事件源顺序地对文档进行扫描,当扫描到文档的开始与结束(Document)标签、节点元素的开始与结束(Element)标签时,直接调用对应的方法,并将状态信息以参数的形式传递到方法中,然后我们可以依据状态信息来执行相关的自定义操作。为了更好的理解SAX解析的工作原理,我们结合具体的代码来更深入的理解下,代码如下:
[java] view plaincopyprint?
  1. /**
  2. * SAX解析类
  3. * @author AndroidLeaf
  4. */
  5. public class MyHandler extends DefaultHandler {
  6. //当开始读取文档标签时调用该方法
  7. @Override
  8. public void startDocument() throws SAXException {
  9. // TODO Auto-generated method stub
  10. super.startDocument();
  11. }
  12. //当开始读取节点元素标签时调用该方法
  13. @Override
  14. public void startElement(String uri, String localName, String qName,
  15. Attributes attributes) throws SAXException {
  16. // TODO Auto-generated method stub
  17. super.startElement(uri, localName, qName, attributes);
  18. //do something
  19. }
  20. //当读取节点元素的子类信息时调用该方法
  21. @Override
  22. public void characters(char[] ch, int start, int length)
  23. throws SAXException {
  24. // TODO Auto-generated method stub
  25. super.characters(ch, start, length);
  26. //do something
  27. }
  28. //当结束读取节点元素标签时调用该方法
  29. @Override
  30. public void endElement(String uri, String localName, String qName)
  31. throws SAXException {
  32. // TODO Auto-generated method stub
  33. super.endElement(uri, localName, qName);
  34. //do something
  35. }
  36. //当结束读取文档标签时调用该方法
  37. @Override
  38. public void endDocument() throws SAXException {
  39. // TODO Auto-generated method stub
  40. super.endDocument();
  41. //do something
  42. }
  43. }
/*** SAX解析类* @author AndroidLeaf*/
public class MyHandler extends DefaultHandler {//当开始读取文档标签时调用该方法@Overridepublic void startDocument() throws SAXException {// TODO Auto-generated method stubsuper.startDocument();}//当开始读取节点元素标签时调用该方法@Overridepublic void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {// TODO Auto-generated method stubsuper.startElement(uri, localName, qName, attributes);//do something}//当读取节点元素的子类信息时调用该方法@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {// TODO Auto-generated method stubsuper.characters(ch, start, length);//do something}//当结束读取节点元素标签时调用该方法@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {// TODO Auto-generated method stubsuper.endElement(uri, localName, qName);//do something}//当结束读取文档标签时调用该方法@Overridepublic void endDocument() throws SAXException {// TODO Auto-generated method stubsuper.endDocument();//do something}}

首先我们先认识一个重要的类–DefaultHandler,该类是XML解析接口(EntityResolver, DTDHandler, ContentHandler, ErrorHandler)的缺省实现,在通常情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现这些接口更容易。接着重写startDocument(),startElement(),characters(),endElement和endDocument()五个方法,这些方法会在事件源(在org.xml.sax包中的XMLReader,通过parser()产生事件)读取到不同的XML标签所产生事件时调用。那我们开发时只要在这些方法中实现我们的自定义操作即可。下面总结罗列了一些使用SAX解析时常用的接口、类和方法:

事件处理器名称

事件处理器处理的事件

ContentHandler

XML文档的开始与结束;

XML文档节点元素的开始与结束,接收字符数据,跳过实体,接收元素内容中可忽略的空白等。

DTDHandler

处理DTD解析时产生的相应事件

ErrorHandler

处理XML文档时产生的错误

EntityResolver

处理外部实体

方法名称

方法说明

startDocument()

用于处理文档解析开始时间

startElement(String uri,String localName,String qName

Attributes attributes)

处理元素开始时间,从参数中可以获取元素所在空间的URL,元素名称,属性列表等信息。

characters(char[] ch,int start,int length)

处理元素的字符内容,从参数中可以获得内容

endElement(String uri,String localName,String qName)

处理元素结束时间,从参数中可以获取元素所在空间的URL,元素名称等信息。

endDocument()

用于处理文档解析的结束事件

基本了解完SAX解析工作原理及开发时用到的常用接口和类后,接下来我们来学习一下使用SAX解析XML的编程步骤,一般分为5个步骤,如下:
1、获取创建一个SAX解析工厂实例;
2、调用工厂实例中的newSAXParser()方法创建SAXParser解析对象;
3、实例化CustomHandler(DefaultHandler的子类);
4、连接事件源对象XMLReader到事件处理类DefaultHandler中;
5、通过DefaultHandler返回我们需要的数据集合。
接着,我们按照这5个步骤来完成Demo实例解析person.xml的工作(person.xml的内容上面已经列出),解析的关键代码是在Demo实例工程中的XmlTools类中,具体代码如下:
[java] view plaincopyprint?
  1. /**————–SAX解析XML——————-*/
  2. /**
  3. * @param mInputStream 需要解析的person.xml的文件流对象
  4. * @param nodeName 节点名称
  5. * @return mList Person对象集合
  6. */
  7. public static ArrayList<Person> saxAnalysis(InputStream mInputStream,String nodeName){
  8. //1、获取创建一个SAX解析工厂实例
  9. SAXParserFactory mSaxParserFactory = SAXParserFactory.newInstance();
  10. try {
  11. //2、调用工厂实例中的newSAXParser()方法创建SAXParser解析对象
  12. SAXParser mSaxParser = mSaxParserFactory.newSAXParser();
  13. //3、实例化CustomHandler(DefaultHandler的子类)
  14. CustomHandler mHandler = new CustomHandler(nodeName);
  15. /**
  16. * 4、连接事件源对象XMLReader到事件处理类DefaultHandler中
  17. * 查看parse(InputStream is, DefaultHandler dh)方法源码如下:
  18. * public void parse(InputSource is, DefaultHandler dh)
  19. *      throws SAXException, IOException {
  20. *      if (is == null) {
  21. *           throw new IllegalArgumentException(“InputSource cannot be null”);
  22. *       }
  23. *     // 获取事件源XMLReader,并通过相应事件处理器注册方法setXXXX()来完成的与ContentHander、DTDHander、ErrorHandler,
  24. *     // 以及EntityResolver这4个接口的连接。
  25. *       XMLReader reader = this.getXMLReader();
  26. *       if (dh != null) {
  27. *           reader.setContentHandler(dh);
  28. *           reader.setEntityResolver(dh);
  29. *           reader.setErrorHandler(dh);
  30. *           reader.setDTDHandler(dh);
  31. *       }
  32. *       reader.parse(is);
  33. *   }
  34. */
  35. mSaxParser.parse(mInputStream, mHandler);
  36. //5、通过DefaultHandler返回我们需要的数据集合
  37. return mHandler.getList();
  38. } catch (ParserConfigurationException e) {
  39. // TODO Auto-generated catch block
  40. e.printStackTrace();
  41. } catch (SAXException e) {
  42. // TODO Auto-generated catch block
  43. e.printStackTrace();
  44. } catch (IOException e) {
  45. // TODO Auto-generated catch block
  46. e.printStackTrace();
  47. }
  48. return null;
  49. }
/**--------------SAX解析XML-------------------*//*** @param mInputStream 需要解析的person.xml的文件流对象* @param nodeName 节点名称* @return mList Person对象集合*/public static ArrayList<Person> saxAnalysis(InputStream mInputStream,String nodeName){//1、获取创建一个SAX解析工厂实例SAXParserFactory mSaxParserFactory = SAXParserFactory.newInstance();try {//2、调用工厂实例中的newSAXParser()方法创建SAXParser解析对象SAXParser mSaxParser = mSaxParserFactory.newSAXParser();//3、实例化CustomHandler(DefaultHandler的子类)CustomHandler mHandler = new CustomHandler(nodeName);/*** 4、连接事件源对象XMLReader到事件处理类DefaultHandler中* 查看parse(InputStream is, DefaultHandler dh)方法源码如下:* public void parse(InputSource is, DefaultHandler dh)*      throws SAXException, IOException {*      if (is == null) {*           throw new IllegalArgumentException("InputSource cannot be null");*       }*     // 获取事件源XMLReader,并通过相应事件处理器注册方法setXXXX()来完成的与ContentHander、DTDHander、ErrorHandler,*     // 以及EntityResolver这4个接口的连接。*       XMLReader reader = this.getXMLReader();*       if (dh != null) {*           reader.setContentHandler(dh);*           reader.setEntityResolver(dh);*           reader.setErrorHandler(dh);*           reader.setDTDHandler(dh);*       }*       reader.parse(is);*   }*/mSaxParser.parse(mInputStream, mHandler);//5、通过DefaultHandler返回我们需要的数据集合return mHandler.getList();} catch (ParserConfigurationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SAXException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}

事件处理器类CustomerHandler中的具体代码如下:

[java] view plaincopyprint?
  1. /**
  2. * SAX解析类
  3. * @author AndroidLeaf
  4. */
  5. public class CustomHandler extends DefaultHandler {
  6. //装载所有解析完成的内容
  7. List<HashMap<String, String>> mListMaps = null;
  8. //装载解析单个person节点的内容
  9. HashMap<String, String> map = null;
  10. //节点名称
  11. private String nodeName;
  12. //当前解析的节点标记
  13. private String currentTag;
  14. //当前解析的节点值
  15. private String currentValue;
  16. public ArrayList<Person> getList(){
  17. ArrayList<Person> mList = new ArrayList<Person>();
  18. if(mListMaps != null && mListMaps.size() > 0){
  19. for(int i = 0;i < mListMaps.size();i++){
  20. Person mPerson = new Person();
  21. HashMap<String, String> mHashMap = mListMaps.get(i);
  22. mPerson.setId(Integer.parseInt(mHashMap.get(”id”)));
  23. mPerson.setUserName(mHashMap.get(”name”));
  24. mPerson.setHeight(Float.parseFloat(mHashMap.get(”height”)));
  25. mPerson.setImageUrl(mHashMap.get(”imageurl”));
  26. mList.add(mPerson);
  27. }
  28. }
  29. return mList;
  30. }
  31. public CustomHandler(String nodeName){
  32. this.nodeName = nodeName;
  33. }
  34. @Override
  35. public void startDocument() throws SAXException {
  36. // TODO Auto-generated method stub
  37. super.startDocument();
  38. mListMaps = new ArrayList<HashMap<String, String>>();
  39. }
  40. @Override
  41. public void startElement(String uri, String localName, String qName,
  42. Attributes attributes) throws SAXException {
  43. // TODO Auto-generated method stub
  44. if (qName.equals(nodeName)) {
  45. map = new HashMap<String, String>();
  46. }
  47. if (map != null && attributes != null) {
  48. for (int i = 0; i < attributes.getLength(); i++) {
  49. map.put(attributes.getQName(i), attributes.getValue(i));
  50. }
  51. }
  52. // 当前的解析的节点名称
  53. currentTag = qName;
  54. }
  55. @Override
  56. public void characters(char[] ch, int start, int length)
  57. throws SAXException {
  58. // TODO Auto-generated method stub
  59. if (map != null && currentTag != null) {
  60. currentValue = new String(ch, start, length);
  61. if (currentValue != null && !currentValue.equals(“”)
  62. && !currentValue.equals(”\n”)) {
  63. map.put(currentTag, currentValue);
  64. }
  65. }
  66. currentTag = null;
  67. currentValue = null;
  68. super.characters(ch, start, length);
  69. }
  70. @Override
  71. public void endElement(String uri, String localName, String qName)
  72. throws SAXException {
  73. // TODO Auto-generated method stub
  74. if (qName.equals(nodeName)) {
  75. mListMaps.add(map);
  76. map = null;
  77. }
  78. super.endElement(uri, localName, qName);
  79. }
  80. @Override
  81. public void endDocument() throws SAXException {
  82. // TODO Auto-generated method stub
  83. super.endDocument();
  84. }
  85. }
/*** SAX解析类* @author AndroidLeaf*/
public class CustomHandler extends DefaultHandler {//装载所有解析完成的内容List<HashMap<String, String>> mListMaps = null;//装载解析单个person节点的内容HashMap<String, String> map = null;//节点名称private String nodeName;//当前解析的节点标记private String currentTag;//当前解析的节点值private String currentValue;public ArrayList<Person> getList(){ArrayList<Person> mList = new ArrayList<Person>();if(mListMaps != null && mListMaps.size() > 0){for(int i = 0;i < mListMaps.size();i++){Person mPerson = new Person();HashMap<String, String> mHashMap = mListMaps.get(i);mPerson.setId(Integer.parseInt(mHashMap.get("id")));mPerson.setUserName(mHashMap.get("name"));mPerson.setHeight(Float.parseFloat(mHashMap.get("height")));mPerson.setImageUrl(mHashMap.get("imageurl"));mList.add(mPerson);}}return mList;}public CustomHandler(String nodeName){this.nodeName = nodeName;}@Overridepublic void startDocument() throws SAXException {// TODO Auto-generated method stubsuper.startDocument();mListMaps = new ArrayList<HashMap<String, String>>();}@Overridepublic void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {// TODO Auto-generated method stubif (qName.equals(nodeName)) {map = new HashMap<String, String>();}if (map != null && attributes != null) {for (int i = 0; i < attributes.getLength(); i++) {map.put(attributes.getQName(i), attributes.getValue(i));}}// 当前的解析的节点名称currentTag = qName;}@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {// TODO Auto-generated method stubif (map != null && currentTag != null) {currentValue = new String(ch, start, length);if (currentValue != null && !currentValue.equals("")&& !currentValue.equals("\n")) {map.put(currentTag, currentValue);}}currentTag = null;currentValue = null;super.characters(ch, start, length);}@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {// TODO Auto-generated method stubif (qName.equals(nodeName)) {mListMaps.add(map);map = null;}super.endElement(uri, localName, qName);}@Overridepublic void endDocument() throws SAXException {// TODO Auto-generated method stubsuper.endDocument();}
}

CustomerHandler通过不断接收事件源传递过来的事件,进而执行相关解析工作并调用对应的方法,然后以参数的形式接收解析结果。为了更好的让读者理解CustomerHandler的解析过程,下面有一张展示解析person.xml文件的流程图,如下:

DOM解析XML文件实例

DOM是基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。Android完全支持DOM 解析。利用DOM中的对象,可以对XML文档进行读取、搜索、修改、添加和删除等操作。
      DOM的工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素、属性和注释等,然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档——这就是DOM的工作原理。DOM实现时首先为XML文档的解析定义一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,这样代码就可以使用DOM接口来操作整个树结构。由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。 当然,如果XML文件的内容比较小,采用DOM是可行的。下面罗列了一些使用DOM解析时常用的接口和类,如下:

接口或类名称

接口或类说明

Document

该接口定义分析并创建DOM文档的一系列方法,它是文档树的根,是操作DOM的基础。

Element

该接口继承Node接口,提供了获取、修改XML元素名字和属性的方法

Node

该接口提供处理并获取节点和子节点值的方法

NodeList

提供获得子节点个数和当前节点的方法。这样就可以迭代地访问各个节点

DOMParser

该类是Apache的Xerces中的DOM解析器类,可直接解析XML。

接下来我们学习一下使用DOM解析XML的编程步骤,一般分为6个步骤,如下:

1、创建文档对象工厂实例;
2、调用DocumentBuilderFactory中的newDocumentBuilder()方法创建文档对象构造器;
3、将文件流解析成XML文档对象;
4、使用mDocument文档对象得到文档根节点;
5、根据名称获取根节点中的子节点列表;
6 、获取子节点列表中需要读取的节点信息。

然后,我们按照这6个步骤来完成Demo实例解析person.xml的工作(person.xml的内容上面已经列出),解析的关键代码是在Demo实例工程中的XmlTools类中,具体代码如下:

[java] view plaincopyprint?
  1. /**————–DOM解析XML——————-*/
  2. /**
  3. * @param mInputStream 需要解析的person.xml的文件流对象
  4. * @return mList Person对象集合
  5. */
  6. public static ArrayList<Person> domAnalysis(InputStream mInputStream){
  7. ArrayList<Person> mList = new ArrayList<Person>();
  8. //1、创建文档对象工厂实例
  9. DocumentBuilderFactory mDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
  10. try {
  11. //2、调用DocumentBuilderFactory中的newDocumentBuilder()方法创建文档对象构造器
  12. DocumentBuilder mDocumentBuilder = mDocumentBuilderFactory.newDocumentBuilder();
  13. //3、将文件流解析成XML文档对象
  14. Document mDocument = mDocumentBuilder.parse(mInputStream);
  15. //4、使用mDocument文档对象得到文档根节点
  16. Element mElement = mDocument.getDocumentElement();
  17. //5、根据名称获取根节点中的子节点列表
  18. NodeList mNodeList =  mElement.getElementsByTagName(”person”);
  19. //6 、获取子节点列表中需要读取的节点信息
  20. for(int i = 0 ;i < mNodeList.getLength();i++){
  21. Person mPerson = new Person();
  22. Element personElement = (Element) mNodeList.item(i);
  23. //获取person节点中的属性
  24. if(personElement.hasAttributes()){
  25. mPerson.setId(Integer.parseInt(personElement.getAttribute(”id”)));
  26. }
  27. if(personElement.hasChildNodes()){
  28. //获取person节点的子节点列表
  29. NodeList mNodeList2 = personElement.getChildNodes();
  30. //遍历子节点列表并赋值
  31. for(int j = 0;j < mNodeList2.getLength();j++){
  32. Node mNodeChild = mNodeList2.item(j);
  33. if(mNodeChild.getNodeType() == Node.ELEMENT_NODE){
  34. if(“name”.equals(mNodeChild.getNodeName())){
  35. mPerson.setUserName(mNodeChild.getFirstChild().getNodeValue());
  36. }else if(“height”.equals(mNodeChild.getNodeName())){
  37. mPerson.setHeight(Float.parseFloat(mNodeChild.getFirstChild().getNodeValue()));
  38. }else if(“imageurl”.equals(mNodeChild.getNodeName())){
  39. mPerson.setImageUrl(mNodeChild.getFirstChild().getNodeValue());
  40. }
  41. }
  42. }
  43. }
  44. mList.add(mPerson);
  45. }
  46. } catch (ParserConfigurationException e) {
  47. // TODO Auto-generated catch block
  48. e.printStackTrace();
  49. } catch (SAXException e) {
  50. // TODO Auto-generated catch block
  51. e.printStackTrace();
  52. } catch (IOException e) {
  53. // TODO Auto-generated catch block
  54. e.printStackTrace();
  55. }
  56. return mList;
  57. }
/**--------------DOM解析XML-------------------*//*** @param mInputStream 需要解析的person.xml的文件流对象* @return mList Person对象集合*/public static ArrayList<Person> domAnalysis(InputStream mInputStream){ArrayList<Person> mList = new ArrayList<Person>();//1、创建文档对象工厂实例DocumentBuilderFactory mDocumentBuilderFactory = DocumentBuilderFactory.newInstance();try {//2、调用DocumentBuilderFactory中的newDocumentBuilder()方法创建文档对象构造器DocumentBuilder mDocumentBuilder = mDocumentBuilderFactory.newDocumentBuilder();//3、将文件流解析成XML文档对象Document mDocument = mDocumentBuilder.parse(mInputStream);//4、使用mDocument文档对象得到文档根节点Element mElement = mDocument.getDocumentElement();//5、根据名称获取根节点中的子节点列表NodeList mNodeList =  mElement.getElementsByTagName("person");//6 、获取子节点列表中需要读取的节点信息for(int i = 0 ;i < mNodeList.getLength();i++){Person mPerson = new Person();Element personElement = (Element) mNodeList.item(i);//获取person节点中的属性if(personElement.hasAttributes()){mPerson.setId(Integer.parseInt(personElement.getAttribute("id")));}if(personElement.hasChildNodes()){//获取person节点的子节点列表NodeList mNodeList2 = personElement.getChildNodes();//遍历子节点列表并赋值for(int j = 0;j < mNodeList2.getLength();j++){Node mNodeChild = mNodeList2.item(j);if(mNodeChild.getNodeType() == Node.ELEMENT_NODE){if("name".equals(mNodeChild.getNodeName())){mPerson.setUserName(mNodeChild.getFirstChild().getNodeValue());}else if("height".equals(mNodeChild.getNodeName())){mPerson.setHeight(Float.parseFloat(mNodeChild.getFirstChild().getNodeValue()));}else if("imageurl".equals(mNodeChild.getNodeName())){mPerson.setImageUrl(mNodeChild.getFirstChild().getNodeValue());}}}}mList.add(mPerson);}} catch (ParserConfigurationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SAXException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return mList;}

PULL解析XML文件实例

PULL的解析方式与SAX解析类似,都是基于事件的模式。不同的是,在PULL解析过程中返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。PULL 的工作原理:XML pull提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据。当解释到一个文档结束时,自动生成EndDocument事件。下面罗列了一些使用PULL解析时常用的接口、类和方法:

接口和类名称

接口和类说明

XmlPullParser

XML Pull解析接口,该接口定义了解析功能

XmlSerializer

它是一个接口,定义了XML信息集的序列

XmlPullParserFactory

XML PULL解析工厂类,用于创建XML Pull解析器

XmlPullParserException

抛出单一的XML pull解析器相关的错误

方法名

方法说明

getEventType()

该方法用于获取当前解析到的事件类型

nextText()

提取当前节点元素的字符数据

next()

获取下一个节点元素的类型

getName()

获取当前节点元素的名称

getAttributeCount()

获取当前节点属性的数量

XmlPullParser.START_DOCUMENT

文档开始解析类型

XmlPullParser.END_DOCUMENT

文档结束解析类型

XmlPullParser.START_TAG

节点开始解析类型

XmlPullParser.END_TAG

节点结束解析类型

XmlPullParser.TEXT

文本解析类型

接下来我们将学习使用PULL解析XML的编程步骤,一般分为5个步骤,如下:
1、获取PULL解析工厂实例对象;
2、使用XmlPullParserFactory的newPullParser()方法实例化PULL解析实例对象;
3、设置需解析的XML文件流和字符编码;
4、获取事件解析类型;
5、循环遍历解析,当文档解析结束时结束循环;
然后,我们按照这5个步骤来完成Demo实例解析person.xml的工作(person.xml的内容上面已经列出),解析的关键代码是在Demo实例工程中的XmlTools类中,具体代码如下:
[java] view plaincopyprint?
  1. /**————–PULL解析XML——————-*/
  2. /**
  3. * @param mInputStream 需要解析的person.xml的文件流对象
  4. * @param encode 设置字符编码
  5. * @return mList Person对象集合
  6. */
  7. public static ArrayList<Person> PullAnalysis(InputStream mInputStream,String encode){
  8. ArrayList<Person> mList = null;
  9. Person mPerson = null;
  10. try {
  11. //1、获取PULL解析工厂实例对象
  12. XmlPullParserFactory mXmlPullParserFactory = XmlPullParserFactory.newInstance();
  13. //2、使用XmlPullParserFactory的newPullParser()方法实例化PULL解析实例对象
  14. XmlPullParser mXmlPullParser = mXmlPullParserFactory.newPullParser();
  15. //3、设置需解析的XML文件流和字符编码
  16. mXmlPullParser.setInput(mInputStream, encode);
  17. //4、获取事件解析类型
  18. int eventType = mXmlPullParser.getEventType();
  19. //5、循环遍历解析,当文档解析结束时结束循环
  20. while(eventType != XmlPullParser.END_DOCUMENT){
  21. switch (eventType) {
  22. //开始解析文档
  23. case XmlPullParser.START_DOCUMENT:
  24. mList = new ArrayList<Person>();
  25. break;
  26. //开始解析节点
  27. case XmlPullParser.START_TAG:
  28. if(“person”.equals(mXmlPullParser.getName())){
  29. mPerson = new Person();
  30. //获取该节点中的属性的数量
  31. int attributeNumber = mXmlPullParser.getAttributeCount();
  32. if(attributeNumber > 0){
  33. //获取属性值
  34. mPerson.setId(Integer.parseInt(mXmlPullParser.getAttributeValue(0)));
  35. }
  36. }else if(“name”.equals(mXmlPullParser.getName())){
  37. //获取该节点的内容
  38. mPerson.setUserName(mXmlPullParser.nextText());
  39. }else if(“height”.equals(mXmlPullParser.getName())){
  40. mPerson.setHeight(Float.parseFloat(mXmlPullParser.nextText()));
  41. }else if(“imageurl”.equals(mXmlPullParser.getName())){
  42. mPerson.setImageUrl(mXmlPullParser.nextText());
  43. }
  44. break;
  45. //解析节点结束
  46. case XmlPullParser.END_TAG:
  47. if(“person”.equals(mXmlPullParser.getName())){
  48. mList.add(mPerson);
  49. mPerson = null;
  50. }
  51. break;
  52. default:
  53. break;
  54. }
  55. eventType = mXmlPullParser.next();
  56. }
  57. } catch (XmlPullParserException e) {
  58. // TODO Auto-generated catch block
  59. e.printStackTrace();
  60. } catch (IOException e) {
  61. // TODO Auto-generated catch block
  62. e.printStackTrace();
  63. }
  64. return mList;
  65. }
/**--------------PULL解析XML-------------------*//*** @param mInputStream 需要解析的person.xml的文件流对象* @param encode 设置字符编码* @return mList Person对象集合*/public static ArrayList<Person> PullAnalysis(InputStream mInputStream,String encode){ArrayList<Person> mList = null;Person mPerson = null;try {//1、获取PULL解析工厂实例对象XmlPullParserFactory mXmlPullParserFactory = XmlPullParserFactory.newInstance();//2、使用XmlPullParserFactory的newPullParser()方法实例化PULL解析实例对象XmlPullParser mXmlPullParser = mXmlPullParserFactory.newPullParser();//3、设置需解析的XML文件流和字符编码mXmlPullParser.setInput(mInputStream, encode);//4、获取事件解析类型int eventType = mXmlPullParser.getEventType();//5、循环遍历解析,当文档解析结束时结束循环while(eventType != XmlPullParser.END_DOCUMENT){switch (eventType) {//开始解析文档case XmlPullParser.START_DOCUMENT:mList = new ArrayList<Person>();break;//开始解析节点case XmlPullParser.START_TAG:if("person".equals(mXmlPullParser.getName())){mPerson = new Person();//获取该节点中的属性的数量int attributeNumber = mXmlPullParser.getAttributeCount();if(attributeNumber > 0){//获取属性值mPerson.setId(Integer.parseInt(mXmlPullParser.getAttributeValue(0)));}}else if("name".equals(mXmlPullParser.getName())){//获取该节点的内容mPerson.setUserName(mXmlPullParser.nextText());}else if("height".equals(mXmlPullParser.getName())){mPerson.setHeight(Float.parseFloat(mXmlPullParser.nextText()));}else if("imageurl".equals(mXmlPullParser.getName())){mPerson.setImageUrl(mXmlPullParser.nextText());}break;//解析节点结束case XmlPullParser.END_TAG:if("person".equals(mXmlPullParser.getName())){mList.add(mPerson);mPerson = null;}break;default:break;}eventType = mXmlPullParser.next();}} catch (XmlPullParserException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return mList;}

现在我么已经分别使用SAX、DOM和PULL解析器解析person.xml的文件流后,结果返回Person对象的集合,我们的解析工作便完成了,接下来需要做的就是将解析结果以列表的方式展现在客户端界面上。那首先我们先来实现一下从网络服务端获取数据的网络访问代码,在工程中主要包含HttpRequest和MyAsynctask两个类,前者主要功能是执行网络请求,后者是进行异步请求的帮助类。首先看HttpRequest类的代码,如下:
[java] view plaincopyprint?
  1. /**
  2. * 网络访问类
  3. * @author AndroidLeaf
  4. */
  5. public class HttpRequest {
  6. /**
  7. * @param urlStr 请求的Url
  8. * @return InputStream 返回请求的流数据
  9. */
  10. public static InputStream getInputStreamFromNetWork(String urlStr)
  11. {
  12. URL mUrl = null;
  13. HttpURLConnection  mConnection= null;
  14. InputStream mInputStream = null;
  15. try {
  16. mUrl = new URL(urlStr);
  17. mConnection = (HttpURLConnection)mUrl.openConnection();
  18. mConnection.setDoOutput(true);
  19. mConnection.setDoInput(true);
  20. mConnection.setReadTimeout(15 * 1000);
  21. mConnection.setConnectTimeout(15 * 1000);
  22. mConnection.setRequestMethod(”GET”);
  23. int responseCode = mConnection.getResponseCode();
  24. if(responseCode == HttpURLConnection.HTTP_OK){
  25. //获取下载资源的大小
  26. //contentLength = mConnection.getContentLength();
  27. mInputStream = mConnection.getInputStream();
  28. return mInputStream;
  29. }
  30. } catch (IOException e) {
  31. // TODO: handle exception
  32. }
  33. return null;
  34. }
  35. /**
  36. * 得到图片字节流 数组大小
  37. * */
  38. public static byte[] readStream(InputStream mInputStream){
  39. ByteArrayOutputStream outStream = new ByteArrayOutputStream();
  40. byte[] buffer = new byte[2048];
  41. int len = 0;
  42. try {
  43. while((len = mInputStream.read(buffer)) != -1){
  44. outStream.write(buffer, 0, len);
  45. }
  46. } catch (IOException e) {
  47. // TODO Auto-generated catch block
  48. e.printStackTrace();
  49. }finally{
  50. try {
  51. if(outStream != null){
  52. outStream.close();
  53. }
  54. if(mInputStream != null){
  55. mInputStream.close();
  56. }
  57. } catch (IOException e) {
  58. // TODO Auto-generated catch block
  59. e.printStackTrace();
  60. }
  61. }
  62. return outStream.toByteArray();
  63. }
/*** 网络访问类* @author AndroidLeaf*/
public class HttpRequest {/*** @param urlStr 请求的Url* @return InputStream 返回请求的流数据*/public static InputStream getInputStreamFromNetWork(String urlStr){URL mUrl = null;HttpURLConnection  mConnection= null;InputStream mInputStream = null;try {mUrl = new URL(urlStr);mConnection = (HttpURLConnection)mUrl.openConnection();mConnection.setDoOutput(true);mConnection.setDoInput(true);mConnection.setReadTimeout(15 * 1000);mConnection.setConnectTimeout(15 * 1000);mConnection.setRequestMethod("GET");int responseCode = mConnection.getResponseCode();if(responseCode == HttpURLConnection.HTTP_OK){//获取下载资源的大小//contentLength = mConnection.getContentLength();mInputStream = mConnection.getInputStream();return mInputStream;}       } catch (IOException e) {// TODO: handle exception}return null;}/*** 得到图片字节流 数组大小* */public static byte[] readStream(InputStream mInputStream){ ByteArrayOutputStream outStream = new ByteArrayOutputStream();      byte[] buffer = new byte[2048];      int len = 0;      try {while((len = mInputStream.read(buffer)) != -1){      outStream.write(buffer, 0, len);      }} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{try {if(outStream != null){outStream.close();}if(mInputStream != null){mInputStream.close();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}      }      return outStream.toByteArray();      }

接着实现MyAsynctask类的代码,如下:

[java] view plaincopyprint?
  1. /**
  2. * 异步请求工具类
  3. * @author AndroidLeaf
  4. */
  5. public class MyAsynctask extends AsyncTask<Object, Void, Object>  {
  6. private ImageView mImageView;
  7. private ImageCallBack mImageCallBack;
  8. //请求类型,分为XML文件请求和图片下载请求
  9. private int typeId;
  10. //使用的XML解析类型ID
  11. private int requestId;
  12. /**
  13. * 定义一个回调,用于监听网络请求,当请求结束,返回访问结果
  14. */
  15. public HttpDownloadedListener mHttpDownloadedListener;
  16. public interface HttpDownloadedListener{
  17. public void onDownloaded(String result,int requestId);
  18. }
  19. public void setOnHttpDownloadedListener(HttpDownloadedListener mHttpDownloadedListener){
  20. this.mHttpDownloadedListener = mHttpDownloadedListener;
  21. }
  22. public MyAsynctask(ImageView mImageView,ImageCallBack mImageCallBack,int requestId){
  23. this.mImageView = mImageView;
  24. this.mImageCallBack = mImageCallBack;
  25. this.requestId = requestId;
  26. }
  27. @Override
  28. protected void onPreExecute() {
  29. // TODO Auto-generated method stub
  30. super.onPreExecute();
  31. }
  32. @Override
  33. protected Object doInBackground(Object… params) {
  34. // TODO Auto-generated method stub
  35. InputStream mInputStream = HttpRequest.getInputStreamFromNetWork((String)params[0]);
  36. if(mInputStream != null){
  37. switch ((int)params[1]) {
  38. case Constants.TYPE_STR:
  39. typeId = Constants.TYPE_STR;
  40. return WriteIntoFile(mInputStream);
  41. case Constants.TYPE_STREAM:
  42. typeId = Constants.TYPE_STREAM;
  43. return getBitmap(HttpRequest.readStream(mInputStream),
  44. 200, 200);
  45. default:
  46. break;
  47. }
  48. }
  49. return null;
  50. }
  51. @Override
  52. protected void onPostExecute(Object result) {
  53. // TODO Auto-generated method stub
  54. if(result != null){
  55. switch (typeId) {
  56. case Constants.TYPE_STR:
  57. mHttpDownloadedListener.onDownloaded((String)result,requestId);
  58. break;
  59. case Constants.TYPE_STREAM:
  60. mImageCallBack.resultImage(mImageView,(Bitmap)result);
  61. break;
  62. default:
  63. break;
  64. }
  65. typeId = -1;
  66. }
  67. super.onPostExecute(result);
  68. }
  69. public Bitmap getBitmap(byte[] bytes,int width,int height){
  70. //获取屏幕的宽和高
  71. /**
  72. * 为了计算缩放的比例,我们需要获取整个图片的尺寸,而不是图片
  73. * BitmapFactory.Options类中有一个布尔型变量inJustDecodeBounds,将其设置为true
  74. * 这样,我们获取到的就是图片的尺寸,而不用加载图片了。
  75. * 当我们设置这个值的时候,我们接着就可以从BitmapFactory.Options的outWidth和outHeight中获取到值
  76. */
  77. BitmapFactory.Options op = new BitmapFactory.Options();
  78. op.inJustDecodeBounds = true;
  79. Bitmap pic = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
  80. int wRatio = (int) Math.ceil(op.outWidth / (float) width); //计算宽度比例
  81. int hRatio = (int) Math.ceil(op.outHeight / (float) height); //计算高度比例
  82. /**
  83. * 接下来,我们就需要判断是否需要缩放以及到底对宽还是高进行缩放。
  84. * 如果高和宽不是全都超出了屏幕,那么无需缩放。
  85. * 如果高和宽都超出了屏幕大小,则如何选择缩放呢》
  86. * 这需要判断wRatio和hRatio的大小
  87. * 大的一个将被缩放,因为缩放大的时,小的应该自动进行同比率缩放。
  88. * 缩放使用的还是inSampleSize变量
  89. */
  90. if (wRatio > 1 && hRatio > 1) {
  91. if (wRatio > hRatio) {
  92. op.inSampleSize = wRatio;
  93. } else {
  94. op.inSampleSize = hRatio;
  95. }
  96. }
  97. op.inJustDecodeBounds = false; //注意这里,一定要设置为false,因为上面我们将其设置为true来获取图片尺寸了
  98. pic = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
  99. return pic;
  100. }
  101. /**
  102. * 将下载的XML文件流存储到手机指定的SDcard目录下
  103. * @param mInputStream 需要读入的流
  104. * @return String 返回存储的XML文件的路径
  105. */
  106. public String WriteIntoFile(InputStream mInputStream){
  107. if(isSDcard()){
  108. try {
  109. FileOutputStream mOutputStream = new FileOutputStream(new File(getFileName()));
  110. int len = -1;
  111. byte[] bytes = new byte[2048];
  112. try {
  113. while((len = mInputStream.read(bytes)) != -1){
  114. mOutputStream.write(bytes, 0, len);
  115. }
  116. } catch (IOException e) {
  117. // TODO Auto-generated catch block
  118. e.printStackTrace();
  119. }finally{
  120. try {
  121. if(mOutputStream != null){
  122. mOutputStream.close();
  123. }
  124. if(mInputStream != null){
  125. mInputStream.close();
  126. }
  127. } catch (IOException e) {
  128. // TODO Auto-generated catch block
  129. e.printStackTrace();
  130. }
  131. }
  132. } catch (FileNotFoundException e) {
  133. // TODO Auto-generated catch block
  134. e.printStackTrace();
  135. }
  136. return getFileName();
  137. }
  138. return null;
  139. }
  140. /**
  141. * 检测SDcard是否可用
  142. * @return
  143. */
  144. public boolean isSDcard(){
  145. if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
  146. return true;
  147. }else{
  148. return false;
  149. }
  150. }
  151. /**
  152. * 获取需要存储的XML文件的路径
  153. * @return String 路径
  154. */
  155. public String getFileName(){
  156. String path = Environment.getExternalStorageDirectory().getPath() +”/XMLFiles”;
  157. File mFile = new File(path);
  158. if(!mFile.exists()){
  159. mFile.mkdirs();
  160. }
  161. return mFile.getPath() + “/xmlfile.xml”;
  162. }
/*** 异步请求工具类* @author AndroidLeaf*/
public class MyAsynctask extends AsyncTask<Object, Void, Object>  {private ImageView mImageView;private ImageCallBack mImageCallBack;//请求类型,分为XML文件请求和图片下载请求private int typeId;//使用的XML解析类型IDprivate int requestId;/*** 定义一个回调,用于监听网络请求,当请求结束,返回访问结果*/public HttpDownloadedListener mHttpDownloadedListener;public interface HttpDownloadedListener{public void onDownloaded(String result,int requestId);}public void setOnHttpDownloadedListener(HttpDownloadedListener mHttpDownloadedListener){this.mHttpDownloadedListener = mHttpDownloadedListener;}public MyAsynctask(ImageView mImageView,ImageCallBack mImageCallBack,int requestId){this.mImageView = mImageView;this.mImageCallBack = mImageCallBack;this.requestId = requestId;}@Overrideprotected void onPreExecute() {// TODO Auto-generated method stubsuper.onPreExecute();}@Overrideprotected Object doInBackground(Object... params) {// TODO Auto-generated method stubInputStream mInputStream = HttpRequest.getInputStreamFromNetWork((String)params[0]);if(mInputStream != null){switch ((int)params[1]) {case Constants.TYPE_STR:typeId = Constants.TYPE_STR;return WriteIntoFile(mInputStream);case Constants.TYPE_STREAM:typeId = Constants.TYPE_STREAM;return getBitmap(HttpRequest.readStream(mInputStream),200, 200);default:break;}}return null;}@Overrideprotected void onPostExecute(Object result) {// TODO Auto-generated method stubif(result != null){switch (typeId) {case Constants.TYPE_STR:mHttpDownloadedListener.onDownloaded((String)result,requestId);break;case Constants.TYPE_STREAM:mImageCallBack.resultImage(mImageView,(Bitmap)result);break;default:break;}typeId = -1;}super.onPostExecute(result);}public Bitmap getBitmap(byte[] bytes,int width,int height){//获取屏幕的宽和高  /** * 为了计算缩放的比例,我们需要获取整个图片的尺寸,而不是图片 * BitmapFactory.Options类中有一个布尔型变量inJustDecodeBounds,将其设置为true * 这样,我们获取到的就是图片的尺寸,而不用加载图片了。 * 当我们设置这个值的时候,我们接着就可以从BitmapFactory.Options的outWidth和outHeight中获取到值 */  BitmapFactory.Options op = new BitmapFactory.Options();  op.inJustDecodeBounds = true;  Bitmap pic = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);int wRatio = (int) Math.ceil(op.outWidth / (float) width); //计算宽度比例  int hRatio = (int) Math.ceil(op.outHeight / (float) height); //计算高度比例/** * 接下来,我们就需要判断是否需要缩放以及到底对宽还是高进行缩放。 * 如果高和宽不是全都超出了屏幕,那么无需缩放。 * 如果高和宽都超出了屏幕大小,则如何选择缩放呢》 * 这需要判断wRatio和hRatio的大小 * 大的一个将被缩放,因为缩放大的时,小的应该自动进行同比率缩放。 * 缩放使用的还是inSampleSize变量 */  if (wRatio > 1 && hRatio > 1) {  if (wRatio > hRatio) {  op.inSampleSize = wRatio;  } else {  op.inSampleSize = hRatio;  }  }  op.inJustDecodeBounds = false; //注意这里,一定要设置为false,因为上面我们将其设置为true来获取图片尺寸了  pic = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);return pic;}/*** 将下载的XML文件流存储到手机指定的SDcard目录下* @param mInputStream 需要读入的流* @return String 返回存储的XML文件的路径*/public String WriteIntoFile(InputStream mInputStream){if(isSDcard()){try {FileOutputStream mOutputStream = new FileOutputStream(new File(getFileName()));int len = -1;byte[] bytes = new byte[2048];try {while((len = mInputStream.read(bytes)) != -1){mOutputStream.write(bytes, 0, len);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{try {if(mOutputStream != null){mOutputStream.close();}if(mInputStream != null){mInputStream.close();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}return getFileName();}return null;}/*** 检测SDcard是否可用* @return*/public boolean isSDcard(){if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){return true;}else{return false;}}/*** 获取需要存储的XML文件的路径* @return String 路径*/public String getFileName(){String path = Environment.getExternalStorageDirectory().getPath() +"/XMLFiles";File mFile = new File(path);if(!mFile.exists()){mFile.mkdirs();}return mFile.getPath() + "/xmlfile.xml";}

实现完网络请求的功能后,我们就可以从服务端获取到person.xml的文件流,然后再分别用SAX、DOM和PULL解析器将文件流解析(在上面介绍这几种解析器时已经实现了解析的代码,在工程中的XmlTools类中)成对应的Java对象集合,最后将Java对象集合以列表的形式展现在客户端界面上,那接下来我们将实现该功能。在工程中主要包含MainActivity、MyAdapter和ImageCallBack类,首先实现MainActivity的代码,如下:

[java] view plaincopyprint?
  1. public class MainActivity extends ListActivity implements HttpDownloadedListener{
  2. private ProgressDialog mProgressDialog;
  3. //需要解析的节点名称
  4. private String nodeName = “person”;
  5. @Override
  6. protected void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.activity_list);
  9. //初始化数据
  10. initData();
  11. }
  12. public void initData(){
  13. mProgressDialog = new ProgressDialog(this);
  14. mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
  15. mProgressDialog.setTitle(”正在加载中…..”);
  16. mProgressDialog.show();
  17. //首次进入界面是,默认使用SAX解析数据
  18. downloadData(this,Constants.XML_PATH,Constants.REQUEST_PULL_TYPE,null,null,Constants.TYPE_STR);
  19. }
  20. @Override
  21. public boolean onCreateOptionsMenu(Menu menu) {
  22. // TOdO Auto-generated method stub
  23. getMenuInflater().inflate(R.menu.main, menu);
  24. return true;
  25. }
  26. @Override
  27. public boolean onOptionsItemSelected(MenuItem item) {
  28. // TOdO Auto-generated method stub
  29. int requestId = -1;
  30. switch (item.getItemId()) {
  31. case R.id.sax:
  32. requestId = Constants.REQUEST_SAX_TYPE;
  33. break;
  34. case R.id.dom:
  35. requestId = Constants.REQUEST_DOM_TYPE;
  36. break;
  37. case R.id.pull:
  38. requestId = Constants.REQUEST_PULL_TYPE;
  39. break;
  40. default:
  41. break;
  42. }
  43. downloadData(this, Constants.XML_PATH, requestId, null, null, Constants.TYPE_STR);
  44. mProgressDialog.show();
  45. return super.onOptionsItemSelected(item);
  46. }
  47. @Override
  48. public void onDownloaded(String result,int requestId) {
  49. // TODO Auto-generated method stub
  50. FileInputStream mFileInputStream = null;
  51. try {
  52. mFileInputStream = new FileInputStream(new File(result));
  53. } catch (FileNotFoundException e) {
  54. // TODO Auto-generated catch block
  55. e.printStackTrace();
  56. }
  57. ArrayList<Person> mList = null;
  58. switch (requestId) {
  59. case Constants.REQUEST_SAX_TYPE:
  60. mList = XmlTools.saxAnalysis(mFileInputStream,nodeName);
  61. break;
  62. case Constants.REQUEST_DOM_TYPE:
  63. mList = XmlTools.domAnalysis(mFileInputStream);
  64. break;
  65. case Constants.REQUEST_PULL_TYPE:
  66. mList = XmlTools.PullAnalysis(mFileInputStream,”UTF-8”);
  67. break;
  68. default:
  69. break;
  70. }
  71. MyAdapter myAdapter = new MyAdapter(this, mList);
  72. setListAdapter(myAdapter);
  73. if(mProgressDialog.isShowing()){
  74. mProgressDialog.dismiss();
  75. }
  76. }
  77. //执行网络下载代码
  78. public static void downloadData(HttpDownloadedListener mDownloadedListener,String url,int requestId,ImageView mImageView,ImageCallBack mImageCallBack,int typeId){
  79. MyAsynctask mAsynctask = new MyAsynctask(mImageView,mImageCallBack,requestId);
  80. mAsynctask.setOnHttpDownloadedListener(mDownloadedListener);
  81. mAsynctask.execute(url,typeId);
  82. }
  83. }
public class MainActivity extends ListActivity implements HttpDownloadedListener{private ProgressDialog mProgressDialog;//需要解析的节点名称private String nodeName = "person";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_list);//初始化数据initData();}public void initData(){mProgressDialog = new ProgressDialog(this);mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);mProgressDialog.setTitle("正在加载中.....");mProgressDialog.show();//首次进入界面是,默认使用SAX解析数据downloadData(this,Constants.XML_PATH,Constants.REQUEST_PULL_TYPE,null,null,Constants.TYPE_STR);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// TOdO Auto-generated method stubgetMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// TOdO Auto-generated method stubint requestId = -1;switch (item.getItemId()) {case R.id.sax:requestId = Constants.REQUEST_SAX_TYPE;break;case R.id.dom:requestId = Constants.REQUEST_DOM_TYPE;break;case R.id.pull:requestId = Constants.REQUEST_PULL_TYPE;break;default:break;}downloadData(this, Constants.XML_PATH, requestId, null, null, Constants.TYPE_STR);mProgressDialog.show();return super.onOptionsItemSelected(item);}@Overridepublic void onDownloaded(String result,int requestId) {// TODO Auto-generated method stubFileInputStream mFileInputStream = null;try {mFileInputStream = new FileInputStream(new File(result));} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}ArrayList<Person> mList = null;switch (requestId) {case Constants.REQUEST_SAX_TYPE:mList = XmlTools.saxAnalysis(mFileInputStream,nodeName);break;case Constants.REQUEST_DOM_TYPE:mList = XmlTools.domAnalysis(mFileInputStream);break;case Constants.REQUEST_PULL_TYPE:mList = XmlTools.PullAnalysis(mFileInputStream,"UTF-8");break;default:break;}MyAdapter myAdapter = new MyAdapter(this, mList);setListAdapter(myAdapter);if(mProgressDialog.isShowing()){mProgressDialog.dismiss();}}//执行网络下载代码public static void downloadData(HttpDownloadedListener mDownloadedListener,String url,int requestId,ImageView mImageView,ImageCallBack mImageCallBack,int typeId){MyAsynctask mAsynctask = new MyAsynctask(mImageView,mImageCallBack,requestId);mAsynctask.setOnHttpDownloadedListener(mDownloadedListener);mAsynctask.execute(url,typeId);}}

然后再实现界面的适配器类–MyAdapter,具体代码如下:

[java] view plaincopyprint?
  1. /**
  2. * 数据界面展示的适配器类
  3. * @author AndroidLeaf
  4. */
  5. public class MyAdapter extends BaseAdapter {
  6. private Context mContext;
  7. private ArrayList<Person> mList;
  8. private Bitmap[] mBitmaps;
  9. public MyAdapter(Context mContext,ArrayList<Person> mList){
  10. this.mContext = mContext;
  11. this.mList = mList;
  12. mBitmaps = new Bitmap[mList.size()];
  13. }
  14. @Override
  15. public int getCount() {
  16. // TODO Auto-generated method stub
  17. return mList.size();
  18. }
  19. @Override
  20. public Object getItem(int position) {
  21. // TODO Auto-generated method stub
  22. return mList.get(position);
  23. }
  24. @Override
  25. public long getItemId(int position) {
  26. // TODO Auto-generated method stub
  27. return position;
  28. }
  29. @Override
  30. public View getView(int position, View convertView, ViewGroup parent) {
  31. // TODO Auto-generated method stub
  32. ViewHolder mHolder;
  33. Person mPerson = mList.get(position);
  34. if(convertView == null){
  35. convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, null);
  36. mHolder = new ViewHolder();
  37. mHolder.mTextView_id = (TextView)convertView.findViewById(R.id.item_id);
  38. mHolder.mTextView_name = (TextView)convertView.findViewById(R.id.item_name);
  39. mHolder.mTextView_height = (TextView)convertView.findViewById(R.id.item_height);
  40. mHolder.mImageView_image = (ImageView)convertView.findViewById(R.id.item_image);
  41. //为Imageview设置TAG,作为每一个ImageView的唯一标识
  42. mHolder.mImageView_image.setTag(mPerson.getImageUrl());
  43. convertView.setTag(mHolder);
  44. }else{
  45. mHolder = (ViewHolder)convertView.getTag();
  46. }
  47. mHolder.mTextView_id.setText(String.valueOf(mPerson.getId()));
  48. mHolder.mTextView_name.setText(mPerson.getUserName());
  49. mHolder.mTextView_height.setText(String.valueOf(mPerson.getHeight()));
  50. /**
  51. * 解决异步加载过程中Listview列表中图片显示错位问题
  52. */
  53. //判断当前位置的ImageView和是否为上次执行加载操作的ImageView,若false则重置上次加载的那个Imageview中的图片资源
  54. if(!mPerson.getImageUrl().equals(String.valueOf(mHolder.mImageView_image.getTag()))){
  55. mHolder.mImageView_image.setImageResource(R.drawable.ic_launcher);
  56. }
  57. //重新为ImageView实例设置TAG
  58. mHolder.mImageView_image.setTag(mPerson.getImageUrl());
  59. if(mBitmaps[position] == null){
  60. //执行异步加载图片操作
  61. MainActivity.downloadData((HttpDownloadedListener)mContext, Constants.BASE_PATH + mPerson.getImageUrl(), -1,
  62. mHolder.mImageView_image, new MyImageCallBack(position,mPerson.getImageUrl()), Constants.TYPE_STREAM);
  63. }else{
  64. mHolder.mImageView_image.setImageBitmap(mBitmaps[position]);
  65. }
  66. return convertView;
  67. }
  68. class ViewHolder{
  69. TextView mTextView_id;
  70. TextView mTextView_name;
  71. TextView mTextView_height;
  72. ImageView mImageView_image;
  73. }
  74. class MyImageCallBack implements ImageCallBack{
  75. int index = -1;
  76. String imageUrl = null;
  77. public MyImageCallBack(int index,String imageUrl){
  78. this.index = index;
  79. this.imageUrl = imageUrl;
  80. }
  81. @Override
  82. public void resultImage(ImageView mImageView, Bitmap mBitmap) {
  83. // TODO Auto-generated method stub
  84. //判断当前显示的ImageView的URL是否与需要下载的图片ImageView的URL相同
  85. if(imageUrl.equals(String.valueOf(mImageView.getTag()))){
  86. mBitmaps[index] = mBitmap;
  87. mImageView.setImageBitmap(mBitmap);
  88. }
  89. }
  90. }
  91. }
/*** 数据界面展示的适配器类* @author AndroidLeaf*/
public class MyAdapter extends BaseAdapter {private Context mContext;private ArrayList<Person> mList;private Bitmap[] mBitmaps;public MyAdapter(Context mContext,ArrayList<Person> mList){this.mContext = mContext;this.mList = mList;mBitmaps = new Bitmap[mList.size()];}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn mList.size();}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn mList.get(position);}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubViewHolder mHolder;Person mPerson = mList.get(position);if(convertView == null){convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, null);mHolder = new ViewHolder();mHolder.mTextView_id = (TextView)convertView.findViewById(R.id.item_id);mHolder.mTextView_name = (TextView)convertView.findViewById(R.id.item_name);mHolder.mTextView_height = (TextView)convertView.findViewById(R.id.item_height);mHolder.mImageView_image = (ImageView)convertView.findViewById(R.id.item_image);//为Imageview设置TAG,作为每一个ImageView的唯一标识mHolder.mImageView_image.setTag(mPerson.getImageUrl());convertView.setTag(mHolder);}else{mHolder = (ViewHolder)convertView.getTag();}mHolder.mTextView_id.setText(String.valueOf(mPerson.getId()));mHolder.mTextView_name.setText(mPerson.getUserName());mHolder.mTextView_height.setText(String.valueOf(mPerson.getHeight()));/*** 解决异步加载过程中Listview列表中图片显示错位问题*///判断当前位置的ImageView和是否为上次执行加载操作的ImageView,若false则重置上次加载的那个Imageview中的图片资源if(!mPerson.getImageUrl().equals(String.valueOf(mHolder.mImageView_image.getTag()))){mHolder.mImageView_image.setImageResource(R.drawable.ic_launcher);}//重新为ImageView实例设置TAGmHolder.mImageView_image.setTag(mPerson.getImageUrl());if(mBitmaps[position] == null){//执行异步加载图片操作MainActivity.downloadData((HttpDownloadedListener)mContext, Constants.BASE_PATH + mPerson.getImageUrl(), -1, mHolder.mImageView_image, new MyImageCallBack(position,mPerson.getImageUrl()), Constants.TYPE_STREAM);}else{mHolder.mImageView_image.setImageBitmap(mBitmaps[position]);}return convertView;}class ViewHolder{TextView mTextView_id;TextView mTextView_name;TextView mTextView_height;ImageView mImageView_image;}class MyImageCallBack implements ImageCallBack{int index = -1;String imageUrl = null;public MyImageCallBack(int index,String imageUrl){this.index = index;this.imageUrl = imageUrl;}@Overridepublic void resultImage(ImageView mImageView, Bitmap mBitmap) {// TODO Auto-generated method stub//判断当前显示的ImageView的URL是否与需要下载的图片ImageView的URL相同if(imageUrl.equals(String.valueOf(mImageView.getTag()))){mBitmaps[index] = mBitmap;mImageView.setImageBitmap(mBitmap);}}}
}

观察上面的代码,在实现适配器类时,由于我们需要异步下载图片,因此在图片绑定和显示时由于列表项焦点的不断变换和图片数据加载的延迟会导致ListView中的图片显示错位的问题,为了解决该问题,我们采取对ImageView设置TAG来解决了图片错位问题,那要明白其中的原理,就必须对Listview加载item view列表项的实现机制比较清楚,由于该问题不是本文的重点,因此在此不便细讲,有兴趣的读者可以学习本博客的另一篇文章《Android异步加载数据时ListView中图片错位问题解析》,希望对你有所帮助。在实现图片异步加载时,程序中还使用到了一个非常有用的接口–ImageCallBack,该接口主要作用是将异步下载的图片设置到对应的Imageview控件中,该接口的具体代码如下:

[java] view plaincopyprint?
  1. public interface ImageCallBack {
  2. public void resultImage(ImageView mImageView,Bitmap mBitmap);
  3. }
public interface ImageCallBack {public void resultImage(ImageView mImageView,Bitmap mBitmap);
}

当然,还有常量Constants类和Entity对象Person类。Constants类的具体的代码:

[java] view plaincopyprint?
  1. /**
  2. * 网络请求的Url地址及一些常量
  3. * @author AndroidLeaf
  4. */
  5. public class Constants {
  6. //基路径
  7. public static final String BASE_PATH = “http://10.0.2.2:8080/09_Android_XMLServer_Blog/”;
  8. //person.xml网络请求路径
  9. public static final String XML_PATH = BASE_PATH + “xmlfile/person.xml”;
  10. //使用SAX解析的标签类型
  11. public static final int REQUEST_SAX_TYPE = 0;
  12. //使用DOM解析的标签类型
  13. public static final int REQUEST_DOM_TYPE = 1;
  14. //使用PULL解析的标签类型
  15. public static final int REQUEST_PULL_TYPE = 2;
  16. //请求person.xml文件标签
  17. public static final int TYPE_STR = 1;
  18. //请求图片文件标签
  19. public static final int TYPE_STREAM = 2;
  20. }
/*** 网络请求的Url地址及一些常量* @author AndroidLeaf*/
public class Constants {//基路径public static final String BASE_PATH = "http://10.0.2.2:8080/09_Android_XMLServer_Blog/";//person.xml网络请求路径public static final String XML_PATH = BASE_PATH + "xmlfile/person.xml";//使用SAX解析的标签类型public static final int REQUEST_SAX_TYPE = 0;//使用DOM解析的标签类型public static final int REQUEST_DOM_TYPE = 1;//使用PULL解析的标签类型public static final int REQUEST_PULL_TYPE = 2;//请求person.xml文件标签public static final int TYPE_STR = 1;//请求图片文件标签public static final int TYPE_STREAM = 2;}

Person类的代码如下:

[java] view plaincopyprint?
  1. public class Person {
  2. private int id;
  3. private String userName;
  4. private float height;
  5. private String imageUrl;
  6. public int getId() {
  7. return id;
  8. }
  9. public void setId(int id) {
  10. this.id = id;
  11. }
  12. public String getUserName() {
  13. return userName;
  14. }
  15. public void setUserName(String userName) {
  16. this.userName = userName;
  17. }
  18. public float getHeight() {
  19. return height;
  20. }
  21. public void setHeight(float height) {
  22. this.height = height;
  23. }
  24. public String getImageUrl() {
  25. return imageUrl;
  26. }
  27. public void setImageUrl(String imageUrl) {
  28. this.imageUrl = imageUrl;
  29. }
  30. @Override
  31. public String toString() {
  32. return “Person [id=” + id + “, userName=” + userName + “, height=”
  33. + height + ”, imageUrl=” + imageUrl + “]”;
  34. }
  35. }
public class Person {private int id;private String userName;private float height;private String imageUrl;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public float getHeight() {return height;}public void setHeight(float height) {this.height = height;}public String getImageUrl() {return imageUrl;}public void setImageUrl(String imageUrl) {this.imageUrl = imageUrl;}@Overridepublic String toString() {return "Person [id=" + id + ", userName=" + userName + ", height="+ height + ", imageUrl=" + imageUrl + "]";}
}

全部的编码都已经完成,最后我们再Android模拟器上运行我们的Demo实例工程,运行及操作的效果图如下:

SAX、DOM和PULL解析器的比较

SAX解析器的特点:SAX解析器解析速度快、高效,占用内存少。但它的缺点是编码实现比其它解析方式更复杂,对于只需解析较少数量的XML文件时,使用SAX解析显得实现代码比较臃肿。
DOM解析器的特点:由于DOM在内存中是以树形结构存放的,那虽然检索和更新效率比较高,但对于使用DOM来解析较大数据的XML文件,将会消耗很大内存资源,这对于内存资源比较有限的手机设备来讲,是不太适合的。
PULL解析器的特点:PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。
根据上面介绍的这些解析器的特点我们可在不同的开发情况下选择不同的解析方式,比如说,当XML文件数据较小时,可以选择DOM解析,因为它将XML数据以树形结构存放在内存中,在占用不多的内存资源情况下检索和更新效率比较高,当XML文件数据较大时,可以选择SAX和PULL解析,因为它们不需要将所有的XML文件都加载到内存中,这样对有限的Android内存更有效。SAX和PULL解析的不同之处是,PULL解析并不像SAX解析那样监听元素的结束,而是在开始处完成了大部分处理。这有利于提早读取XML文件,可以极大的减少解析时间,这种优化对于连接速度较漫的移动设备而言尤为重要。对于XML文档数据较大但只需要文档的一部分时,XML PULL解析器则是更为有效的方法。
总结:本文学习了在Android开发中解析XML文件的几种常用解析方式,这几种解析方式各有优缺点,我们应根据不同的开发需求选择合适的解析方式。最后总结一下在Android解析XML所需掌握的主要知识点:(1)XML的特点以及结构组成形式,掌握如何编写XML文件;(2)了解SAX、PULL和DOM解析器的特点,并掌握在Android中使用这三种解析方式的使用;(3)比较三种解析器的特点,学会在不同情况下选择合适的解析方式。
源代码下载,请戳下面:
  • GITHUB下载
  • CSDN下载

Android中XML数据解析相关推荐

  1. Android中Json数据解析

    Android学习系列(20)--App数据格式之解析Json (很基本基础的入门,对json的基础讲的很好) http://my.eoe.cn/874311/archive/1936.html An ...

  2. Android网络之数据解析----SAX方式解析XML数据

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  3. delphi读取xml中的内容property name传递参数_python3 Json和XML数据解析

    一.Json数据解析 Python3 中可以使用 json 模块来对 JSON 数据进行编解码,它包含了两个函数: json.dumps(): 对数据进行编码. json.loads(): 对数据进行 ...

  4. android libbfaac.so,Android中Json数据读取与创建

    一:  Json的特性和在数据交互中的地位就不用说了,直接看案例. 首先在android studio中创建assets文件目录,用于存放Json数据文件,android studio 1.3 默认项 ...

  5. Android JSONObject – Android中的JSON解析

    Android JSONObject is used for JSON parsing in android apps. In this tutorial we'll discuss and impl ...

  6. android Java开发设计模式及在android中的应用解析

    android Java开发设计模式及在android中的应用解析 什么是设计模式: 可以用一句话概括设计模式---设计模式是一种利用OOP的封闭.继承和多态三大特性,同时在遵循单一职责原则.开闭原则 ...

  7. iOS - XML 数据解析

    前言 @interface NSXMLParser : NSObjectpublic class NSXMLParser : NSObject 1.XML 数据 XML(Extensible Mark ...

  8. android修改xml变量值,Android中XML的基本操作(增、删、改、查)

    Android中XML的一些操作 解析类: // 构造方法 public XMLParser() { } /** * 从URL获取XML使HTTP请求 * * @param url * string ...

  9. XML数据解析-SAX和DOM

    XML:Extensible Markup language(可扩展标记语言),主流数据格式之一,可以用来存储和传输数据. StudentInfo_XML文件: <Students> &l ...

最新文章

  1. 大脑是怎样和身体交流的?
  2. 新的MOVE结构,和在项目中实际的感受
  3. Java 数字用二进制表示,以及原码,反码,补码、负数的二进制表示
  4. python数据分析numpy_Python数据分析之numpy学习
  5. 优化Linux系统中的服务
  6. 脚本其实很简单-windows配置核查程序(1)
  7. Hadoop YARN:调度性能优化实践【转】
  8. centos内核编译与其签名机制
  9. Java 高并发下的实践
  10. 【转】3.1SharePoint服务器端对象模型 之 访问文件和文件夹(Part 1)
  11. 大数据的搜索引擎——Elasticsearch
  12. linux centos java 应用服务器配置
  13. GNSS静态测量数据采集与内业解算
  14. 常用Gis通用符号库大全
  15. 【重要更新】TX Text Control ActiveX X16发布 | 附下载
  16. 赛式方法论(上):为什么你的游戏做不完、做得烂?
  17. 计算机金融专业亚洲大学排行,金融类专业大学排名
  18. java 汉字转拼音工具_java汉字转拼音工具类
  19. ERP现状及未来发展趋势分析?
  20. 论文阅读-Training a Helpful and Harmless Assistant withReinforcement Learning from Human Feedback

热门文章

  1. 高等组合学笔记(一)集合的计数,映射与集合的排列组合
  2. pycharm与python连接_pycharm2017实现python3.6与mysql的连接
  3. CSS3边框图片、边框阴影、文本阴影
  4. 浮动和清浮动,内外边距和margin的坑
  5. vue v-for循环动态获取_快速、简洁讲明Vue中vfor循环key的作用
  6. 帆软报表调用python脚本_帆软报表(finereport)实现自动滚屏效果
  7. sendfile实现文件服务器,sendfile
  8. python模块request怎么安装_安装 request模块
  9. python导入自己写的模块_Python:包、模块和导入
  10. 2008版计算机基础,计算机应用基础2008版各章课后习题解析