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);
       }