android学习日记23--Android XML解析
一、简述
XML语言是跨平台,JAVA对XML语言支持得比较好,android系统的应用层平台是JAVA做的,所以用XML。
XML解析比较简单。XML解析就是将获取到的数据分离出来,基本的网络数据传输,需要使用XML
比如天气预报,从网上获取的是XML文件,通过XML解析可以把天气状态读出来
例:
1 <forecast_date data="2009-07-31" /> 2 <condition data="晴" /> 3 <humidity data="湿度: 65%" />(XML文件不全)
可得到 2009-07-31 晴 湿度:65%
还有一作用是保存你的数据,比如做个旅游网站,你需要把全国各个省、城市名称写到XML文件进行保存,在程序中通过解析读取调用。
Android 平台上可用的XML解析有三种
1、Simple API for XML(SAX)
2、Document Object Model(DOM)
3、Android附带的pull解析器
二、实例
分别用三种方法解析如下persons.xml文件(文件放在assert目录下)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <persons> 3 <person id="23"> 4 <name>liming</name> 5 <age>30</age> 6 </person> 7 <person id="20"> 8 <name>dehua</name> 9 <age>25</age> 10 </person> 11 </persons>
还需定义个javabean 用于存放解析出来的内容
1 package com.example.xml; 2 3 public class Person { 4 private Integer id; 5 private String name; 6 private Short age; 7 8 public Integer getId() { 9 return id; 10 } 11 12 public void setId(Integer id) { 13 this.id = id; 14 } 15 16 public String getName() { 17 return name; 18 } 19 20 public void setName(String name) { 21 this.name = name; 22 } 23 24 public Short getAge() { 25 return age; 26 } 27 28 public void setAge(Short age) { 29 this.age = age; 30 } 31 32 // @Override 33 // public String toString() { 34 // return "id:" + id + ", name:" + name + ", age:" + age; 35 // } 36 }
1、Simple API for XML(SAX)
SAX是一个解析速度快并且占用内存少的XML解析器,很适合用于Android等移动设备。
SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,
SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。所谓事件,其实就是一些回调(callback)方法,
这些方法(事件)定义在ContentHandler接口。
直接看代码:
1 public class XMLContentHandler extends DefaultHandler { 2 private List<Person> persons = null; 3 private Person currentPerson; 4 private String tagName = null;// 当前解析的元素标签 5 private static final String TAG = "XMLContentHandler"; 6 7 public List<Person> getPersons() { 8 return persons; 9 } 10 11 /* 12 * 接收文档的开始的通知。 13 */ 14 15 @Override 16 public void startDocument() throws SAXException { 17 persons = new ArrayList<Person>(); 18 Log.i(TAG, "startDocument"); 19 } 20 21 /* 22 * 结束文档的开始的通知。 23 */ 24 25 @Override 26 public void endDocument() throws SAXException { 27 super.endDocument(); 28 Log.i(TAG, "endDocument"); 29 } 30 31 /* 32 * 接收字符数据的通知。 33 */ 34 35 @Override 36 public void characters(char[] ch, int start, int length) 37 throws SAXException { 38 if (tagName != null) { 39 String data = new String(ch, start, length); 40 if (tagName.equals("name")) { 41 this.currentPerson.setName(data); 42 } else if (tagName.equals("age")) { 43 this.currentPerson.setAge(Short.parseShort(data)); 44 } 45 } 46 Log.i(TAG, "characters("+ch.toString()+","+start+","+length+")"); 47 48 } 49 50 /* 51 * 52 * 接收元素开始的通知。 53 * 参数意义如下: 54 * namespaceURI:元素的命名空间 55 * localName :元素的本地名称(不带前缀) 56 * qName :元素的限定名(带前缀) 57 * atts :元素的属性集合 58 */ 59 60 @Override 61 public void startElement(String namespaceURI, String localName, 62 String qName, Attributes atts) throws SAXException { 63 64 if (localName.equals("person")) { 65 currentPerson = new Person(); 66 currentPerson.setId(Integer.parseInt(atts.getValue("id"))); 67 } 68 69 this.tagName = localName; 70 Log.i(TAG, "startElement("+namespaceURI+","+localName+","+qName+atts+")"); 71 72 } 73 74 /* 75 * 接收文档的结尾的通知。 76 * 参数意义如下: 77 * uri :元素的命名空间 78 * localName :元素的本地名称(不带前缀) 79 * name :元素的限定名(带前缀) 80 */ 81 @Override 82 public void endElement(String uri, String localName, String name) 83 throws SAXException { 84 85 if (localName.equals("person")) { 86 persons.add(currentPerson); 87 currentPerson = null; 88 } 89 90 this.tagName = null; 91 Log.i(TAG, "endElement("+uri+","+localName+","+name+")"); 92 93 } 94 }
2、Document Object Model(DOM)
DOM解析XML文件时,会将XML文件的所有内容读取到内存中,然后允许您使用DOM API遍历XML树、检索所需的数据。
使用DOM操作XML的代码看起来比较直观,并且,在某些方面比基于SAX的实现更加简单。但是,因为DOM需要将XML文件的所有内容读取到内存中,
所以内存的消耗比较大,特别对于运行Android的移动设备来说,因为设备的资源比较宝贵,所以建议还是采用SAX来解析XML文件,
当然,如果XML文件的内容比较小采用DOM是可行的。
1 public class DomParseXML { 2 3 public List<Person> readXML(InputStream inStream) { 4 5 List<Person> persons = new ArrayList<Person>(); 6 7 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();// 获取实例 8 9 try { 10 11 DocumentBuilder builder = factory.newDocumentBuilder(); 12 Document dom = builder.parse(inStream); 13 Element root = dom.getDocumentElement(); 14 NodeList items = root.getElementsByTagName("person");// 查找所有person节点 15 16 for (int i = 0; i < items.getLength(); i++) { 17 18 Person person = new Person(); 19 20 // 得到第一个person节点 21 Element personNode = (Element) items.item(i); 22 23 // 获取person节点的id属性值 24 person.setId(new Integer(personNode.getAttribute("id"))); 25 26 // 获取person节点下的所有子节点(标签之间的空白节点和name/age元素) 27 NodeList childsNodes = personNode.getChildNodes(); 28 29 for (int j = 0; j < childsNodes.getLength(); j++) { 30 31 Node node = (Node) childsNodes.item(j); // 判断是否为元素类型 32 if (node.getNodeType() == Node.ELEMENT_NODE) { 33 Element childNode = (Element) node; 34 35 // 判断是否name元素 36 if ("name".equals(childNode.getNodeName())) { 37 38 // 获取name元素下Text节点,然后从Text节点获取数据 39 person.setName(childNode.getFirstChild() 40 .getNodeValue()); 41 42 } else if ("age".equals(childNode.getNodeName())) { 43 person.setAge(new Short(childNode.getFirstChild() 44 .getNodeValue())); 45 46 } 47 } 48 } 49 persons.add(person); 50 } 51 inStream.close(); 52 } catch (Exception e) { 53 e.printStackTrace(); 54 } 55 56 return persons; 57 58 } 59 }
3、Android附带的pull解析器
Pull解析和Sax解析很相似,都是轻量级的解析,在Android的内核中已经嵌入了Pull,所以我们不需要再添加第三方jar包来支持Pull。
Pull解析和Sax解析不一样的地方有(1)pull读取xml文件后触发相应的事件调用方法返回的是数字(2)pull可以在程序中控制想解析到哪里就可以停止解析。
1 public class PullParseXML { 2 3 public List<Person> readXML(InputStream inStream) throws XmlPullParserException, IOException{ 4 5 List<Person> persons = null; 6 Person person = null; 7 XmlPullParser parser = Xml.newPullParser(); 8 parser.setInput(inStream, "UTF-8"); 9 10 int event = parser.getEventType();//产生第一个事件 11 while(event!=XmlPullParser.END_DOCUMENT){ 12 switch(event){ 13 case XmlPullParser.START_DOCUMENT://判断当前事件是否是文档开始事件 14 persons = new ArrayList<Person>();//初始化Persons集合 15 break; 16 case XmlPullParser.START_TAG://判断当前事件是否是标签元素开始事件 17 if("person".equals(parser.getName())){//判断开始标签元素是否是person 18 person = new Person(); 19 person.setId(Integer.parseInt(parser.getAttributeValue(0)));//得到Person标签的属性值,并设置Person的id 20 } 21 if(person!=null){ 22 if("name".equals(parser.getName())){//判断开始标签元素是否是name 23 person.setName(parser.nextText()); 24 }else if("age".equals(parser.getName())){//判断开始标签元素是否是price 25 person.setAge(Short.parseShort(parser.nextText())); 26 } 27 } 28 break; 29 case XmlPullParser.END_TAG://判断当前事件是否是标签元素结束事件 30 if("person".equals(parser.getName())){//判断结束标签元素是否是Person 31 persons.add(person);//将person添加到persons集合 32 person = null; 33 } 34 break; 35 } 36 event = parser.next();//进入下一个元素并触发相应事件 37 }//end while 38 return persons; 39 40 } 41 }
运行界面:
绑定按钮触发的事件代码:
1 @Override 2 protected void onCreate(Bundle savedInstanceState) { 3 super.onCreate(savedInstanceState); 4 setContentView(R.layout.activity_main); 5 textView = (TextView)findViewById(R.id.textView); 6 sax_prase = (Button)findViewById(R.id.sax_prase); 7 dom_parse = (Button)findViewById(R.id.dom_parse); 8 pull_parse = (Button)findViewById(R.id.pull_parse); 9 10 11 try { 12 inStream = getAssets().open("persons.xml"); 13 } catch (IOException e) { 14 // TODO Auto-generated catch block 15 e.printStackTrace(); 16 } 17 18 //绑定按钮监听器 19 sax_prase.setOnClickListener(new OnClickListener() { 20 @Override 21 public void onClick(View v) { 22 persons = SaxParseXML(inStream); 23 for (Person person : persons) { 24 Log.i(TAG, person.getId()+":"+person.getName()+":"+person.getAge()); 25 } 26 } 27 }); 28 //绑定按钮监听器 29 dom_parse.setOnClickListener(new OnClickListener() { 30 @Override 31 public void onClick(View v) { 32 33 DomParseXML domParseXML = new DomParseXML(); 34 persons = domParseXML.readXML(inStream); 35 for (Person person : persons) { 36 Log.i(TAG, person.getId()+":"+person.getName()+":"+person.getAge()); 37 } 38 } 39 }); 40 pull_parse.setOnClickListener(new OnClickListener() { 41 @Override 42 public void onClick(View v) { 43 44 PullParseXML pullParseXML = new PullParseXML(); 45 try { 46 persons = pullParseXML.readXML(inStream); 47 } catch (XmlPullParserException e) { 48 // TODO Auto-generated catch block 49 e.printStackTrace(); 50 } catch (IOException e) { 51 // TODO Auto-generated catch block 52 e.printStackTrace(); 53 } 54 for (Person person : persons) { 55 Log.i(TAG, person.getId()+":"+person.getName()+":"+person.getAge()); 56 } 57 58 } 59 }); 60 } 61 62 private static List<Person> SaxParseXML(InputStream inStream) { 63 // TODO Auto-generated method stub 64 try { 65 SAXParserFactory spf = SAXParserFactory.newInstance(); 66 SAXParser saxParser = spf.newSAXParser(); // 创建解析器 67 68 // 设置解析器的相关特性,http://xml.org/sax/features/namespaces = true 69 // 表示开启命名空间特性,缺省情况设为true,设置使代码更具可读性,但我加进去报错,索性注释掉 70 //saxParser.setProperty("http://xml.org/sax/features/namespaces",true); 71 XMLContentHandler handler = new XMLContentHandler(); 72 73 saxParser.parse(inStream, handler); 74 inStream.close(); 75 76 return handler.getPersons(); 77 78 } catch (Exception e) { 79 80 e.printStackTrace(); 81 82 } 83 84 return null; 85 }
分别点击三个按钮用不同方法解析出来的结果:
三、总结
对于三种解析XML方法,各有千秋,倾向于PULL解析器,因为SAX解析器操作起来太笨重,DOM不适合文档较大,内存较小的场景,
唯有Pull轻巧灵活,速度快,占用内存小,使用非常顺手,Pull解析可以用于很多场合,例如接受google天气,rss新闻等。