Java XML DOM解析(xPath)

(一) XML概念node

  在電子計算機中,標記指計算機所能理解的信息符號,經過此種標記,計算機之間能夠處理包含各類的信息好比文章等。它能夠用來標記數據、定義數據類型,是一種容許用戶對本身的標記語言進行定義的源語言。 它很是適合萬維網傳輸,提供統一的方法來描述和交換獨立於應用程序或供應商的結構化數據。是Internet環境中跨平臺的、依賴於內容的技術,也是當今處理分佈式結構信息的有效工具。早在1998年,W3C就發佈了XML1.0規範,使用它來簡化Internet的文檔信息傳輸。數據庫

 

(二)XML做用瀏覽器

1. 描述帶關係的數據(經常使用作軟件的配置文件):描述包含於被包含的關係,適用範圍很是普遍,好比 tomcat SSH框架所有都使用到了XMLtomcat

例如配置主機和端口號:框架

1 host.xml
2                             <host>
3                                 <ip>255.43.12.55</ip>
4                                 <port>1521</port>
5                             </host>

 

2. 做爲數據的載體(存儲數據,小型的「數據庫」)dom

例如存儲信息:分佈式

1 teacher.xml
2                         <teacher>    
3                                 <name>張三</name>
4                                 <email>zhangsan@qq.com</email>
5                                 <workage>2</workage>
6                         </teacher>

 

(三)XML語法函數

  xml文件以xml後綴名結尾。工具

  xml文件須要使用xml解析器去解析。瀏覽器內置了xml解析器spa

3.1 標籤

語法: <student></student>  開始標籤  標籤體內容  結束標籤

1)<student/> 或 <student></student> 空標籤。沒有標籤體內容

2)xml標籤名稱區分大小寫。

3)xml標籤必定要正確配對。

4)xml標籤名中間不能使用空格

5)xml標籤名不能以數字開頭

6)注意: 在一個xml文檔中,有且僅有一個根標籤

 

3.2 屬性

語法: <Student name="eric">student</Student>

注意:

1)屬性值必須以引號包含,不能省略,也不能單雙引號混用!

2)一個標籤內能夠有多個屬性,但不能出現重複的屬性名!

 

3.3 轉義字符

在xml中內置了一些特殊字符,這些特殊字符不能直接被瀏覽器原樣輸出。若是但願把這些特殊字符按照原樣輸出到瀏覽器,對這些特殊字符進行轉義。轉義以後的字符就叫轉義字節。

特殊字符 轉義字符
<            &lt;
>        &gt;
"         &quot;
&        &amp;
空格      &nsbp;

 

(四) XML的DOM解析:

  XML文檔除了須要供開發者來閱讀、配置相關信息,還須要讓程序可以讀懂其中包含的信息,這就叫作XML文檔的解析。

其中XML文檔主要有兩種解析方式,DOM解析和SAX解析,這裏咱們主要講DOM解析方式,而這種方式也是SSH三大框架的解析XML的方式。

 

4.1 DOM解析:

DOM解析原理:xml解析器一次性把整個xml文檔加載進內存,而後在內存中構建一顆Document的對象樹,經過Document對象,獲得樹上的節點對象,經過節點對象訪問(操做)到xml文檔的內容。

Document對象表明了一個完整的xml文檔,經過Document對象,能夠獲得其下面的其餘節點對象,經過各個節點對象來訪問xml文檔的內容。

其中主要包括:標籤節點,屬性節點,文本節點和註釋節點;而且各種節點也被封裝成對應的對象,經過操做不一樣的對象來訪問xml的內容:

樹只有一個根標籤,樹上的分支叫作節點(node)

 

4.2 Domj4讀取xml文件

  首先建立xml解析器對象,獲取到Document對象:

複製代碼
 1     public static Document getDocument(){
 2 
 3         //建立一個XML解析器
 4         SAXReader saxReader = new SAXReader();
 5         try {
 6             //讀取Document對象
 7             Document document = null;
 8             document = saxReader.read("./src/xml/User.xml");
 9             return document;
10         } catch (DocumentException e) {
11             e.printStackTrace();
12         }
13         return null;
14     }
複製代碼

節點:

 Iterator  Element.nodeIterator();  //獲取當前標籤節點下的全部子節點

 

標籤:

Element Document.getRootElement();  //獲取xml文檔的根標籤              

Element ELement.element("標籤名") //指定名稱的第一個子標籤

Iterator<Element> Element.elementIterator("標籤名");// 指定名稱的全部子標籤

List<Element> Element.elements(); //獲取全部子標籤

代碼示例:

複製代碼
 1 /**
 2      * 遍歷全部的標籤節點
 3      * @param document
 4      */
 5     public static void gerAll(Document document){
 6 
 7         //獲取XML文檔的根標籤
 8         Element rootElement = document.getRootElement();
 9         getChildNodes(rootElement);
10     }
11 
12     /**
13      * 遞歸獲取傳入標籤下的全部子節點
14      * @param element
15      */
16     public static void getChildNodes(Element element){
17         System.out.println(element.getName());
18         // 迭代器獲取當前節點下的全部子節點
19         Iterator<Node> it = element.nodeIterator();
20         while (it.hasNext()){
21             Node node = it.next();
22             //1 判斷是不是標籤
23             if (node instanceof Element){
24                 //若是仍然是標籤節點,那個遞歸獲取子節點
25                 getChildNodes((Element) node);
26             }
27 
28         }
29     }
30 
31 
32     /**
33      * 獲取當前標籤的指定名稱的第一個子標籤
34      * @param element 當前標籤
35      */
36     public static Element getElementByName(Element element, String elemName){
37 
38         //獲取當前標籤下的指定名稱的第一個子標籤
39         Element elem = element.element(elemName);
40         System.out.println(elem.getName());
41         return elem;
42     }
43 
44     /**
45      * 獲取當前標籤下指定名稱的全部子標籤
46      * @param element 當前標籤
47      * @param elemName 指定的名稱
48      */
49     public static Iterator<Element> getElementsByName(Element element, String elemName){
50 
51         //獲取當前標籤下的指定名稱的全部子標籤
52         Iterator<Element> itElement = element.elementIterator(elemName);
53         while (itElement.hasNext()){
54             Element elem = itElement.next();
55             System.out.println(elem.getName());
56         }
57         return itElement;
58     }
59 
60     /**
61      * 獲取當前標籤下全部子標籤
62      * @param element 當前標籤
63      */
64     public static List<Element> getElements(Element element){
65 
66         //獲取當前標籤下的指定名稱的全部子標籤
67         List<Element> elementList = element.elements();
68         for (Element elem : elementList) {
69             System.out.println(elem.getName());
70         }
71 
72         return elementList;
73     }
複製代碼

 

屬性:

String   Element.attributeValue("屬性名") //獲取指定名稱的屬性值

Attribute    Element.attribute("屬性名");//獲取指定名稱的屬性對象      

Attribute.getName()  //獲取屬性名稱

Attibute.getValue()  //獲取屬性值

List<Attribute>  Element.attributes();  //獲取全部屬性對象

Iterator<Attribute>  Element.attibuteIterator(); //獲取全部屬性對象

 代碼示例:

複製代碼
 1 /**
 2      * 獲取屬性信息
 3      */
 4 
 5 
 6     /**
 7      * 根據屬性名稱獲取指定的屬性 和屬性值
 8      * @param element 所在標籤節點
 9      * @param attName 屬性名
10      */
11     public static void getAttributeByName(Element element,String attName){
12 
13         //想要獲取屬性,首先要獲取屬性所在的標籤 即傳入的標籤
14 
15         // 直接根據id獲取屬性值
16         element.attributeValue(attName);
17 
18         // 獲取attribute對象,而後獲取name和value值
19         Attribute attribute = element.attribute(attName);
20         String str = attribute.getName() + "=" + attribute.getValue();
21         System.out.println(str);
22     }
23 
24     public static void getAttributes(Element element){
25 
26         List<Attribute> attributeList =  element.attributes();
27         for (Attribute attribute : attributeList) {
28             System.out.println( attribute.getName() + "="+ attribute.getValue() );
29         }
30 
31         //Iterator<Attribute> itAttribute = element.attributeIterator();
32     }
複製代碼

 

文本:

Element.getText();  //獲取當前標籤的文本

Element.elementText("標籤名") //獲取當前標籤的指定名稱的子標籤的文本內容

代碼示例:

複製代碼
1     /**
2      * 獲取文本信息
3      */
4 
5     public static String getText(Element element){
6         //注意:空格和換行也是xml的內容
7         String text = element.getText();
8         return text;
9     }
複製代碼

 

4.3 Domj4修改xml文件


增長:

DocumentHelper.createDocument() 增長文檔

addElement("名稱") 增長標籤

addAttribute("名稱",「值」) 增長屬性

代碼示例:

複製代碼
 1 /**
 2      * 增長:文檔,標籤 ,屬性
 3      */
 4     @Test
 5     public void AddNode() throws Exception{
 6 
 7         //建立文檔
 8         Document doc = DocumentHelper.createDocument();
 9         //增長標籤
10         Element rootElem = doc.addElement("UserList");
11         Element userElem = rootElem.addElement("User");
12         userElem.addElement("username");
13         //增長屬性值
14         userElem.addAttribute("id", "001");
15         userElem.addAttribute("username", "eric");
16         
17         writeXml(doc);
18     }
複製代碼

 

修改:

Attribute.setValue("值") 修改屬性值

Element.addAtribute("同名的屬性名","值") 修改同名的屬性值

Element.setText("內容") 修改文本內容

代碼示例:

複製代碼
 1 /**
 2      * 修改:屬性值,文本
 3      * @throws Exception
 4      */
 5     @Test
 6     public void updateNode()    throws Exception{
 7         Document doc = new SAXReader().read(new File("./src/xml/userWrite.xml"));
 8         
 9         /**
10          * 方案一: 修改屬性值   1.獲得標籤對象 2.獲得屬性對象 3.修改屬性值
11          */
12         //1.1 獲得標籤對象
13         /*
14         Element userElem = doc.getRootElement().element("User");
15         //1.2 獲得屬性值
16         Attribute idAttr = userElem.attribute("id");
17         //1.3 修改屬性值
18         idAttr.setValue("003");
19         */
20         /**
21          * 方案二: 修改屬性值
22          */
23         //1.1 獲得標籤對象
24         /*
25         Element userElem = doc.getRootElement().element("User");
26         //1.2 經過增長同名屬性的方法,修改屬性值
27         userElem.addAttribute("id", "004");
28         */
29 
30         /**
31          * 修改文本 1.獲得標籤對象 2.修改文本
32          */
33         Element nameElem = doc.getRootElement().element("User").element("username");
34         nameElem.setText("王五");
35 
36         //把修改後的Document對象寫出到xml文檔中
37         writeXml(doc);
38     }
複製代碼

 

刪除

Element.detach(); 刪除標籤

Attribute.detach(); 刪除屬性

 代碼示例:

複製代碼
 1 /**
 2      * 刪除:標籤,屬性
 3      * @throws Exception
 4      */
 5     @Test
 6     public void deleteNode() throws Exception{
 7         Document doc = new SAXReader().read(new File("./src/xml/userWrite.xml"));
 8         
 9         /**
10          * 1.刪除標籤   1.1 獲得標籤對象  1.2 刪除標籤對象
11          */
12         // 1.1 獲得標籤對象
13         /*
14         Element ageElem = doc.getRootElement().element("User").element("age");
15         //1.2 刪除標籤對象
16         ageElem.detach();
17         //ageElem.getParent().remove(ageElem);
18         */
19         /**
20          * 2.刪除屬性   2.1獲得屬性對象  2.2 刪除屬性
21          */
22         //2.1 獲得屬性對象
23         //到第二個user標籤
24         Element userElem = (Element)doc.getRootElement().
25             elements().get(0);
26         //2.2 獲得屬性對象
27         Attribute idAttr = userElem.attribute("id");
28         //2.3 刪除屬性
29         idAttr.detach();
30         //idAttr.getParent().remove(idAttr);
31 
32         writeXml(doc);
33     }
複製代碼

 

寫出內容到xml文檔
XMLWriter writer = new XMLWriter(OutputStream, OutputForamt)
wirter.write(Document);

代碼示例:

複製代碼
 1 /**
 2      * 把修改後的Document對象寫出到xml文檔中
 3      * @param document
 4      * @throws IOException
 5      */
 6     public void writeXml(Document document) throws IOException {
 7         //把修改後的Document對象寫出到xml文檔中
 8         FileOutputStream out = new FileOutputStream("./src/xml/userWrite.xml");
 9         //比較美觀的排版方式 用於人閱讀
10         OutputFormat format = OutputFormat.createPrettyPrint();
11 
12         //緊湊型的排版方式 ,主要用於程序運行中使用 減小沒必要要的空格換行等
13         //OutputFormat format2 = OutputFormat.createCompactFormat();
14 
15         format.setEncoding("utf-8");
16         XMLWriter writer = new XMLWriter(out,format);
17         writer.write(document);
18         writer.close();
19 
20     }
複製代碼

 

其中使用的到xml文件:

複製代碼
 1 <?xml version="1.0" encoding="utf-8"?>
 2 
 3 <UserList>
 4     <User id="001">
 5         <username>張三</username>
 6         <passwprd>33333</passwprd>
 7         <age>33</age>
 8         <address>aaaaaaaa</address>
 9     </User>
10 
11     <User id="002">
12         <username>李四</username>
13         <passwprd>44444</passwprd>
14         <age>44</age>
15         <address>bbbbbbbbb</address>
16     </User>
17     <abc></abc>
18 
19 </UserList>
複製代碼

 

 

(五)xPath技術


5.1 引入


問題:當使用dom4j查詢比較深的層次結構的節點(標籤,屬性,文本),比較麻煩!


5.2 xPath做用
主要是用於快速獲取所需的節點對象。

 

5.3 在dom4j中如何使用xPath技術


1)導入xPath支持jar包 。 jaxen-1.1-beta-6.jar
2)使用xpath方法 :這裏使用的是多態技術,由於不論是標籤仍是屬性或者文本類型的對象都是節點對象
List<Node> selectNodes("xpath表達式"); 查詢多個節點對象
Node selectSingleNode("xpath表達式"); 查詢一個節點對象

5.4 xPath語法

/ 絕對路徑 表示從xml的根位置開始或子元素(一個層次結構)
// 相對路徑 表示不分任何層次結構的選擇元素。 
* 通配符 表示匹配全部元素
[] 條件 表示選擇什麼條件下的元素
@ 屬性 表示選擇屬性節點
and 關係 表示條件的與關係(等價於&&)
text() 文本 表示選擇文本內容

 

語法示例:

 

/AAA

選擇根元素AAA


     <
AAA
          <BBB/> 
          <CCC/> 
          <BBB/> 
          <BBB/> 
          <DDD> 
               <BBB/> 
          </DDD> 
          <CCC/> 
     </
AAA>

 

/AAA/CCC

選擇AAA的全部CCC子元素


     <AAA> 
          <BBB/> 
          <
CCC/> 
          <BBB/> 
          <BBB/> 
          <DDD> 
               <BBB/> 
          </DDD> 
          <
CCC/> 
     </AAA>

 

/AAA/DDD/BBB

選擇AAA的子元素DDD的全部子元素


     <AAA> 
          <BBB/> 
          <CCC/> 
          <BBB/> 
          <BBB/> 
          <DDD> 
               <
BBB/> 
          </DDD> 
          <CCC/> 
     </AAA>

 

若是路徑以雙斜線 // 開頭, 則表示選擇文檔中全部知足雙斜線//以後規則的元素(不管層級關係)

 

//BBB

選擇全部BBB元素


     <AAA> 
          <
BBB/> 
          <CCC/> 
          <
BBB/> 
          <DDD> 
               <
BBB/> 
          </DDD> 
          <CCC> 
               <DDD> 
                    <
BBB/> 
                    <
BBB/> 
               </DDD> 
          </CCC> 
     </AAA>

//DDD/BBB

選擇全部父元素是DDDBBB元素


     <AAA> 
          <BBB/> 
          <CCC/> 
          <BBB/> 
          <DDD> 
              
 <BBB/> 
          </DDD> 
          <CCC> 
               <DDD> 
                 
   <BBB/> 
                    <BBB/> 

               </DDD> 
          </CCC> 
     </AAA>

 

星號 * 表示選擇全部由星號以前的路徑所定位的元素

 

/AAA/CCC/DDD/*

選擇全部路徑依附於/AAA/CCC/DDD的元素


     <AAA> 
          <XXX> 
               <DDD> 
                    <BBB/> 
                    <BBB/> 
                    <EEE/> 
                    <FFF/> 
               </DDD> 
          </XXX> 
          <CCC> 
               <DDD> 
                    <
BBB/> 
                    <
BBB/> 
                    <
EEE/> 
                    <
FFF/> 
               </DDD> 
          </CCC> 
          <CCC> 
               <BBB> 
                    <BBB> 
                         <BBB/> 
                    </BBB> 
               </BBB> 
          </CCC> 
     </AAA>

 

 

/*/*/*/BBB

選擇全部的有3個祖先元素的BBB元素


     <AAA> 
          <XXX> 
               <DDD> 
                    <
BBB/> 
                    <
BBB/> 
                    <EEE/> 
                    <FFF/> 
               </DDD> 
          </XXX> 
          <CCC> 
               <DDD> 
                    <
BBB/> 
                    <
BBB/> 
                    <EEE/> 
                    <FFF/> 
               </DDD> 
          </CCC> 
          <CCC> 
               <BBB> 
                    <
BBB
                         <BBB/> 
                    </
BBB
               </BBB> 
          </CCC> 
     </AAA>

 

方塊號裏的表達式能夠進一步的指定元素, 其中數字表示元素在選擇集裏的位置, 而last()函數則表示選擇集中的最後一個元素.

 

/AAA/BBB[1]

選擇AAA的第一個BBB子元素


     <AAA> 
          <
BBB/> 
          <BBB/> 
          <BBB/> 
          <BBB/> 
     </AAA>

 

/AAA/BBB[last()]

選擇AAA的最後一個BBB子元素


     <AAA> 
          <BBB/> 
          <BBB/> 
          <BBB/> 
          <
BBB/> 
     </AAA>

 

屬性經過前綴 @ 來指定

 

//@id

選擇全部的id屬性


     <AAA> 
          <BBB
 id = "b1"/> 
          <BBB
 id = "b2"/> 
          <BBB name = "bbb"/> 
          <BBB/> 
     </AAA>

 

//BBB[@id]

選擇有id屬性的BBB元素


     <AAA> 
          <
BBB id = "b1"/> 
          <
BBB id = "b2"/> 
          <BBB name = "bbb"/> 
          <BBB/> 
     </AAA>

 

//BBB[@name]

選擇有name屬性的BBB元素


     <AAA> 
          <BBB id = "b1"/> 
          <BBB id = "b2"/> 
          <
BBB name = "bbb"/> 
          <BBB/> 
     </AAA>

 

//BBB[@*]

選擇有任意屬性的BBB元素


     <AAA> 
          <
BBB id = "b1"/> 
          <
BBB id = "b2"/> 
          <
BBB name = "bbb"/> 
          <BBB/> 
     </AAA>

 

屬性的值能夠被用來做爲選擇的準則, normalize-space函數刪除了前部和尾部的空格, 而且把連續的空格串替換爲一個單一的空格

 

//BBB[@id='b1']

選擇含有屬性id且其值爲'b1'的BBB元素


     <AAA> 
          <
BBB id = "b1"/> 
          <BBB name = " bbb "/> 
          <BBB name = "bbb"/> 
     </AAA>

 

count()函數能夠計數所選元素的個數

//*[count(BBB)=2]

選擇含有2個BBB子元素的元素


     <AAA> 
          <CCC> 
               <BBB/> 
               <BBB/> 
               <BBB/> 
          </CCC> 
          <
DDD
               <BBB/> 
               <BBB/> 
          </
DDD>           <EEE>                <CCC/>                <DDD/>           </EEE>      </AAA>

相關文章
相關標籤/搜索