關鍵詞:xml、DTD約束、Schema約束、dom解析、sax解析、jaxp解析器、dom4j解析器
一、xml的簡介
1、eXtensible Markup Language:可擴展標記型語言
①標記型語言:HTML是標記型語言,即使用標簽來操作。
②可擴展:
- HTML里面的標簽是固定,每個標簽都有特定的含義<h1><br/><hr/>
- 標簽可以自己定義,可以寫中文的標簽<person></person>、<貓></貓>
2、xml用途
①HTML是用於顯示數據,xml也可以顯示數據(不是主要功能)
②xml主要功能,為了儲存數據
3、xml是W3C組織發布的技術,目前有兩個版本1.0、1.1
目前使用的都是1.0版本(1.1版本不能向下兼容)
二、xml的應用
1、不同的系統之間傳輸數據
2、用來表示生活中有關系的數據
3、經常用在配置文件,如:現在連接數據庫,肯定知道數據庫的用戶名和密碼,數據庫名稱,如果修改數據的信息,不需要修改源代碼,只要修改配置文件就可以了。
三、xml的語法
1、xml的文檔聲明
①創建一個文件 后綴名是 .xml
②如果寫xml,第一步必須要有一個文檔聲明(寫了文檔聲明之后,表示寫xml文件的內容)
<?xml version="1.0" encoding="gbk"?>
- 在“<”和“?”之間、“?”和“>”之間和“xml”之間不能有空格。
- 文檔聲明必須寫在第一行第一列
- 屬性:
- version:xml的版本1.0(使用)1.1
- encoding:xml編碼gbk utf-8 iso8859-1(不包含中文)
- standalone:是否需要依賴其他文件yes/no
③xml的中文亂碼問題解決:保存時候和設置打開時的編碼一致,不會出現亂碼
2、定義元素(標簽)
①標簽定義
- 標簽定義有開始必須有結束:<person></person>
- 標簽沒有內容,可以在標簽內結束:<aa/>
- 標簽可以嵌套,必須要合理嵌套
- 合理嵌套:<aa><bb></bb></aa>
- 不合理嵌套:<aa><bb></aa></bb>,這種方式是錯誤的
- 一個xml中,只能有一個根標簽,其他標簽都是這個標簽下面的標簽
- 在xml中把空格和換行都當成內容來解析,
- 下面這兩段代碼含義是不一樣的
<aa>1111111</aa> <aa> 1111111 </aa>
②xml中標簽的命名規則(可以用中文)
-
- xml代碼區分大小寫,如<p><P>是兩個不同的標簽
- 不能以數字或“_”(下划線)開頭
- 不能以xml(或XML、或Xml等)開頭
- 不能包含空格
- 名稱中間不能包含冒號(:)。
3、定義屬性
①在xml文檔中,可以為元素定義屬性
<person id1="aa" id2="bb"></person>
②屬性定義要求
- 一個標簽上可以有多個屬性,如:<person id1="aa" id2="bb"></person>
- 屬性名稱不能相同,如<person id="aa" id="bb"></person>,出現錯誤
- 屬性名稱和屬性值之間使用=,屬性值使用引號包起來(可以是單引號,也可以雙引號)
- xml屬性的命名規范和元素的命名規范一致
4、注釋
寫法:<!-- 注釋信息 -->
- 注釋不能放到第一行,第一行必須放文檔說明
- 注釋不能出現在標記中,如非法寫法: <greeting <!--Begin greet-->></greeting>
- 字符串“--”不能出現在注釋中,如非法寫法: <!--This is a Example--Hello World-->
- 在xml中,不允許注釋以“--->”結尾。
- 注釋不嵌套
5、特殊字符
利用轉義字符
特殊符號 | 預定義實體 | 特殊符號 | 預定義實體 |
& | & | " | " |
< | < | ' | &apos |
> | > |
6、CDATA區
可以解決多個字符都需要轉義的操作 if (a<b && b<c && d>f){}
把這些內容放到CDATA區里面,不需要轉義了
寫法:
<![CDATA[ 內容 ]]>
如:
<![CDATA[ <b>if (a<b && b<c && d>f){} </b> ]]>
把特殊字符當做文本內容,而不是標簽
7、PI指令(處理指令)(了解)
可以在xml中設置樣式
寫法:
<?xml-stylesheet type="text/css" href="css的路徑"?>
設置樣式,只能對英文標簽名稱起作用,對於中文的標簽名稱不起作用的。
8、xml語法總結:
- 所有xml元素都必須有關閉標簽
- xml 標簽對大小寫敏感
- xml 必須正確嵌套順序
- xml文檔必須有根元素(只有一個)
- xml 的屬性值需加引號
- 特殊字符必須轉義 ----CDATA
- xml 中的空格、回車換行會解析時被保留
四、xml的約束
約束的作用:
如現在定義一個person的xml文件,只想要這個文件里面保存人的信息,比如name age等,但是如果在xml文件中寫一個標簽<貓>,發現可以正常顯示,因為符合語法規范。但是貓肯定不是人的信息,xml的標簽是自定義的,需要技術來規定xml中只能出現的元素,這個時候需要約束。
xml的約束的技術:DTD約束 和Schema約束。
1、DTD的快速入門
創建一個文件,后綴名為“.dtd”
步驟:
(1) 看xml中有幾個元素,有幾個元素,在dtd文件中寫幾個<!ELEMENT>
(2) 判斷元素是簡單元素還是復雜元素
-復雜元素:有子元素的元素
<!ELEMENT 元素名稱 (子元素)>
-簡單元素:沒有子元素
<!ELEMENT 元素名稱 (#PCDATA)>
(3)需要在xml文件中引入dtd文件三種引入方式:
①引入外部的dtd文件
<!DOCTYPE 根元素名稱 SYSTEM “dtd文件的路徑”>
②使用內部的dtd文件
<!DOCTYPE 書架 [ <!ELEMENT 書架 (書+)> <!ELEMENT 書 (書名,作者,售價)> <!ELEMENT 書名 (#PCDATA)> <!ELEMENT 作者 (#PCDATA)> <!ELEMENT 售價 (#PCDATA)> ]>
③使用外部的dtd文件(網絡上的dtd文件)
<!DOCTYPE 根元素名稱 PUBLIC "DTD名稱" “DTD文件的URL”>
在框架struts2使用配置文件 使用外部的dtd文件
示例:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE 書架 SYSTEM "book.dtd"> <書架> <書> <書名>Java就業培訓教程</書名> <作者>張孝祥</作者> <售價>58.00元</售價> <!--如果添加dtd中無添加的元素,就會報錯,即為約束--> </書> <書> <書名>EJB3.0入門經典</書名> <作者>黎活明</作者> <售價>39.00元</售價> </書> </書架>
book.dtd :
<!ELEMENT 書架 (書+)> <!ELEMENT 書 (書名,作者,售價)> <!ELEMENT 書名 (#PCDATA)> <!ELEMENT 作者 (#PCDATA)> <!ELEMENT 售價 (#PCDATA)>
2、使用dtd定義元素
語法:
<!ELEMENT 元素名 約束>
-簡單元素:沒有子元素
<!ELEMENT 元素名稱 (#PCDATA)>
-
- (#PCDATA):約束元素為字符串類型
- EMPTY:約束元素為空
- ANY:任意
-復雜元素:有子元素的元素
<!ELEMENT 元素名稱 (子元素)>
表示子元素出現的次數
-
- +:表示一次或者多次
- ?:表示零次或者一次
- *:表示零次或者多次
子元素直接使用逗號“,”進行隔開,表示元素出現的順序
子元素直接使用“|”隔開,表示元素只能出現其中的任意一個
括號“()”,用於給元素進行分組
示例:
<!ELEMENT person (name+,age?,sex*,school)>
3、使用dtd定義屬性
①語法:
<!ATTLIST 元素名稱 屬性名稱 屬性類型 屬性的約束 >
②屬性類型:
-CDATA:字符串
<!ATTLIST birthday ID1 CDATA #REQUIRED >
-枚舉:表示只能在一定范圍內出現值,但是只能每次出現其中的一個
如:紅綠燈效果、(aa|bb|cc)
<!ATTLIST age ID2 (AA|BB|CC) #REQUIRED >
-ID:值只能是字母或下划線開頭
<!ATTLIST name ID3 ID #REQUIRED>
③屬性的約束
-#REQUIRED:屬性必須存在
-#IMPLIED:屬性可有可無
-#FIXED:表示一個固定值 ,如#FIXED "AAA"
屬性的值必須是設置的這個固定值
<!ATTLIST sex ID4 CDATA #FIXED "AAA">
-直接值
不寫屬性,使用直接值
寫了屬性,使用設置那個值
<!ATTLIST school ID5 CDATA “WWW”>
4、實體的定義
語法:
<!ENTITY 實體名稱 “實體的值”>
<!ENTITY TEST "HAHAHA">
使用實體 &實體名稱; 比如: &TEST;
注意:定義實體需要寫在內部dtd里面,如果寫在外部的dtd里面,在某些瀏覽器下,內容無法顯示。
五、xml解析的簡介
1、xml是標記型文檔
2、js使用dom解析標記型文檔?
根據html的層級結構,在內存中分配一個樹形結構,把html的標簽,樹形結構,把html的標簽,屬性和文本都封裝成對象
document對象、element對象、屬性對象、文本對象、Node節點對象
3、xml的解析方式(技術):dom和sax
①dom解析和sax解析區別:
dom方式解析:根據xml的層級結構在內存中分配一個樹形結構,把xml的標簽,屬性和文本都封裝成對象
缺點:如果文件過大,造成內存溢出
優點:很方便實現增刪改操作
sax方式解析:采用事件驅動,邊讀邊解析,
從上到下,一行一行的解析,解析到某一個對象,把對象名稱返回
缺點:不能實現增刪改操作
優點:如果文件過大不會造成內存溢出,實現查詢操作

②xml解析器:不同的公司和組織提供了針對dom和sax方式的解析器,通過api方式提供
- sun公司提供了針對dom和sax解析器 jaxp
- dom4j組織,針對dom和sax解析器 dom4j(實際開發中使用)
- jdom組織,針對dom和sax解析器 jdom
4、jaxp的api的查看
jaxp是javase中的一部分,jaxp解析器在jdk的javax.xml.parsers包里面
四個類:分別是針對dom和sax解析使用的類
①dom:
DocumentBuilder:解析器類
-抽象類,不能new
此類的實例可以從DocumentBuilderFactory.newDocumentBuilder() 方法獲取
-一個方法,可以解析xml parse(“xml”路徑) 返回是Document整個文檔
-返回的document是一個接口,父節點是Node,如果在document里面找不到想要的方法,到Node里面去找
-在document里面方法
getElementsByTagName(String tagname)
--這個方法可以得到標簽
--返回集合NodeList
createElement(String tagName)
--創建標簽
createTextNode(String data)
--創建文本
appendChild(Node newChild)
--把文本添加到標簽下面
removeChild(Node oldChild)
--刪除節點
getParentNode()
--獲取父節點
getTextContent()
--得到標簽里面的內容
DocumentBuilderFactory:解析器工廠
②sax:
SAXParser: 解析器類
SAXParserFactory:解析器工廠
5、使用jaxp實現增刪改查操作
①、使用jaxp實現查詢操作
查詢xml中所有的name元素的值
步驟:
1、創建解析器工廠
DocumentBuilderFactory.newInstance();
2、根據解析器工廠創建解析器
builderFactory.newDocumentBuilder();
3、解析xml返回document
Document document = builder.parse(uri);
4、得到所有的name元素
使用document.getElementsByTagName("name");
5、返回集合,遍歷集合,得到每一個name元素
-遍歷 getLength() item()
-得到元素里面值 使用getTextContent()
查詢xml中第一個name元素的值
步驟:
1、創建解析器工廠
2、根據解析器工廠創建解析器
3、解析xml返回document
4、得到所有的name元素
5、使用返回集合,里面方法item,下標獲取具體的元素
Nodelist.item(下標):集合下標從0開始
6、得到具體的值,使用getTextContent方法
②使用jaxp添加節點
在第一個p1下面(末尾)添加<sex>nv</sex>
步驟:
1、創建解析器工廠
2、根據解析器工廠創建解析器
3、解析xml返回document
4、得到第一個p1(得到所有p1,使用item方法下標得到)
5、創建sex標簽createElementNode
6、串及文本createTextNode
7、把文本添加到sex下面appendChild
8、把sex添加到第一個p1下面
9、回寫xml
③使用jaxp修改節點
修改第一p1下面的sex內容是男
步驟:
1、創建解析器工廠
2、根據解析器工廠創建解析器
3、解析xml返回document
4、得到sex item方法
5、修改sex里面的值setTextContent方法
6、回寫xml
④使用jaxp刪除節點
刪除<sex>男</sex>節點
步驟:
1、創建解析器工廠
2、根據解析器工廠創建解析器
3、解析xml返回document
4、獲取sex元素
5、獲取sex的父節點,使用getParentNode方法
6、刪除,使用父節點刪除removeChild方法
7、回寫xml
⑤使用jaxp遍歷節點
遍歷節點,把xml中的所有元素名稱打印出來
步驟:
1、創建解析器工廠
2、根據解析器工廠創建解析器
3、解析xml返回document
===使用遞歸實現======
4、得到根節點
5、得到根節點子節點
6、得到根節點子節點的子節點
遍歷方法:
private static void list1(Node node) { //判斷元素類型時候才打印 if (node.getNodeType() == Node.ELEMENT_NODE){ System.out.println(node.getNodeName()); } //得到一層子節點 NodeList list = node.getChildNodes(); //遍歷list for(int i=0; i<list.getLength();i++){ //繼續得到node1的子節點 Node node1 = list.item(i); list1(node1); } }
實例:
xml文檔:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><person> <p1> <name>zhangsan</name> <age>20</age> <sex>女</sex> </p1> <p1> <name>lisi</name> <age>30</age> </p1> </person>}
1 package jaxptest; 2 import org.w3c.dom.*; 3 import javax.xml.parsers.DocumentBuilder; 4 import javax.xml.parsers.DocumentBuilderFactory; 5 import javax.xml.transform.Transformer; 6 import javax.xml.transform.TransformerFactory; 7 import javax.xml.transform.dom.DOMSource; 8 import javax.xml.transform.stream.StreamResult; 9 10 public class TestJaxp { 11 public static void main(String[] args) throws Exception{ 12 String uri = "src/person.xml"; 13 // selectAll(uri); 14 // selectSin(uri); 15 // addSex(uri); 16 // modifySex(uri); 17 // delSex(uri); 18 listElement(uri); 19 } 20 //解析dom方法解析xml文檔方法 21 private static Document jaxpParseXml(String uri) throws Exception { 22 //創建解析器工廠 23 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); 24 //創建解析器 25 DocumentBuilder builder = builderFactory.newDocumentBuilder(); 26 //解析xml返回document 27 Document document = builder.parse(uri); 28 return document; 29 } 30 //回寫xml方法 31 private static void writeBack(Document document,String uri) throws Exception{ 32 TransformerFactory transformerFactory = TransformerFactory.newInstance(); 33 Transformer transformer = transformerFactory.newTransformer(); 34 transformer.transform(new DOMSource(document),new StreamResult(uri)); 35 } 36 //查詢所有name元素的值 37 public static void selectAll(String uri) throws Exception { 38 //查詢所有name元素的值 39 /* 40 * 1、創建解析器工廠 41 * 2、根據解析器工廠創建解析器 42 * 3、解析xml返回document 43 * 4、得到所有的name元素 44 * 5、返回集合,遍歷集合,得到每一個name元素 45 * */ 46 Document document = jaxpParseXml(uri); 47 //得到name元素 48 NodeList list = document.getElementsByTagName("name"); 49 //遍歷集合 50 for(int i=0;i<list.getLength();i++) { 51 Node name1 = list.item(i); 52 //得到name1元素里面的值 53 String s = name1.getTextContent(); 54 System.out.println(s); 55 } 56 } 57 //查詢xml中第一個name元素的值 58 public static void selectSin(String uri) throws Exception{ 59 /* 60 * 1、創建解析器工廠 61 * 2、根據解析器工廠創建解析器 62 * 3、解析xml返回document 63 * 4、得到所有的name元素 64 * 5、使用返回集合,里面方法item,下標獲取具體的元素 65 * 6、得到具體的值,使用getTextContent方法 66 * */ 67 Document document = jaxpParseXml(uri); 68 NodeList list = document.getElementsByTagName("name"); 69 Node name1 = list.item(0); 70 String s1 = name1.getTextContent(); 71 System.out.println(s1); 72 } 73 //在第一個p1下面(末尾)添加<sex>nv</sex> 74 public static void addSex(String uri) throws Exception { 75 /* 76 * 1、創建解析器工廠 77 * 2、根據解析器工廠創建解析器 78 * 3、解析xml返回document 79 * 4、得到第一個p1(得到所有p1,使用item方法下標得到) 80 * 5、創建sex標簽createElementNode 81 * 6、串及文本createTextNode 82 * 7、把文本添加到sex下面appendChild 83 * 8、把sex添加到第一個p1下面 84 * 9、回寫xml 85 * */ 86 Document document = jaxpParseXml(uri); 87 NodeList list = document.getElementsByTagName("p1"); 88 Node p1 = list.item(0); 89 Element sex1 = document.createElement("sex"); 90 Text text = document.createTextNode("女"); 91 sex1.appendChild(text); 92 p1.appendChild(sex1); 93 writeBack(document,uri); 94 } 95 //修改第一p1下面的sex內容是男 96 public static void modifySex(String uri) throws Exception{ 97 /* 98 * 1、創建解析器工廠 99 * 2、根據解析器工廠創建解析器 100 * 3、解析xml返回document 101 * 4、得到sex item方法 102 * 5、修改sex里面的值setTextContent方法 103 * 6、回寫xml 104 * */ 105 Document document = jaxpParseXml(uri); 106 Node sex1 = document.getElementsByTagName("sex").item(0); 107 sex1.setTextContent("男"); 108 writeBack(document,uri); 109 } 110 //刪除<sex>男</sex>節點 111 public static void delSex(String uri) throws Exception{ 112 /* 113 * 1、創建解析器工廠 114 * 2、根據解析器工廠創建解析器 115 * 3、解析xml返回document 116 * 4、獲取sex元素 117 * 5、獲取sex的父節點,使用getParentNode方法 118 * 6、刪除,使用父節點刪除removeChild方法 119 * 7、回寫xml 120 * */ 121 Document document = jaxpParseXml(uri); 122 Node sex1 = document.getElementsByTagName("sex").item(0); 123 Node p1 = sex1.getParentNode(); 124 p1.removeChild(sex1); 125 writeBack(document,uri); 126 } 127 //遍歷節點,把xml中的所有元素名稱打印出來 128 public static void listElement(String uri) throws Exception { 129 /* 130 * 1、創建解析器工廠 131 * 2、根據解析器工廠創建解析器 132 * 3、解析xml返回document 133 * ===使用遞歸實現====== 134 * 4、得到根節點 135 * 5、得到根節點子節點 136 * 6、得到根節點子節點的子節點 137 * */ 138 Document document = jaxpParseXml(uri); 139 //編寫一個方法實現遍歷操作 140 list1(document); 141 } 142 private static void list1(Node node) { 143 //判斷元素類型時候才打印 144 if (node.getNodeType() == Node.ELEMENT_NODE){ 145 System.out.println(node.getNodeName()); 146 } 147 //得到一層子節點 148 NodeList list = node.getChildNodes(); 149 //遍歷list 150 for(int i=0; i<list.getLength();i++){ 151 //繼續得到node1的子節點 152 Node node1 = list.item(i); 153 list1(node1); 154 } 155 }
六、Schema約束
(一)schema介紹
dtd語法:<!ELEMENT 元素名稱 約束>
schema符號xml的語法,xml語句
一個xml中可以有多個schema,多個schema使用名稱空間區分(類似於Java包名)
dtd里面有PCDATA類型,但是在schema里面可以支持更多的數據類型
比如年齡只能是整數,在schema中可以直接定義一個整數類型
schema語法更加復雜,schema目前不能替代dtd
(二)schema的快速入門
創建一個schema文件,后綴名是“.xsd”
根節點<schema>
1、在schema文件中
屬性 xmlns="http://www.w3.org/2001/XMLSchema"
-表示當前xml是一個約束文件
targetNamespace="http://www.itcast.cn/201711111"
-使用schema約束文件,直接通過這個地址引入約束文件
elementFormDefault="qualified"
2、步驟:
①看xml中有多少個元素
<element>
②看簡單元素和復雜元素
如復雜元素:
<complexType> <sequence> 子元素 </sequence> </complexType>
③簡單元素,寫在復雜元素的子元素位置
<element name="person"> <complexType> <sequence> <element name="name" type="string"></element> <element name="age" type="int"></element> </sequence> </complexType> </element>
④在被約束文件里面引入約束文件
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.itcast.cn/201711111" xsi:schemaLocation="http://www.itcast.cn/201711111 1.xsd">
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" --表示xml是一個被約束文件
- xmlns="http://www.itcast.cn/201711111" --是約束文檔中targetNamespace
- xsi:schemaLocation="http://www.itcast.cn/201711111 1.xsd" --targetNamespace 空格 約束文檔的地址
3、XMLSchema復雜元素指示器
-
- <sequence>:表示元素的出現的順序
- <all>:元素只能出現一次
- <choice>:元素只能出現其中的一個
- maxOccurs="unbounded" :表示元素的出現的次數,如:<element name="name" type="string" maxOccurs="unbounded"></element>
- <any></any>:表示任意元素
可以約束屬性
寫在復雜元素里面
寫在</complexType>之前
--
<attribute name="id1" type="int" use="required"></attribute>
-name :屬性名稱
-type:屬性類型int string
-use:屬性是否必須出現 required
4、復雜的schema約束
<company xmlns = "http://www.example.org/company"
xmlns:dept = "http://www.example.org/department"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.example.org/company company.xsd http://www.example.org/department denpartment.xsd">
*引入多個schema文件,可以給每個起一個別名
如:
<employee age="30">
<!-- 部門名稱 -->
<dept:name>100</dept:name>
*想要引入部門的約束文件里的那么,使用部門的別名 detp:元素名稱
<!-- 員工名稱 -->
<name>張三</name>
</employee>
示例:
xml文檔
<?xml version="1.0" encoding="UTF-8" ?> <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.itcast.cn/201711111" xsi:schemaLocation="http://www.itcast.cn/201711111 1.xsd"> <name>zhangsan</name> <age>20</age> </person>
xsd文檔
<?xml version="1.0" encoding="UTF-8" ?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.itcast.cn/201711111" elementFormDefault="qualified"> <element name="person"> <complexType> <sequence> <element name="name" type="string"></element> <element name="age" type="int"></element> </sequence> </complexType> </element> </schema>
七、sax解析
1、sax解析
解析xml有兩種技術 dom和sax
dom方式解析:
根據xml的層級結構在內存中分配一個樹形結構,
把xml的標簽,屬性和文本都封裝成對象
sax方式解析:
采用事件驅動,邊讀邊解析,
在java.xml.parsers包里面
-SAXParser
此類的實例可以從SAXParserFactory.newSAXParser()方法獲得
-parse(File f,DefaultHandler dh)
第一個參數:xml的路徑
第二個參數:事件處理器
-SAXParserFactory
實例newInstance()方法得到
sax執行過程:

2、使用jaxp的sax方式解析xml
sax方式不能實現增刪改操作,只能做查詢操作
打印出整個文檔
-執行parse方法,第一個參數xml路徑,第二個參數是事件處理器
-創建一個類,繼承事件處理器的類,重寫里面的三個方法
獲取到所有的name元素的值
-定義一個成員變量flag=false
-判斷開始方法是否是name元素,如果是name元素,把flag值設置成true
-如果flag值是true,在characters方法里面打印內容
-當執行到結束方法時候,把flag值設置成false
獲取第一個name元素的值
-定義一個成員變量idx=1
-在結束方法時候,idx++
-想要打印出第一個name元素的值,在characters方法里面判斷
實例:
1 import org.xml.sax.Attributes; 2 import org.xml.sax.SAXException; 3 import org.xml.sax.helpers.DefaultHandler; 4 import javax.xml.parsers.SAXParser; 5 import javax.xml.parsers.SAXParserFactory; 6 7 public class TestSax { 8 public static void main(String[] args) throws Exception { 9 /* 10 * 1、創建解析工廠 11 * 2、創建解析器 12 * 3、執行parse方法 13 * 4、自己創建一個類,繼承DefaultHandler 14 * 5、重寫里面的三個方法 15 * */ 16 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); 17 SAXParser saxParser = saxParserFactory.newSAXParser(); 18 saxParser.parse("src/p1.xml",new MyDefault2()); 19 saxParser.parse("src/p1.xml",new MyDefault1()); 20 } 21 } 22 //實現獲取第一個name元素 23 class MyDefault2 extends DefaultHandler { 24 boolean flag = false; 25 int index = 1; 26 @Override 27 public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException { 28 //判斷qName是否是name元素 29 if ("name".equals(qName)) { 30 flag = true ; 31 } 32 } 33 @Override 34 public void characters(char[] ch, int start, int length) throws SAXException { 35 //當flag值是true時候,表示解析到name元素 36 if (flag == true && index == 1){ 37 System.out.println(new String(ch,start,length)); 38 } 39 } 40 @Override 41 public void endElement(String uri, String localName, String qName) throws SAXException { 42 //把flag設置成false,表示name元素結束 43 if ("name".equals(qName)) { 44 flag = false; 45 } 46 index++; 47 } 48 }
//獲取所有name元素 49 class MyDefault1 extends DefaultHandler { 50 @Override 51 public void startElement(String uri, String localName, String qName, 52 Attributes attributes) throws SAXException { 53 System.out.print("<"+qName+">"); 54 } 55 @Override 56 public void characters(char[] ch, int start, int length) throws SAXException { 57 System.out.print(new String(ch,start,length)); 58 } 59 @Override 60 public void endElement(String uri, String localName, String qName) throws SAXException { 61 System.out.print("</"+ qName+">"); 62 } 63 }
xml文件:
<?xml version="1.0" encoding="UTF-8" ?> <person> <p1> <name>zhangsan</name> <age>20</age> </p1> <p1> <name>lisi</name> <age>25</age> </p1> </person>
八、使用dom4j解析xml
1、dom4j
dom4j使用一個組織,針對xml解析,提供解析器dom4j,非javase的一部分,需導入jar包
得到document
SAXReader reader = new SAXReader();
Document document = reader.read(url);
document的父接口是Node
如果在document里面找不到想要的方法,到Node里面去找
document里面的方法getRootElement():獲取根節點返回的是Element
Element也是一個接口,父接口是Node
-Element和Node里面方法
getParent():獲取父節點
addElement:添加標簽
2、使用dom4j對xml進行增刪改查操作
①查詢所有name元素里面的值
步驟:
1、創建解析器
2、得到document
3、得到根節點 getRootElement()
4、得到所有的p1標簽
-element(qname)
-表示獲取標簽下面的第一個子標簽
-qname:標簽名稱
-elements(qname)
-獲取標簽下面是這個名稱的所有子標簽(一層)
-qname:標簽名稱
-elements()
-獲取標簽下面的所有一層子標簽
5、得到name
6、得到name里面的值
②使用dom4j對xml進行增刪改查操作示例以及方法的封裝
xml文檔:
<?xml version="1.0" encoding="UTF-8"?> <person> <p1 id1="aaa"> <name>zhangsan</name> <age>30</age> <sex>女</sex> </p1> <p1> <name>lisi</name> <age>25</age> </p1> </person>
java文檔:
1 package testDom4j; 2 3 import dom4jutils.Dom4jUtils; 4 import org.dom4j.Document; 5 import org.dom4j.DocumentHelper; 6 import org.dom4j.Element; 7 import org.dom4j.io.OutputFormat; 8 import org.dom4j.io.SAXReader; 9 import org.dom4j.io.XMLWriter; 10 11 import java.io.FileOutputStream; 12 import java.util.List; 13 14 public class TestDom4j { 15 public static void main(String[] args) throws Exception { 16 // selectName(); 17 // selectSin(); 18 // selectSecond(); 19 // addSex(); 20 // addAgeBefore(); 21 // modifyAge(); 22 // deleteSchool(); 23 getValues(); 24 } 25 //查詢xml中所有name元素的值 26 public static void selectName() throws Exception{ 27 /* 28 * 1、創建解析器 29 * 2、得到document 30 * 3、得到根節點 getRootElement() 返回Element 31 * 4、得到所有的p1標簽 32 * -elements("p1") 返回Element 33 * 5、得到name 34 * -在p1下面執行element("name")的方法返回Element 35 * 6、得到name里面的值 36 * -getText方法得到值 37 * */ 38 //創建解析器 39 SAXReader reader = new SAXReader(); 40 //得到document 41 Document document = reader.read("src/p1.xml"); 42 //得到根節點 43 Element root = document.getRootElement(); 44 //得到p1 45 List<Element> list = root.elements("p1"); 46 //遍歷list 47 for(Element element : list) { 48 //element是每一個p1 49 //得到p1下面的name元素 50 Element name1 = element.element("name") ; 51 //得到name里面的值 52 String s = name1.getText(); 53 System.out.println(s); 54 } 55 } 56 57 //獲取得到第一個name元素的值 58 public static void selectSin() throws Exception { 59 /* 60 * 1、創建解析器 61 * 2、得到document 62 * 3、得到根節點 63 * 4、得到第一個p1標簽 64 * 5、得到p1下面的name元素 65 * 6、得到name里面的值 66 * */ 67 Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH); 68 Element root = document.getRootElement(); 69 Element p1 = root.element("p1"); 70 Element name1 = p1.element("name"); 71 System.out.println(name1.getText()); 72 } 73 //獲取得到第二個name元素的值 74 public static void selectSecond() throws Exception { 75 /* 76 * 1、創建解析器 77 * 2、得到document 78 * 3、得到根節點 79 * 4、得到所有的p1 80 * 5、遍歷得到第二p1 81 * 6、得到第二個p1下面的name 82 * 7、得到name的值 83 * */ 84 Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH); 85 Element root = document.getRootElement(); 86 List<Element> list = root.elements("p1"); 87 Element p2 = list.get(1); 88 Element name2 = p2.element("name"); 89 System.out.println(name2.getText()); 90 } 91 92 //在第一個p1標簽末尾添加一個元素<sex>女</sex> 93 public static void addSex() throws Exception { 94 /* 95 * 1、創建解析器 96 * 2、得到document 97 * 3、得到根節點 98 * 4、獲取第一個p1 99 * 5、在p1下面添加元素 100 * 6、在添加完成之后的元素下面添加文本 101 * 7、回寫xml 102 * */ 103 Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH); 104 Element root = document.getRootElement(); 105 //得到第一個p1元素 106 Element p1 = root.element("p1"); 107 //在p1下面直接添加元素 108 Element sex1 = p1.addElement("sex"); 109 //在sex下面添加文本 110 sex1.setText("女"); 111 //回寫xml 112 OutputFormat format = OutputFormat.createPrettyPrint(); 113 XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("src/p1.xml"),format); 114 xmlWriter.write(document); 115 xmlWriter.close(); 116 } 117 118 //在特定位置添加元素,在第一個p1下面的age標簽之前添加<school>ecit</school> 119 public static void addAgeBefore() throws Exception { 120 /* 121 * 1、創建解析器 122 * 2、得到document 123 * 3、得到根節點 124 * 4、獲取第一個p1 125 * 5、在p1下面所有的元素 126 * 6、在指定位置添加元素 127 * 7、回寫xml 128 * */ 129 //獲得document 130 Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH); 131 Element root = document.getRootElement(); 132 Element p1 = root.element("p1") ; 133 //獲取p1下所有元素的集合 134 List<Element> list = p1.elements(); 135 //創建元素 136 Element school = DocumentHelper.createElement("school"); 137 school.setText("ecit"); 138 //在指定位置添加元素 139 list.add(1,school); 140 //回寫xml 141 Dom4jUtils.xmlWriters(Dom4jUtils.PATH,document); 142 } 143 //修改節點的操作,修改第一個p1下面的age元素值為30 144 public static void modifyAge() throws Exception { 145 /* 146 * 1、得到document 147 * 2、得到根節點 148 * 3、獲取第一個p1 149 * 4、得到p1下面的age 150 * 5、修改為30 151 * 6、回寫xml 152 * */ 153 Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH); 154 Element root = document.getRootElement(); 155 Element p1 = root.element("p1"); 156 Element age = p1.element("age"); 157 //使用setText()方法修改文本內容 158 age.setText("30"); 159 Dom4jUtils.xmlWriters(Dom4jUtils.PATH,document); 160 } 161 //使用dom4j實現刪除節點的操作,刪除第一個p1下面的<school>ecit<school>元素 162 public static void deleteSchool() throws Exception{ 163 /* 164 * 1、得到document 165 * 2、得到根節點 166 * 3、獲取第一個p1 167 * 4、得到第一個p1下面的school 168 * 5、刪除(使用p1刪除school) 169 * -得到school的父節點 170 * -第一種直接得到p1 171 * -使用方法getParent方法 172 * -在p1上面執行remove方法刪除節點 173 * 6、回寫xml 174 * */ 175 Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH); 176 Element root = document.getRootElement(); 177 Element p1 = root.element("p1"); 178 Element sch = p1.element("school"); 179 //通過父節點刪除 180 p1.remove(sch); 181 Dom4jUtils.xmlWriters(Dom4jUtils.PATH,document); 182 } 183 //使用dom4j獲取屬性的操作,獲取第一個p1的屬性id1的值 184 public static void getValues() throws Exception { 185 /* 186 * 1、得到document 187 * 2、得到根節點 188 * 3、獲取第一個p1 189 * 4、得到第一個p1的值 190 * */ 191 Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH); 192 Element root = document.getRootElement(); 193 Element p1 = root.element("p1"); 194 String value = p1.attributeValue("id1"); 195 System.out.println(value); 196 } 197 }
1 package dom4jutils; 2 3 import org.dom4j.Document; 4 import org.dom4j.DocumentException; 5 import org.dom4j.io.OutputFormat; 6 import org.dom4j.io.SAXReader; 7 import org.dom4j.io.XMLWriter; 8 9 import java.io.FileOutputStream; 10 import java.io.IOException; 11 12 public class Dom4jUtils { 13 public static final String PATH="src/p1.xml"; 14 //返回document 15 public static Document getDocument(String path) { 16 try { 17 //創建解析器 18 SAXReader reader = new SAXReader(); 19 //得到document 20 Document document = reader.read(path); 21 return document; 22 } catch (DocumentException e) { 23 e.printStackTrace(); 24 } 25 return null; 26 } 27 //回寫xml 28 public static void xmlWriters(String path,Document document) { 29 try { 30 OutputFormat format = OutputFormat.createPrettyPrint(); 31 XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(path),format); 32 xmlWriter.write(document); 33 xmlWriter.close(); 34 } catch (IOException e) { 35 e.printStackTrace(); 36 } 37 } 38 }
3、使用dom4j支持xpath的操作
可以直接獲取到某個元素
第一種形式
/AAA/DDD/BBB:表示一層一層的,AAA下面DDD下面的BBB
第二種形式
//BBB:表示和這個名稱相同,只要是名稱是BBB,都得到
第三種形式
/* :所有元素
第四種形式
** BBB[1] :表示第一個BBB元素
** BBB[last()] :表示最后一個BBB元素
第五種形式
** //BBB[@id]:表示只要BBB元素上面有id屬性,都得到
第六種形式
** //BBB[@id='b1'] :表示元素名稱是BBB,在BBB上面有id屬性,並且id的屬性值是b1
①具體操作:
默認情況下,dom4j不支持xpath,需導入jaxen-1.1-beta-6.jar
在dom4j里面提供了兩個方法,用來支持xpath
-selectNodes("xpath表達式") ,獲取多個節點
-selectionSingleNode(“xpath”表達式),獲取一個節點
*使用xpath實現:查詢xml中所有name元素的值
-所有name元素的xpath表示://name
-使用selectionNodes(“//name”);
代碼和步驟:
/* * 1、得到document * 2、直接使用selectNodes("//name")方法的到所有的name元素 * */ //得到document Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH); //使用selectNodes("//name")方法得到所有的name元素 List<Node> list = document.selectNodes("//name"); for (Node node : list){ //node是每一個name元素 String s = node.getText(); System.out.println(s); }
*使用xpath實現:獲取第一個p1下面的name的值
-//p1[@id1='aaa']/name
-使用到selectSingleNode(“//p1[@id1='aaa']/name”)
九、實現簡單的學生管理系統
1、xml文檔,用於儲存信息:
<?xml version="1.0" encoding="UTF-8"?> <student> <stu> <id>100</id> <name>zhangsan</name> <age>20</age> </stu> <stu> <id>101</id> <name>zhangsan</name> <age>30</age> </stu> </student>
2、構建service jar包用於查詢、添加、刪除方法的存儲
1 package service; 2 3 import org.dom4j.Document; 4 import org.dom4j.Element; 5 import org.dom4j.Node; 6 import vo.Student; 7 import java.util.List; 8 9 public class StuService { 10 11 //查詢 根據id查詢學生信息 12 public static Student getStu(String id) throws Exception { 13 /* 14 * 1、創建解析器 15 * 2、得到document 16 * 3、獲取所有的id 17 * 18 * 4、返回list集合,遍歷list集合 19 * 5、得到每一個id的節點 20 * 6、id節點的值 21 * 7、判斷id的值和傳遞的id值是否相同 22 * 8、如果相同,先獲取到id的父節點stu 23 * 9、通過stu獲取到name age值 24 * */ 25 Document document = StudentUtils.getDocument(StudentUtils.PATH); 26 List<Node> list = document.selectNodes("//id"); 27 Student student = new Student(); 28 for (Node node : list) { 29 String idv = node.getText(); 30 if (idv.equals(id)) { 31 Element stu = node.getParent(); 32 String namev = stu.element("name").getText(); 33 String agev = stu.element("age").getText(); 34 student.setId(idv); 35 student.setName(namev); 36 student.setAge(agev); 37 } 38 } 39 return student; 40 } 41 //增加 42 public static void addStu(Student student) throws Exception { 43 /* 44 * 1、創建解析器 45 * 2、得到document 46 * 3、獲得根節點 47 * 4、在根節點上面創建stu標簽 48 * 5、在stu標簽上面依次添加id、name、age 49 * 6、在id name age上面依次添加值 50 * */ 51 Document document = StudentUtils.getDocument(StudentUtils.PATH); 52 Element root = document.getRootElement(); 53 Element stu = root.addElement("stu"); 54 Element id1 = stu.addElement("id"); 55 Element name1 = stu.addElement("name"); 56 Element age1 = stu.addElement("age"); 57 id1.setText(student.getId()); 58 name1.setText(student.getName()); 59 age1.setText(student.getAge()); 60 StudentUtils.xmlWriters(StudentUtils.PATH,document); 61 } 62 //刪除,根據學生的id刪除 63 public static void delStu(String id) throws Exception{ 64 /* 65 * 1、創建解析器 66 * 2、得到document 67 * 3、獲取所有的id 68 * 使用xpath //id 返回list集合 69 * 4、遍歷list集合 70 * 5、判斷集合里面的id和傳遞的id是否相同 71 * 6、如果相同,把id所在的stu刪除 72 * */ 73 Document document = StudentUtils.getDocument(StudentUtils.PATH); 74 List<Node> list = document.selectNodes("//id"); 75 for (Node node : list) { 76 String idv = node.getText(); 77 if (idv.equals(id)) { 78 Element stu = node.getParent(); 79 Element student = stu.getParent(); 80 student.remove(stu); 81 } 82 } 83 StudentUtils.xmlWriters(StudentUtils.PATH,document); 84 } 85 }
StuService操作類:
1 package service; 2 import org.dom4j.Document; 3 import org.dom4j.DocumentException; 4 import org.dom4j.io.OutputFormat; 5 import org.dom4j.io.SAXReader; 6 import org.dom4j.io.XMLWriter; 7 import java.io.FileOutputStream; 8 import java.io.IOException; 9 10 public class StudentUtils { 11 public static final String PATH="src/student.xml"; 12 //返回document 13 public static Document getDocument(String path) { 14 try { 15 //創建解析器 16 SAXReader reader = new SAXReader(); 17 //得到document 18 Document document = reader.read(path); 19 return document; 20 } catch (DocumentException e) { 21 e.printStackTrace(); 22 } 23 return null; 24 } 25 //回寫xml 26 public static void xmlWriters(String path,Document document) { 27 try { 28 OutputFormat format = OutputFormat.createPrettyPrint(); 29 XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(path),format); 30 xmlWriter.write(document); 31 xmlWriter.close(); 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 } 36 }
3、構建對象的封裝包,用於對象設置與獲取。
1 package vo; 2 3 public class Student { 4 private String id; 5 private String name; 6 private String age; 7 public String getId() {return id; } 8 public String getName() {return name; } 9 public String getAge() { return age;} 10 public void setId(String id) {this.id = id;} 11 public void setName(String name) { this.name = name;} 12 public void setAge(String age) { this.age = age;} 13 14 @Override 15 public String toString() { 16 return "Student{" + 17 "id='" + id + '\'' + 18 ", name='" + name + '\'' + 19 ", age='" + age + '\'' + 20 '}'; 21 } 22 }
4、構建測試包
1 package test; 2 3 import service.StuService; 4 import vo.Student; 5 6 public class TestStu { 7 public static void main(String[] args) throws Exception{ 8 testSelect(); 9 // testAdd(); 10 // testDel(); 11 } 12 //測試查詢方法 13 public static void testSelect() throws Exception { 14 Student stu = StuService.getStu("100"); 15 System.out.println(stu.toString()); 16 } 17 //測試添加方法 18 public static void testAdd() throws Exception { 19 Student stu = new Student(); 20 stu.setId("103"); 21 stu.setName("wanwu"); 22 stu.setAge("25"); 23 StuService.addStu(stu); 24 } 25 //測試添加方法 26 public static void testDel() throws Exception{ 27 StuService.delStu("103"); 28 } 29 }