Java XML DOM解析(xPath)

(一) XML概念

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

 

(二)XML作用

1. 描述帶關係的數據(常用做軟件的配置文件):描述包含於被包含的關係,適用範圍非常廣泛,比如 tomcat SSH框架全部都使用到了XML

例如配置主機和端口號:

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

 

2. 作爲數據的載體(存儲數據,小型的“數據庫”)

例如存儲信息:

1 teacher.xml2                         <teacher>    3                                 <name>張三</name>4                                 <email>[email protected]</email>5                                 <workage>2</workage>6                         </teacher>

 

(三)XML語法

  xml文件以xml後綴名結尾。

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

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 element15      */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>

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章