1. 程式人生 > >【XML解析】(1)Java下使用JAXP中的DOM解析方式對XML文件進行解析

【XML解析】(1)Java下使用JAXP中的DOM解析方式對XML文件進行解析

關於JAXP、DOM、SAX:

何為JAXP?

JAXP(JavaApi for Xml Programming) – sun公司的一套操作XML的API。

JAXP中分為三種解析方式:

DOM解析、SAX解析、StAX

DOM解析:一次性的將資料全部裝入記憶體。

SAX解析:邊讀取邊解析。

DOM、SAX、StAX關鍵詞解釋:

【DOM】:

DOM-Document Object Model-文件對像模型。是w3c組織處理xml的一種方式。

DOM的特點:

①一次將所有資料全部載入到記憶體中。

②對xml文件中的每一個節點都當成一個Node對像處理。包括元素、文字、屬性。

③org.w3c.dom包中的Document,Element,Node。

④非常方便進行修改。

⑤已經整合在了JDK中,是Sun對xml操作的標準。

⑥缺點是當文件資料量很大時,對記憶體有佔用很大。

【SAX】:

Sax – Simple Api for XML 。

①在讀取資料時分析資料,通過事件監聽器來完成。

②速度快但只適合讀取資料,僅向前讀取不可後退。

【StAX】:

①The Streaming API for XML基於流的XML程式設計介面

②StAX即可讀文件也可以寫文件。

③而SAX只可以讀取文件。

XML解析的方式分為以下幾種-圖解:

這裡寫圖片描述

DOM解析的說明:

DOM解析一次將所有的元素全部載入到記憶體中:如有以下XML文件(users.xml):

users.xml:

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user id="A001">
        <name
>
Jack</name> <age>22</age> </user> <user id="A002"> <name>張三</name> <age>21</age> </user> </users> 【注意】由於DOM解析,一次性的將所有元素(包含屬性和文字) 全部載入到記憶體中,所以不適用於解析大量的資料。

user.xml在記憶體中的DOM結構:

這裡寫圖片描述

JAXP-DOM解析時候用到的Java包:

【org.w3c.dom】 – 關鍵類Document代表記憶體中的文件對像模型。

這裡寫圖片描述
w3c是制定標準,具體的實現還是看sun公javax.xml.parsers

【javax.xml.parse】– 關鍵類DocumentBuilder,文件解析對像。

【javax.xml】– 關鍵類Transformer,用於將記憶體中的文件儲存到檔案中。

以上三個類之間的關係:

這裡寫圖片描述

在DOM中,所有元素都是Node的子類:

這裡寫圖片描述

DOM解析的具體實現方式:

準備XML資料:

users.xml 這裡寫圖片描述

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user id="A001">
        <name>Jack</name>
        <age>22</age>
    </user>
    <user id="A002">
        <name>張三</name>
        <age>21</age>
    </user>
</users>

建立Document物件的思路:

①首先直接找到Document類,在org.w3c.dom包中找到,我們可以看到Document是一個介面,因此需要找到此介面的具體實現類或者能夠返回出此型別的方法。

②因為w3c只是制定標準,具體類實現在sun公司的java包中,javax.xml.parsers。

③類 DocumentBuilderFactory構造方法是protected的,因此要找其中的static方法(newInstance() ),此方法返回此類型別,此時有了dbf物件。

④通過此物件dbf呼叫(newDocumentBuilder())得到DocumentBuilder類物件db。

⑤有了db物件,就可以呼叫此類(DocumentBuilder)中的parse(File f)方法就可以返回(Document)類物件dom。

建立Document物件程式碼實現:

第一步:建立工廠
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
第二步:建立解析器
DocumentBuilder db=dbf.newDocumentBuilder();
第三步:獲得dom物件
Document dom=db.parse("./xml/users.xml");
第四步:通過節點(Node)或者元素(Element)方式解析DOM樹
/....../

(一)通過節點(Node)方法解析DOM樹:

第四步:首先獲取根節點
Node rootNode=dom.getFirstChild();
第五步:接著獲取此根節點的所有孩子節點
NodeList nodeList=rootNode.getChildNodes();
第六步:獲取<user>標籤的這個節點
Node userNode=nodeList.item(1);
第七步:獲取<user>節點下的<name>節點
Node nameNode=userNode.getChildNodes().item(1)
第八步:獲取此name節點的文字內容
String name=nameNode.getTextContent();

(二)通過Document中的getElementsByTagName()方法解析DOM樹:

第四步:首先獲取根節點:
Node root=dom.getFirstChild();
第五步:將根節點強轉成Element元素型別
Element eroot=(Element) root;
第六步:通過標籤名獲取所有的此標籤節點
NodeList userList=eroot.getElementsByTagName("user");
第七步:將某一個標籤節點進行強轉
Element eUser1=(Element) userList.item(0);
第八步:再逐層通過標籤名獲得某個元素
NodeList nameList=eUser1.getElementsByTagName("name");
Node nameNode=nameList.item(0);
String name=nameNode.getTextContent();

讀取節點中的屬性:

因為Node沒有獲取屬性的方式,所以必須將Node強制向下轉換成Element來處理。

使用:getAttribute(String name)來獲取。
這裡寫圖片描述

獲取節點屬性程式碼實現:

DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
Document dom=db.parse("./xml/users.xml/");
//將根節點強制轉換為元素型別
Node root=dom.getFirstChild();
Element eroot=(Element) root;
NodeList userList=eroot.getElementsByTagName("user");
Element eUser1=(Element) userList.item(0);
//獲取user節點中的屬性id
String id=eUser1.getAttribute("id");
System.out.println("id="+id);

完整程式碼演示:

package cn.hncu.jaxp.dom;

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

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

/**
 * 解析XML:
 * 1、解析XML的方式:JAXP(DOM、StAX)、jDom(dom4j)
 * 2、如何使用?
 * JDK中有兩個專用於dom程式設計的包:
 * (1)、org.w3c.dom -----w3c是制定標準,具體的實現還是看sun公司的javax.xml.parsers
 * (2)、javax.xml.parsers -----sun公司具有開發出來解析的工具
 * 
 * 
 * 入口方式:
 * Document(來自org.w3c.dom)-->要用工廠方法獲得該dom物件-->工廠方法來自sun公司(javax.xml.parsers)
 * 
 * 
 */

public class DomDemo {
    /*
     * 獲取dom物件
     */
    @Test
    public void getDom() throws Exception{

        DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
        DocumentBuilder db=dbf.newDocumentBuilder();
        Document dom=db.parse("./xml/users.xml");
        System.out.println(dom);//[#document: null]
    }

    /*
     * 通過節點的方式獲得name,age
     */
    @Test
    public void getName() throws Exception{
        DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
        DocumentBuilder db=dbf.newDocumentBuilder();
        Document dom=db.parse("./xml/users.xml");
        //獲得根節點
        Node rootNode=dom.getFirstChild();
        String rootNodeName=rootNode.getNodeName();
        System.out.println("rootNodeName= "+rootNodeName);  
        /*
         * 獲得根節點的所有孩子節點:包括空白符和標籤
         * 【注意】:
         *  1、通過Node中的getChildNodes(),返回型別為NodeList,獲取當前節點的所有子節點(包括文字內容和標籤節點)。
         *  2、但是一般不選擇這種方式的理由:文字內容尤其是空白符也是其中的孩子節點,會產生干擾!
         *  3、因此最好的方式就是:通過Element下的getElementByTagName(String name)
         */
        NodeList nodeList=rootNode.getChildNodes();
        for(int i=0;i<nodeList.getLength();i++){
            System.out.println( nodeList.item(i).getNodeName());
        }
        //獲取第一個user節點下的name、age
        Node userNode=nodeList.item(1);
        String name=userNode.getChildNodes().item(1).getTextContent();
        String age=userNode.getChildNodes().item(3).getTextContent();
        System.out.println(name+","+age);
        //獲取第二個user節點下的name、age
        Node userNode2=nodeList.item(3);
        String name2=userNode2.getChildNodes().item(1).getTextContent();
        String age2=userNode2.getChildNodes().item(3).getTextContent();
        System.out.println(name2+","+age2);
    }

    /*
     * 建議採用的方式:用Element中的getElementsByTagName(String name)
     * 為了使用使用Element中的方法必須將Node強轉成Element型別。 
     */
    @Test
    public void getName2() throws Exception{
        DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
        DocumentBuilder db=dbf.newDocumentBuilder();
        Document dom=db.parse("./xml/users.xml/");
        //將根節點強制轉換為元素型別
        Node root=dom.getFirstChild();
        Element eroot=(Element) root;
        NodeList userList=eroot.getElementsByTagName("user");
        Element eUser1=(Element) userList.item(0);
        //獲取user節點中的屬性id
        String id=eUser1.getAttribute("id");
        System.out.println("id="+id);

        //獲取name
        NodeList nameList=eUser1.getElementsByTagName("name");
        Node nameNode=nameList.item(0);
        String name=nameNode.getTextContent();
        //獲取age
        NodeList ageList=eUser1.getElementsByTagName("age");
        Node ageNode=ageList.item(0);
        String age=ageNode.getTextContent();
        System.out.println(name+":"+age);

    }


}

執行結果:

getName()執行結果:

這裡寫圖片描述

getName2()執行結果:

這裡寫圖片描述