Android--解析XML之DOM


前言

  前面已經介紹了Android平台下兩種解析XML的方法,SAX和PULL,這兩個均為事件驅動,以流的形式解析XML文檔。現在介紹一種新的方式DOM方式解析XML。

  DOM是一種用於XML文檔對象模型,可用於直接訪問XML文檔的各個部位,在DOM中文檔被模擬成樹狀,其中XML語法的每一組成部分都表示一個節點,DOM允許用戶遍歷文檔樹,從父節點移動到子節點和兄弟節點。並利用某節點類型特有的屬性(元素具有屬性,文本節點具有文本數據)。

  對於DOM而言,XML文檔中每一個成分都是一個節點。

  DOM是這樣規定的:

  1. 整個文檔是一個文檔節點。
  2. 每一個XML標簽是一個元素節點。
  3. 包含在XML元素中的文本是一個文本節點。
  4. 每一個XML屬性是一個屬性節點。

 

DOM解析XML

  DOM解析XML也是需要一個工廠類DocumentBuilderFactory,這一點和SAX、PULL類似。工廠類也是單例模式,沒有提供共有的構造函數,需要使用靜態的newInstance()方法獲得,並且需要工廠類來獲取DOM解析器實例,使用DocumentBuilderFactory.newDocumentBuilder()獲得的DocumentBuilder對象。

  當獲得Document之后,就可以使用parse()解析XML文檔,parser多個重載,可以適用於不同的輸入。

  下面介紹一下在DOM解析XML過程中,會碰上幾個對象,Element、NodeList、Node。說也不太好說清楚,畫個圖解釋一下更直觀。

  從圖上可以看出,Element為一個元素,可以通過這個元素獲取到該元素的屬性值(Attribute),以及它的子節點的集合NodeList。而NodeList作為一個裝載平級節點的集合,可以通過NodeList獲得它內裝載的所有平級節點,可以通過索引獲取。對於Node,表示最終的節點,根據圖示說的,其實Jack文本也是一個文本節點(Node),Node可以獲取其節點名稱、其值、其屬性。所以它們三個是可以相互嵌套的,也不存在說誰一定要在誰的外側或是內層。

 

示例程序

  既然已經說了那么多了,現在通過一個示例程序展示一下DOM解析XML。這是一個Android應用程序,為了模擬真實的環境,通過網絡讀取IIS上的一個靜態XML文件內容。直接上代碼,注釋已經寫的很清楚了。

  IIS上的靜態XML文檔內容:

 1   <?xml version="1.0" encoding="utf-8" ?> 
 2 - <persons>
 3 - <person id="23">
 4   <name>Jack</name> 
 5   <age>21</age> 
 6   </person>
 7 - <person id="20">
 8   <name>Dick</name> 
 9   <age>23</age> 
10   </person>
11   </persons>

 

  DomService,解析網絡傳輸來的XML文檔流:

package cn.bgxt.service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


import cn.bgxt.domain.Person;

public class DomService {

    public DomService() {
        // TODO Auto-generated constructor stub
    }

    public static List<Person> getPersons(InputStream inputStream) throws Exception
    {
        List<Person> list=new ArrayList<Person>();
        //獲取工廠對象,以及通過DOM工廠對象獲取DOMBuilder對象
        DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
        DocumentBuilder builder=factory.newDocumentBuilder();
        //解析XML輸入流,得到Document對象,表示一個XML文檔
        Document document=builder.parse(inputStream);
        //獲得文檔中的次以及節點,persons
        Element element=document.getDocumentElement();
        // 獲取Element下一級的person節點集合,以NodeList的形式存放。
        NodeList personNodes=element.getElementsByTagName("person");
        for(int i=0;i<personNodes.getLength();i++)
        {
            //循環獲取索引為i的person節點
            Element personElement=(Element) personNodes.item(i);
            Person person=new Person();
            //通過屬性名,獲取節點的屬性id
            person.setId(Integer.parseInt(personElement.getAttribute("id")));
            //獲取索引i的person節點下的子節點集合
            NodeList childNodes=personElement.getChildNodes();
            for(int j=0;j<childNodes.getLength();j++)
            {
                //循環遍歷每個person下的子節點,如果判斷節點類型是ELEMENT_NODE,就可以依據節點名稱給予解析
                if(childNodes.item(j).getNodeType()==Node.ELEMENT_NODE)
                {
                    if("name".equals(childNodes.item(j).getNodeName()))
                    {
                        //因為文本也是一個文本節點,
                        //所以這里讀取到name節點的時候,
                        //通過getFirstChild()可以直接獲得name節點的下的第一個節點,就是name節點后的文本節點
                        //取其value值,就是文本的內容
                        person.setName(childNodes.item(j).getFirstChild().getNodeValue());
                    }
                    else if("age".equals(childNodes.item(j).getNodeName()))
                    {
                        person.setAge(Integer.parseInt(childNodes.item(j).getFirstChild().getNodeValue()));
                    }
                }
            }
            //把解析的person對象加入的list集合中
            list.add(person);
        }
        return list;
    }
}

  從IIS服務器上獲取XML的方式,在另外一篇博客:HTTP協議。中已經介紹了,如果不明白可以去看看,這里就不介紹了。

  Activity的布局就是一個按鈕,用於點擊出發解析事件,因為是Android4.0+的環境,需要無法在主線程中訪問網絡,需要使用到多線程的技術,並且不要網了給Android應用增加訪問網絡的權限。

 1 package cn.bgxt.xmlfordom;
 2 
 3 import java.io.InputStream;
 4 import java.util.List;
 5 import cn.bgxt.domain.Person;
 6 import cn.bgxt.http.HttpUtils;
 7 import cn.bgxt.service.DomService;
 8 import android.os.Bundle;
 9 import android.app.Activity;
10 import android.util.Log;
11 import android.view.Menu;
12 import android.view.View;
13 import android.widget.Button;
14 
15 public class MainActivity extends Activity {
16 
17     private Button button;
18     
19     @Override
20     protected void onCreate(Bundle savedInstanceState) {
21         super.onCreate(savedInstanceState);
22         setContentView(R.layout.activity_main);
23         
24         button=(Button)findViewById(R.id.btn);
25         button.setOnClickListener(new View.OnClickListener() {
26             
27             @Override
28             public void onClick(View v) {
29                 // Android 4.0+不能在主線程中訪問網絡
30                 Thread thread=new Thread(new Runnable() {                    
31                     @Override
32                     public void run() {
33                         try {
34                             String path="http://192.168.1.107:1231/persons.xml";
35                             InputStream inputStream=HttpUtils.getXML(path);
36                             List<Person> list=DomService.getPersons(inputStream);
37                             for(Person person:list)
38                             {
39                                 //以日志的形式打印對象內容
40                                 Log.i("DOM", person.toString());                            
41                             }
42                         } catch (Exception e) {
43                             // TODO: handle exception
44                         }
45                     }
46                     
47                 });
48                 thread.start();
49             }
50             
51         });
52         
53         
54     }
55 
56 }

  如果解析成功,可以在LogCat中查看到日志。

  示例程序源碼

總結

  現在已經講解的常用的Android應用中解析XML的方法,DOM和PULL、SAX不一樣,是文檔模型形式的,在解析的時候會把整個XML的內容都讀取到內存中,這樣對於移動設備而言,是很消耗內存的。而PULL以及SAX都是事件驅動,逐行去解析XML的內容,相對而言保證了解析速度又不會很損耗內存。所以Android應用中一般不推薦使用DOM解析XML,還是偏向於使用SAX、PULL。但是DOM也有它的優點,正因為它是把整個文檔都讀取到內存中了,可以指定需要查找的數據而無需遍歷所有的節點,對於內容比較少的XML而言,還是很方便的。所以解析XML的方法有很多,無法絕對的說明誰好誰壞,主要還是看需求設定的環境來取舍的。

  請支持原創,尊重原創,轉載請注明出處。謝謝。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM