三种XML解析方法总结

SAX解析

如果要用SAX来解析xml文档,则需要一个类来继承android系统提供的ContentHandler类。但是如果继承ContentHandler这个类, 即使你不使用这个类提供的所有方法,你也必须实现其内部的所有方法(一般情况下没有使用的方法可以直接用空方法代替),但是这样开发起来不是很方便。因此我们可以改为继承DefaultHandler这个类,这样的话我们只需要实现程序中所需要的方法即可,其它的方法这个类内部其实已经用空方法代替了。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ContentHandler接口的方法有以下几种:  
  2. void startDocument();//文档解析开始时执行  
  3. void endDocument();//文档解析结束时执行  
  4. void startElement(String uri, String localName, String qName, Attributes atts);//标签开始解析时执行  
  5. void endElement(String uri, String localName, String qName, Attributes atts);//标签解析结束时执行  
  6. void characters(char[] ch, int start, int length );//解析标签属性时执行  

android中使用SAX来解析xml文件,需先建立一个SAX工厂,即SAXParserFactory对象,还需建立一个XMLReader对象,该类绑定ContentHandler子类,且与xml源文件结合在一起。即其处理过程为创建事件处理程序,创建SAX解析器,键事件处理程序分配给解析器,对文档进行解析,将每个事件发送给处理程序。

1.在src目录下新建一个android.xml文件

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <persons>  
  3.     <person id="23">  
  4.         <name>xiaanming</name>  
  5.         <age>23</age>  
  6.     </person>  
  7.     <person id="20">  
  8.         <name>liudehua</name>  
  9.         <age>28</age>  
  10.     </person>  
  11. </persons>  

2.新建一个Person.class用来存放解析的对象

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.example.xml_parser;  
  2.   
  3. public class Person {  
  4.     private int id;  
  5.     private String name;  
  6.     private int age;  
  7.       
  8.     public Person(){}  
  9.       
  10.     public Person(int id, String name, int age){  
  11.         this.id = id;  
  12.         this.name = name;  
  13.         this.age = age;  
  14.     }  
  15.   
  16.     public int getId() {  
  17.         return id;  
  18.     }  
  19.   
  20.     public void setId(int id) {  
  21.         this.id = id;  
  22.     }  
  23.   
  24.     public String getName() {  
  25.         return name;  
  26.     }  
  27.   
  28.     public void setName(String name) {  
  29.         this.name = name;  
  30.     }  
  31.   
  32.     public int getAge() {  
  33.         return age;  
  34.     }  
  35.   
  36.     public void setAge(int age) {  
  37.         this.age = age;  
  38.     }  
  39.       
  40.     @Override  
  41.     public String toString() {  
  42.         return "id = " + id + ", name " + name + ", age = " + age;  
  43.     }  
  44.       
  45. }  

3.新建一个SAXforHandler类继承DefaultHandler,而DefaultHandler实现了ContentHandler接口,需要重写我们需要的方法

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.example.xml_parser;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.InputStreamReader;  
  7. import java.util.ArrayList;  
  8. import java.util.List;  
  9.   
  10. import javax.xml.parsers.SAXParser;  
  11. import javax.xml.parsers.SAXParserFactory;  
  12.   
  13. import org.xml.sax.Attributes;  
  14. import org.xml.sax.InputSource;  
  15. import org.xml.sax.SAXException;  
  16. import org.xml.sax.XMLReader;  
  17. import org.xml.sax.helpers.DefaultHandler;  
  18.   
  19. import android.util.Log;  
  20.   
  21. public class SAXforHandler extends DefaultHandler {  
  22.     private static final String TAG = "SAXforHandler";  
  23.     /** 
  24.      * 用来存放解析的Person对象 
  25.      */  
  26.     private List<Person> persons;  
  27.       
  28.     /** 
  29.      * Person 对象的引用,记录当前的Person 
  30.      */  
  31.     private Person person;  
  32.       
  33.     /** 
  34.      * 通过此变量,记录当前一个标签的名称 
  35.      */  
  36.     private String tag ;  
  37.       
  38.   
  39.     /** 
  40.      * 此方法只有在开始解析文档的时候执行一次,比较适合处理一些初始化的东西 
  41.      * 我new 了一个ArrayList<Person>()对象和打印Log 
  42.      */  
  43.     @Override  
  44.     public void startDocument() throws SAXException {  
  45.         persons = new ArrayList<Person>();  
  46.         Log.i(TAG, "****startDocument*****");  
  47.     }  
  48.   
  49.     /** 
  50.      * 文档解析完了调用的回调方法 
  51.      */  
  52.     @Override  
  53.     public void endDocument() throws SAXException {  
  54.         Log.i(TAG, "****endDocument*****");  
  55.     }  
  56.   
  57.     /** 
  58.      * uri 是命名空间 
  59.      * localName 标签的名称,如name, age 等 
  60.      * qName 带命名空间的标签名 
  61.      * Attributes 存放改标签的所有属性 
  62.      *  
  63.      * 当localName为person的时候, 我们拿出 person标签的属性值,此处由于只有一个属性,也可以直接person.setId(Integer.valueOf(attributes.getValue(0))); 
  64.      * 然后设置tag = person,这个方法执行完了,然后会执行回调方法characters(char[] ch, int start, int length),这是一个循环的过程 
  65.      */  
  66.     @Override  
  67.     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {  
  68.         if("person".equals(localName)){  
  69.             for(int i=0; i<attributes.getLength(); i++){  
  70.                 Log.i(TAG, "attributesName: " + attributes.getLocalName(i) + "__attributesValue: " + attributes.getValue(i) );  
  71.                 person = new Person();  
  72.                 person.setId(Integer.valueOf(attributes.getValue(i)));  
  73.             }  
  74.         }  
  75.           
  76.         tag = localName;  
  77.         Log.i(TAG, "localName = " + localName);  
  78.     }  
  79.   
  80.       
  81.     /** 
  82.      * 这个方法只要是获取两个标签里面的值的,这里最好用trim()方法过滤下,可以避免读取到的XML有空格带来不必要的麻烦 
  83.      * 执行完这个方法就执行回调方法endElement(String uri, String localName, String qName),这也是一个循环的过程 
  84.      */  
  85.     @Override  
  86.     public void characters(char[] ch, int start, int length)  
  87.             throws SAXException {  
  88.         String date = new String(ch, start, length).trim();  
  89.         if(!"".equals(date)){  
  90.             Log.i(TAG, "Content: " + date);  
  91.         }  
  92.         if("name".equals(tag)){  
  93.             person.setName(date);  
  94.         }else if("age".equals(tag)){  
  95.             person.setAge(Integer.valueOf(date));  
  96.         }  
  97.     }  
  98.       
  99.       
  100.     /** 
  101.      * uri ,localName, qName跟上面的一个意思 
  102.      * 当localName = person 并且person对象为 null时 ,说明一个person对象解析完毕 
  103.      * 将person加入到List当中 
  104.      * 每个标签解析完了需要将tag = null 
  105.      */  
  106.     @Override  
  107.     public void endElement(String uri, String localName, String qName)  
  108.             throws SAXException {  
  109.         if("person".equals(localName) && person != null){  
  110.             persons.add(person);  
  111.             person = null;  
  112.         }  
  113.           
  114.         tag = null;  
  115.     }  
  116.       
  117.     /** 
  118.      * 拿到成员变量List<Person> persons的方法 
  119.      * @return 
  120.      */  
  121.     public List<Person> getPersons() {  
  122.         return persons;  
  123.     }  
  124.   
  125.   
  126.     /** 
  127.      * 1.加载需要解析的文件,因为XML放在src目录下,可以通过类装载器的方法获得文件路径,在以输入流的方式加入解析器 
  128.      * 2.解析XML有两种形式,创建一个XMLReader 或者直接使用XMLParser 
  129.      * @return 
  130.      * @throws Exception 
  131.      */  
  132.     public static List<Person> sax_XML() throws Exception{  
  133.         InputStream is = MainActivity.class.getClassLoader().getResourceAsStream("android.xml");  
  134.           
  135.         <span style="font-size:32px;color:#ff0000;">/** 坑爹的地方,当我调用getInputStreamContent (InputStream is)这个方法时,解析就错误,不知道为什么???*/  
  136. </span>       
  137.         SAXforHandler saXforHandler = new SAXforHandler();  
  138.         SAXParserFactory spf = SAXParserFactory.newInstance();  
  139.         SAXParser saxParser = spf.newSAXParser();  
  140.           
  141.         //使用XMLReader的方式  
  142. //      XMLReader xmlReader = saxParser.getXMLReader();  
  143. //      xmlReader.setContentHandler(saXforHandler);  
  144. //      xmlReader.parse(new InputSource(is));  
  145.           
  146.         //直接使用XMLParser,推荐使用这种  
  147.         saxParser.parse(is, saXforHandler);  
  148.           
  149.         //获取解析好了的List对象  
  150.         List<Person> list = saXforHandler.getPersons();  
  151.         is.close();  
  152.         return list;  
  153.     }  
  154.       
  155.       
  156.     /** 
  157.      * 测试方法,根据输入流获取里面的内容 
  158.      * @param is 
  159.      * @return 
  160.      * @throws IOException 
  161.      */  
  162.     public static String getInputStreamContent (InputStream is) throws IOException{  
  163.         StringBuffer sb = new StringBuffer();  
  164.         BufferedReader br = new BufferedReader(new InputStreamReader(is));  
  165.         String line;  
  166.         while((line = br.readLine()) != null){  
  167.             sb.append(line);  
  168.         }  
  169.         br.close();  
  170.           
  171.         Log.i(TAG, sb.toString());  
  172.           
  173.         return sb.toString();  
  174.     }  
  175. }  


DOM解析
DOM比SAX更容易掌握,因为她没有涉及回调和复杂的状态管理,然而,DOM的实现常常将所有的XML节点保存在内存中,这样使的处理较大的文档效率低。

XML基本的节点类型

node - DOM基本的数据类型

Element - 最主要处理的对象是Element

Attr - 元素的属性

Text - 一个Element 或者Attr的实际内容

Document - 代表整个XML文档,一个Document对象通常也称为一颗DOM树

 

1 新建一个DomPersonService.class,注释我写的清楚,大家自己看

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.example.dom_parser;  
  2.   
  3. import java.io.InputStream;  
  4. import java.util.ArrayList;  
  5. import java.util.List;  
  6.   
  7. import javax.xml.parsers.DocumentBuilder;  
  8. import javax.xml.parsers.DocumentBuilderFactory;  
  9.   
  10. import org.w3c.dom.Document;  
  11. import org.w3c.dom.Element;  
  12. import org.w3c.dom.Node;  
  13. import org.w3c.dom.NodeList;  
  14.   
  15. import android.util.Log;  
  16.   
  17.   
  18. public class DomPersonService {  
  19.       
  20.       
  21.     public static List<Person> readXML() throws Throwable{  
  22.         //获得android.xml文件的输入流  
  23.         InputStream is = MainActivity.class.getClassLoader().getResourceAsStream("android.xml");  
  24.         List<Person> persons = new ArrayList<Person>();  
  25.           
  26.         //实例化DocumentBuilderFactory和DocumentBuilder,并创建Document  
  27.         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
  28.         DocumentBuilder builder = factory.newDocumentBuilder();  
  29.         Document document = builder.parse(is);  
  30.           
  31.         //返回文档的根(root)元素  
  32.         Element rootElement =  document.getDocumentElement();  
  33.           
  34.         //获取一个Note(DOM基本的数据类型)集合,这里有两个person Note  
  35.         NodeList nodes = rootElement.getElementsByTagName("person");  
  36.           
  37.         //遍历Note集合  
  38.         for(int i=0; i<nodes.getLength(); i++){  
  39.             //先从第一个person元素开始解析  
  40.             Element personElement = (Element) nodes.item(i);  
  41.             Person person = new Person();  
  42.             person.setId(Integer.valueOf(personElement.getAttribute("id")));  
  43.               
  44.             //获取person下面的name 和 age 的Note集合  
  45.             NodeList chileNodes = personElement.getChildNodes();  
  46.             for(int y=0; y<chileNodes.getLength(); y++){  
  47.                 Node childNode = chileNodes.item(y);  
  48.                   
  49.                 //判断子Note的类型为元素Note  
  50.                 if(childNode.getNodeType() == Node.ELEMENT_NODE){  
  51.                     Element childElement = (Element) childNode;  
  52.                 if("name".equals(childElement.getNodeName())){  
  53.                     person.setName(childElement.getFirstChild().getNodeValue());  
  54.                 }else if("age".equals(childElement.getNodeName())){  
  55.                     person.setAge(Integer.valueOf(childElement.getFirstChild().getNodeValue()));  
  56.                 }  
  57.                 }  
  58.             }  
  59.               
  60.             Log.e("log", person.toString());  
  61.               
  62.             persons.add(person);  
  63.         }  
  64.           
  65.         return persons;  
  66.           
  67.     }  
  68. }  

关于DOM解析XML,我们要清楚的知道个节点之间的关系,才能更好的操作对象树,值得注意的是在建立Element时,要注意jar包的导入, 要选择org.w3c.dom.Element,而不是其他的包.


Pull解析

1.Pull简介

Pull解析器是Android系统内置的的,Pull解析器与SAX解析器类似,他提供了类似的事件,如开始元素和介绍元素的事件,使用parser.next()可以进入下一个元素并触发相应的事件,然后进行相应的处理,当元素开始解析时,调用perser.nextText()方法就可以获取到下一个Text类型元素的值。

2.pull特点

一.简单的结构,一个接口,一个另外,一个工厂组成了Pull解析器

二.简单易用,Pull解析器只有一个重要的方法next(),他被用来检索下一个事件,而他的事件也仅仅只有五个,START_DOCUMENT, START_TAG ,TEXT, END_TAG, END_DOCUMENT

三.最小的内存消耗,Pull解析器和SAX解析器一样,对内存的暂用少,但是SAX解析稍微有点繁琐,DOM很耗内存,所以Pull被推荐使用

3,示例 Pull解析XML

新建一个PullXMLService

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.example.pull_parser;  
  2.   
  3. import java.io.InputStream;  
  4. import java.util.ArrayList;  
  5. import java.util.List;  
  6.   
  7. import org.xmlpull.v1.XmlPullParser;  
  8.   
  9. import android.util.Log;  
  10. import android.util.Xml;  
  11.   
  12. public class PullXMLService {  
  13.     public static List<Person> readXML() throws Exception{  
  14.         //获取src目录下面的android.xml文件的输入流  
  15.         InputStream is = PullXMLService.class.getClassLoader().getResourceAsStream("android.xml");  
  16.         //用来存放解析的Person对象  
  17.         List<Person> persons = null;  
  18.         //一个标记  
  19.         boolean flag = false;  
  20.         Person person = null;  
  21.           
  22.         //实例化一个XmlPullParser对象  
  23.         XmlPullParser parser = Xml.newPullParser();  
  24.           
  25.         //设置输入流和编码  
  26.         parser.setInput(is, "UTF-8");  
  27.           
  28.         //触发了第一个事件,根据XML的语法,也就是从他开始了解文档  
  29.         int eventCode = parser.getEventType();  
  30.           
  31.         //如果获得的事件码如果是文档的结束,那么解析结束  
  32.         while (eventCode != XmlPullParser.END_DOCUMENT) {  
  33.             switch(eventCode){  
  34.             case XmlPullParser.START_DOCUMENT:{  
  35.                 //开始解析的时候我们一般做一些初始化的操作  
  36.                 persons = new ArrayList<Person>();  
  37.                 break;  
  38.             }  
  39.             case XmlPullParser.START_TAG:{  
  40.                 //判断当前的元素是否是需要检索的元素  
  41.                 if("person".equals(parser.getName())){  
  42.                     flag = true;  
  43.                     person = new Person();  
  44.                     person.setId(Integer.valueOf(parser.getAttributeValue(0)));  
  45.                 }  
  46.                 if(flag){  
  47.                     if("name".equals(parser.getName())){  
  48.                         person.setName(parser.nextText());  
  49.                     }else if("age".equals(parser.getName())){  
  50.                         person.setAge(Integer.valueOf(parser.nextText()));  
  51.                     }  
  52.                 }  
  53.                 break;  
  54.             }  
  55.             case XmlPullParser.END_TAG:{  
  56.                 if("person".equals(parser.getName()) && person != null){  
  57.                     flag = false;  
  58.                     persons.add(person);  
  59.                     Log.e("log", person.toString());  
  60.                     person = null;  
  61.                 }  
  62.                 break;  
  63.             }  
  64.             }  
  65.               
  66.             //这一步很重要,该方法返回一个事件码,也是触发下一个事件的方法  
  67.             eventCode = parser.next();  
  68.         }  
  69.           
  70.         return persons;  
  71.           
  72.     }  
  73. }  

好了,这样子就解析完了android.xml 是不是很方便很简单呢,比SAX和DOM要更容易理解。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值