一、简述
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新闻等。