android中解析XML文件方式—DOM SAX PULL

 

DOM解析XML文件时,会将XML文件的所有内容以文档树方式存放在内存中,然后允许您使用DOM API遍历XML树、检索所需的数据。使用DOM操作XML的代码看起来是比较直观的,并且在某些方面比基于SAX的实现更加简单。但是,因为DOM需要 将XML文件的所有内容以文档树方式存放在内存中,所以内存的消耗比较大,特别对于运行Android的移动设备来说,因为设备的资源比较宝贵,所以建议还是采用SAX来解析XML文件,当然,如果XML文件的内容比较小采用DOM也是可行的

DOM解析虽然我们在android中并不推荐使用,但是这并不代表着不可以实现。dom的原理是把xml文件的各种部分都看成是节点,所有的节点因为层级关系最后形成了一颗节点树。而DOM的解析方式便是在内存中生存这棵树,并允许用户进行相关的操作。

定义一个XML

public classDOMPersonService {

      

       public static List<Person>getPersonList(InputStream inStream) throws Exception{

             

              List<Person> personList =new ArrayList();

             

              DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();

              DocumentBuilder  builder = factory.newDocumentBuilder();

              Document document =builder.parse(inStream);

             

              //注意,此时xml文件已经都被装入内存中的document对象里了        

             

              //取得根结点(元素节点)

              Element root =document.getDocumentElement(); 

             

              NodeList nodes =root.getElementsByTagName("person");

             

              for(int i=0;i<nodes.getLength(); i++){

                     Element personElement =(Element) nodes.item(i);

                    

                     Person person = newPerson();

                     //为person添加id属性值

                     person.setId(Integer.valueOf(personElement.getAttribute("id")));

                    

                     NodeList childNodes =personElement.getChildNodes();

                    

                     //遍历孩子节点,忽略文本节点,保留并处理元素节点

                     for(int j=0;j<childNodes.getLength(); j++){

                            Node childNode =childNodes.item(j);

                            if(childNode.getNodeType()== Node.ELEMENT_NODE){

                                   if("name".equals(childNode.getNodeName())){

                                          person.setName(childNode.getFirstChild().getNodeValue());

                                   }elseif("age".equals(childNode.getNodeName())){

                                          TexttextNode = (Text) childNode.getFirstChild();

                                          StringageStr = textNode.getNodeValue();

                                          person.setAge(Integer.valueOf(ageStr));

                                   }

                            }

                     }                  

                     personList.add(person);                   

              }           

              return personList;

       }

      

}

<?xmlversion="1.0" encoding="UTF-8"?>

<persons>

       <person id="111">

              <name>Tom</name>

              <age>20</age>

       </person>

       <person id="222">

              <name>Mary</name>

              <age>17</age>

       </person>

</persons>

这里列出几个dom中经常用到的方法

Node 接口的常用方法

一个节点可以调用

shortgetNodeType()

方法返回一个表示节点类型的常量(Node接口规定的常量值),例如,对于Element节点,getNodeType()方法返回的值为:

Node.ELEMENT_NODE

节点可以调用

NodeList  getChildNodes()

返回一个由当前节点的所有子节点组成的NodeList对象。节点调用

Node  getFirstChild()

返回当前节点的第一个子节点。节点调用

Node  getLastChild()

返回当前节点的最后一个子节点。节点可以调用

NodeList  getTextContent()

返回当前节点及所有子孙节点中的文本内容。

 

SAX是一种XML解析的替代方法。相比于DOM,SAX是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一 边解析。而且相比于DOM,SAX可以在解析文档的任意时刻停止解析,但任何事物都有其相反的一面,对于SAX来说就是操作复杂

DOM和SAX的解析方式不相同,DOM方式先扫描xml文件并生成树结构,树结构存储在内存里,操作便利。而SAX解析则由消息响应驱动,不需将文档调入内存。

事件处理的顺序,处理时间的位置:一般在startDocument()初始化工作,在endDocument()中收尾的处理工 作;startElement()—characters()—endDocument()是一个XML节点读取的过程,startElement()用 来初始判断,characters()获取节点的字符数据,endDocument()将数据写入数据结构。

public classSAXPersonService {

      

       public List<Person>getPersonList(InputStream inStream) throws Exception{

             

              //得到创建SAX解析器的工厂对象

              SAXParserFactory factory =SAXParserFactory.newInstance();

              //让工厂对象创建解析器对象

              SAXParser parser =factory.newSAXParser();

             

              //创建DefaultHandler对象

              PersonHandler handler = newPersonHandler();

              //使用parser的parser(Inputstream in, DefaultHandler handler)进行解析       

              parser.parse(inStream, handler);

             

              List<Person> personList =handler.getPersonlist();

             

              return personList;

       }

      

}

覆盖defaulthandler几个方法

public classPersonHandler extends DefaultHandler {

 

       List<Person> personList = null;

 

       Person person = null;

       String elementTag = null;

 

       public void startDocument() throwsSAXException {

              personList = newArrayList<Person>();

       }

 

       public void startElement(String uri,String localName, String qName,

                     Attributes attributes)throws SAXException {

 

              if("person".equals(localName)) {

                     person = new Person();

                     String id =attributes.getValue(0);

 

                     person.setId(Integer.valueOf(id));

              }

              elementTag = localName;

       }

 

       public void characters(char[] ch, intstart, int length)

                     throws SAXException {

 

              String data = new String(ch, start,length);

              if (elementTag != null &&person !=null) {

                     if("name".equals(elementTag)) {

                            person.setName(data);

                     } else if("age".equals(elementTag)) {

                            person.setAge(Integer.valueOf(data));

                     }

              }

       }

 

       public void endElement(String uri, StringlocalName, String qName)

                     throws SAXException {

              if("person".equals(localName)) {

                     personList.add(person);

                     person = null;

              }

              elementTag = null;

       }

 

       public void endDocument() throwsSAXException {

 

       }

 

       public List<Person> getPersonlist(){

              return personList;

       }

 

}

startDocument:当遇到文档的时候就触发这个事件 调用这个方法 可以在其中做些预处理工作。

 

startElement:(String namespaceURI,String localName,String qName,Attributes atts)当遇开始标签的时候就会触发这个方法。

endElement(String uri,String localName,String name):当遇到结束标签时触发这个事件,调用此法可以做些善后工作。

charachers(char []ch,int start,int length):当遇到xml内容时触发这个方法,用newString(ch,start,length)可以接受内容。

PULL

除了可以使用 SAX和DOM解析XML文件,大家也可以使用Android内置的Pull解析器解析XML文件。 Pull解析器的运行方式与SAX 解析器相似。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型节点的值。

1.常见的XML解析方式有三种,DOM、SAX、Pull,Android系统中推荐使用Pull

2.Pull解析器是一个开源的Java项目,Android系统内部解析XML文件均为此种方式,也可用于JavaEE项目

3.Android SDK中已经集成了Pull解析器,无需添加任何jar文件

4.Pull解析器运行方式与SAX类似,提供各种事件的判断

使用Pull解析器解析XML文件

1.  Xml.newPullParser() 获得解析器

2  parser.setInput(in, "UTF-8") 设置输入流以及编码

3. parser.next() 获取下一个解析事件,得到一个事件代码

4. XmlPullParser中定义了常量来标识各种解析事件

START_DOCUMENT、END_DOCUMENT 、START_TAG 、END_TAG 、TEXT

建议使用次解析方式

public classPullPersonService {

 

       public static List<Person>getPersonList(InputStream inStream)

                     throws Exception {

              List<Person> personList =null;

 

              XmlPullParser parser =Xml.newPullParser();

              parser.setInput(inStream,"utf-8");

 

              int eventType =parser.getEventType();

 

              Person person = null;

 

              while (eventType != XmlPullParser.END_DOCUMENT) {

                     switch (eventType) {

                     caseXmlPullParser.START_DOCUMENT: //判断当前事件是否是文档开始事件

                            personList = newArrayList<Person>();

                            break;

                     caseXmlPullParser.START_TAG:

                            // 判断当前元素名是否为person

                            if("person".equals(parser.getName())) {

                                   person = newPerson();

                                   person.setId(Integer.valueOf(parser.getAttributeValue(0)));

                            } else if("name".equals(parser.getName())) {

                                   person.setName(parser.nextText());

                            } else if("age".equals(parser.getName())) {

                                   person.setAge(Integer.valueOf(parser.nextText()));

                            }

                            break;

                     case XmlPullParser.END_TAG://判断当前事件是否是标签元素结束事件

                            if("person".equals(parser.getName()) && person != null) { //判断结束标签元素是否是person

                                   personList.add(person);

                                   person= null;

                            }

                            break;

                     }

 

                     // next方法的调用导致下一个节点的解析,同时返回下一个节点解析的事件类型代码

                     eventType = parser.next();

              }

              return personList;

       }

   利用PULL//创建XML文件

       public static voidwritePersonList(List<Person> personList, Writer writer)

                     throws Exception {

              XmlSerializer serializer =Xml.newSerializer();

              serializer.setOutput(writer);

 

              // 相当于写入<?xmlversion="1.0" encoding="UTF-8"?>

              serializer.startDocument("utf-8",true);

              //写入跟元素的起始标签

              serializer.startTag(null,"persons");

             

              //遍历personList,并且将集合中的Person对象作为person节点写入xml

              for(Person person: personList){

                     serializer.startTag(null,"person");

                     //为person元素添加id属性

                     serializer.attribute(null,"id", String.valueOf(person.getId()));

                    

                     serializer.startTag(null,"name");

                     serializer.text(person.getName());

                     serializer.endTag(null,"name");

                    

                     serializer.startTag(null,"age");

                     serializer.text(String.valueOf(person.getAge()));

                     serializer.endTag(null,"age");

                    

                     serializer.endTag(null,"person");

              }           

             

              //写入跟元素的结束标签             

              serializer.endTag(null,"persons");

              //结束文档的写入

              serializer.endDocument();

             

              writer.flush();

              writer.close();

       }

测试方法

public class Testextends AndroidTestCase {

       public void testSAX() throws Throwable {

 

              List<Person> personList =null;

 

              SAXPersonService service = newSAXPersonService();

 

              InputStream inStream =this.getClass().getClassLoader()

                            .getResourceAsStream("person_list.xml");

              personList =service.getPersonList(inStream);

 

              // for(int i=0;i<personList.size(); i++){

              // Log.i("TAG", personList.get(i).toString());

              // }

 

              Log.i("TAG",personList.toString());

       }

 

       public void testDOM() throws Throwable {

              List<Person> personList =null;

              InputStream inStream =this.getClass().getClassLoader()

                            .getResourceAsStream("person_list.xml");

              personList =DOMPersonService.getPersonList(inStream);

 

              Log.i("TAG",personList.toString());

       }

 

       public void testPull() throws Throwable {

              InputStream inStream =this.getClass().getClassLoader()

                            .getResourceAsStream("person_list.xml");

              List<Person> personList =PullPersonService.getPersonList(inStream);

              Log.i("TAG",personList.toString());        

       }

      

       public void testPullSave() throwsThrowable{

              List<Person> personList =new ArrayList<Person>();

              personList.add(newPerson(999,"Tom", 20));

              personList.add(newPerson(888,"Mary", 21));

              personList.add(newPerson(777,"Jack", 10));

             

              File file = newFile(this.getContext().getFilesDir(), "new_persons.xml");

              Writer writer = newFileWriter(file);

             

              PullPersonService.writePersonList(personList,writer);

       }

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值