在上一篇博文《Android學習筆記41:XML檔案解析(SAX方式)》中,我們學習了如何使用SAX解析器對XML檔案進行解析,從而獲得我們想要的有用資訊。
本篇博文主要介紹如何使用DOM解析器對XML檔案進行解析。
1.DOM樹中的物件類型
使用DOM解析XML文檔時,整個XML文檔會被轉換成一顆DOM樹,DOM解析器會將XML文檔的節點對應轉化成DOM樹的每個節點。
DOM樹不僅可以描述XML文檔的結構化特徵,而且具有物件模型的特徵,將XML文檔轉換成DOM樹的過程,就是將文檔模型對象化的過程。
在DOM樹中所有節點都是Node對象,Node介面中所包含的一些子介面1所示。
圖1 Node介面中包含的子介面
瞭解了DOM模型中各對象的類型之後,便可以在程式利用這些對象的屬性和方法來訪問它們所包含的資料了。
2.DOM解析器
通過以下三個步驟可以實現DOM解析器的建立,並完成XML文檔模型對象化的過程。
(1)通過調用DocumentBuilderFactory類的newInstance()方法,建立一個DOM解析器工廠對象。
(2)通過調用DOM解析器工廠對象的newDocumentBuilder()方法,建立一個DOM解析器對象。
(3)通過調用DOM解析器對象的parse()方法,完成文檔模型對象化的過程,將XML文檔解析成Document文檔對象。
以上三個步驟用代碼實現如下:
1 2 //建立DOM解析器工廠3 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();4 5 //建立DOM解析器6 DocumentBuilder documentBuilder = factory.newDocumentBuilder();7 8 //解析XML文檔,獲得該XML文檔對應的Document對象9 Document document = documentBuilder.parse(inputStream);
以上代碼以InputStream輸入資料流的形式將XML文檔解析成了Document對象。其實,在DocumentBuilder抽象類別中包含了多個重載的parse()方法,可以用於將不同形式的XML文檔解析成Document對象,具體如下所示。
(1)Document parse(File f);
(2)Document parse(InputSourse is);
(3)Document parse(InputStream is);
(4)Document parse(InputStream is, String systemId);
(5)Document parse(String uri);
3.使用DOM解析XML文檔
3.1擷取XML元素
通過上面的方法,我們已經獲得了XML文檔對應的Document對象。在Document中包含了以下一些用來訪問XML文檔中節點的方法。
(1)Element getDocumentElement();
(2)Element getElementById(String elementId);
(3)NodeList getElementByTagName(String tagname);
其中,getDocumentElement()方法用於擷取XML文檔的根節點;getElementById()方法用於根據XML元素的ID來擷取XML元素;getElementByTagName()方法用於根據XML元素的標籤名來擷取XML元素。
3.2擷取XML元素內容
Element是Node的最常用的子介面,代表一個XML元素,在Element介面中提供了以下一些方法用來擷取XML元素的內容。
(1)String getAttribute(String name);
(2)Attr getAttributeNode(String name);
(3)NodeList getElementByTagName(String name);
(4)String getTagName();
(5)boolean hasAttribute(String name);
其中,getAttribute()方法用於根據屬性名稱擷取指定屬性值;getAttributeNode()方法用於根據屬性名稱擷取指定的屬性節點;getElementByTagName()方法用於根據標籤名擷取由該元素包含的所有子項目所組成的NodeList;getTagName()方法用於擷取該元素的標籤名;hasAttribute()方法用於判斷該元素是否包含某個指定屬性。
3.3擷取節點資料
在DOM樹中,所有節點都是Node對象,每個Node對象都可能包括nodeName、nodeValue和attributes等屬性。但是有一點需要注意,不同的Node節點對這3個屬性的支援是不同的。
在Node介面中提供了以下一些常用的擷取節點資料的方法。
(1)NodeList getChildNodes(); //擷取由該節點所包含的所有子節點所組成的NodeList
(2)Node getFirstChild(); //擷取該節點所包含的第一個子節點
(3)Node getLastChild(); //擷取該節點所包含的最後一個子節點
(4)String getLocalName(); //擷取該節點的標籤名(本地部分)
(5)String getNodeName(); //擷取該節點的節點名
(6)String getNodeValue(); //擷取該節點的節點值
(7)Document getOwnerDocument(); //擷取該節點所在的Document對象
(8)Node getParentNode(); //擷取該節點的父節點
(9)String getTextContent(); //擷取該節點及其子節點的常值內容
(10)String getAttributeNode(String name); //根據屬性名稱擷取指定屬性值
4.執行個體
瞭解了以上這些用於擷取XML元素,以及擷取XML元素內容的方法之後,便可以通過調用這些方法來完成XML文檔的解析了。
這裡,我們仍然以上一篇博文中提到的“person.xml”文檔為例進行說明。“person.xml”內容如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <persons> 3 <person id="1"> 4 <name>Jack</name> 5 <age>24</age> 6 </person> 7 <person id="2"> 8 <name>Tom</name> 9 <age>25</age>10 </person>11 <person id="3">12 <name>Bob</name>13 <age>22</age>14 </person>15 </persons>
根據上面的XML文檔內容,我們可以建立一個Person類,用來存放<person></person>標籤中的內容資訊。我們要做的就是解析出<person></person>標籤中所包含的id、name、age資訊,並將其儲存到Person對象中。
如下的代碼給出了一種實現的方案:
1 /* 2 * Function : 使用DOM解析器解析XML文檔 3 * Param : inputStream 以輸入資料流的形式傳入XML文檔 4 * Retuen : List<Person> Person對象列表 5 * Author : 部落格園-依舊淡然 6 */ 7 public static List<Person> readXML(InputStream inputStream) throws Exception { 8 9 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //建立DOM解析器工廠10 DocumentBuilder documentBuilder = factory.newDocumentBuilder(); //建立DOM解析器11 Document document = documentBuilder.parse(inputStream); //解析XML文檔,獲得該XML文檔對應的Document對象12 Element rootElement = document.getDocumentElement(); //擷取XML文檔中的根節點<persons>13 NodeList nodeList = rootElement.getElementsByTagName("person"); //擷取根節點所包含的所有子項目<person>14 15 List<Person> list = new ArrayList<Person>();16 for(int i = 0; i < nodeList.getLength(); i++) { //遍曆所有的<person>標籤17 Element element = (Element)nodeList.item(i); //擷取每一個<person>元素對象18 Person person = new Person();19 person.setId(Integer.parseInt(element.getAttribute("id"))); //獲得<person>元素的id屬性並存入Person對象20 NodeList childNodeList = element.getChildNodes(); //獲得<person>下的所有子項目21 for(int j = 0; j < childNodeList.getLength(); j++) { //遍曆<person>標籤下的所有子標籤22 Node childNode = (Node)childNodeList.item(j);23 if(childNode.getNodeType() == Node.ELEMENT_NODE) { //當前節點是元素節點24 Element childElement = (Element)childNode;25 if(childElement.getNodeName().equals("name")) { //擷取<name>標籤中的內容並存入Person對象26 person.setName(childElement.getFirstChild().getNodeValue());27 } else if(childElement.getNodeName().equals("age")) { //擷取<age>標籤中的內容並存入Person對象28 person.setAge(Integer.parseInt(childElement.getFirstChild().getNodeValue()));29 }30 }31 }32 list.add(person); //每解析完一個<person>標籤,便將Person對象存入Person對象列表33 }34 return list;35 }