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新闻等。

原文地址:https://www.cnblogs.com/aiguozhe/p/3632365.html