編輯:Android開發實例
前言
前面已經介紹了Android平台下兩種解析XML的方法,SAX和PULL,這兩個均為事件驅動,以流的形式解析XML文檔。現在介紹一種新的方式DOM方式解析XML。
DOM是一種用於XML文檔對象模型,可用於直接訪問XML文檔的各個部位,在DOM中文檔被模擬成樹狀,其中XML語法的每一組成部分都表示一個節點,DOM允許用戶遍歷文檔樹,從父節點移動到子節點和兄弟節點。並利用某節點類型特有的屬性(元素具有屬性,文本節點具有文本數據)。
對於DOM而言,XML文檔中每一個成分都是一個節點。
DOM是這樣規定的:
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文檔內容:
- <?xml version="1.0" encoding="utf-8" ?>
- - <persons>
- - <person id="23">
- <name>Jack</name>
- <age>21</age>
- </person>
- - <person id="20">
- <name>Dick</name>
- <age>23</age>
- </person>
- </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應用增加訪問網絡的權限。
- package cn.bgxt.xmlfordom;
- import java.io.InputStream;
- import java.util.List;
- import cn.bgxt.domain.Person;
- import cn.bgxt.http.HttpUtils;
- import cn.bgxt.service.DomService;
- import android.os.Bundle;
- import android.app.Activity;
- import android.util.Log;
- import android.view.Menu;
- import android.view.View;
- import android.widget.Button;
- public class MainActivity extends Activity {
- private Button button;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- button=(Button)findViewById(R.id.btn);
- button.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // Android 4.0+不能在主線程中訪問網絡
- Thread thread=new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- String path="http://192.168.1.107:1231/persons.xml";
- InputStream inputStream=HttpUtils.getXML(path);
- List<Person> list=DomService.getPersons(inputStream);
- for(Person person:list)
- {
- //以日志的形式打印對象內容
- Log.i("DOM", person.toString());
- }
- } catch (Exception e) {
- // TODO: handle exception
- }
- }
- });
- thread.start();
- }
- });
- }
- }
如果解析成功,可以在LogCat中查看到日志。
示例程序源碼
總結
現在已經講解的常用的Android應用中解析XML的方法,DOM和PULL、SAX不一樣,是文檔模型形式的,在解析的時候會把整個XML的內容都讀取到內存中,這樣對於移動設備而言,是很消耗內存的。而PULL以及SAX都是事件驅動,逐行去解析XML的內容,相對而言保證了解析速度又不會很損耗內存。所以Android應用中一般不推薦使用DOM解析XML,還是偏向於使用SAX、PULL。但是DOM也有它的優點,正因為它是把整個文檔都讀取到內存中了,可以指定需要查找的數據而無需遍歷所有的節點,對於內容比較少的XML而言,還是很方便的。所以解析XML的方法有很多,無法絕對的說明誰好誰壞,主要還是看需求設定的環境來取捨的。
我用的是cocos2d-2.0-x-2.0.3 之前弄了一天也沒成功 今天來了下載了最新的ndk8 更新了sdk 又重新是了一遍 居然成功了,不知道是工具的版本問
SlidingDrawer隱藏屏外的內容,並允許用戶通過handle以顯示隱藏內容。它可以垂直或水平滑動,它有倆個View組成,其一是可以拖動的handle,其二
Android中可以直接在位圖上進行人臉檢測。Android SDK為人臉檢測
從 Android 5.0 Lollipop 開始提供一套 API 來支持嵌入的滑動效果。同樣在最