(一) XML概念
在電子計算機中,標記指計算機所能理解的信息符號,通過此種標記,計算機之間可以處理包含各種的信息比如文章等。它可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。 它非常適合萬維網傳輸,提供統一的方法來描述和交換獨立於應用程序或供應商的結構化數據。是Internet環境中跨平台的、依賴於內容的技術,也是當今處理分布式結構信息的有效工具。早在1998年,W3C就發布了XML1.0規范,使用它來簡化Internet的文檔信息傳輸。
(二)XML作用
1. 描述帶關系的數據(常用做軟件的配置文件):描述包含於被包含的關系,適用范圍非常廣泛,比如 tomcat SSH框架全部都使用到了XML
例如配置主機和端口號:
1 host.xml 2 <host> 3 <ip>255.43.12.55</ip> 4 <port>1521</port> 5 </host>
2. 作為數據的載體(存儲數據,小型的“數據庫”)
例如存儲信息:
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解析器
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中內置了一些特殊字符,這些特殊字符不能直接被瀏覽器原樣輸出。如果希望把這些特殊字符按照原樣輸出到瀏覽器,對這些特殊字符進行轉義。轉義之后的字符就叫轉義字節。
特殊字符 轉義字符
< <
> >
" "
& &
空格 &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/CCC |
選擇AAA的所有CCC子元素 |
|
/AAA/DDD/BBB |
選擇AAA的子元素DDD的所有子元素 |
|
如果路徑以雙斜線 // 開頭, 則表示選擇文檔中所有滿足雙斜線//之后規則的元素(無論層級關系)
//BBB |
選擇所有BBB元素 |
|
//DDD/BBB |
選擇所有父元素是DDD的BBB元素 |
|
星號 * 表示選擇所有由星號之前的路徑所定位的元素
/AAA/CCC/DDD/* |
選擇所有路徑依附於/AAA/CCC/DDD的元素 |
|
/*/*/*/BBB |
選擇所有的有3個祖先元素的BBB元素 |
|
方塊號里的表達式可以進一步的指定元素, 其中數字表示元素在選擇集里的位置, 而last()函數則表示選擇集中的最后一個元素.
/AAA/BBB[1] |
選擇AAA的第一個BBB子元素 |
|
/AAA/BBB[last()] |
選擇AAA的最后一個BBB子元素 |
|
屬性通過前綴 @ 來指定
//@id |
選擇所有的id屬性 |
|
//BBB[@id] |
選擇有id屬性的BBB元素 |
|
//BBB[@name] |
選擇有name屬性的BBB元素 |
|
//BBB[@*] |
選擇有任意屬性的BBB元素 |
|
屬性的值可以被用來作為選擇的准則, normalize-space函數刪除了前部和尾部的空格, 並且把連續的空格串替換為一個單一的空格
//BBB[@id='b1'] |
選擇含有屬性id且其值為'b1'的BBB元素 |
|
count()函數可以計數所選元素的個數
//*[count(BBB)=2] |
選擇含有2個BBB子元素的元素 |
|
本文所涉及到的代碼:https://git.oschina.net/infaraway/basisJava/tree/master/src/xml