schema約束 SAXP和DOM解析,案例 Dom4J xpath總結
1、schema約束
dtd語法: <!ELEMENT 元素名稱 約束>
** schema符合xml的語法,xml語句
** 一個xml中可以有多個schema,多個schema使用名稱空間區分(類似於java包名)
** dtd裡面有PCDATA型別,但是在schema裡面可以支援更多的資料型別
*** 比如 年齡 只能是整數,在schema可以直接定義一個整數型別
*** schema語法更加複雜,schema目前不能替代dtd
2、schema的快速入門
* 建立一個schema檔案 字尾名是 .xsd
** 根節點 <schema>
** 在schema檔案裡面
** 屬性 xmlns="http://www.w3.org/2001/XMLSchema"
- 表示當前xml檔案是一個約束檔案
** targetNamespace="http://www.itcast.cn/20151111"
- 使用schema約束檔案,直接通過這個地址引入約束檔案
** elementFormDefault="qualified"
步驟
(1)看xml中有多少個元素
<element>
(2)看簡單元素和複雜元素
* 如果複雜元素
<complexType>
<sequence>
子元素
</sequence>
</complexType>
(3)簡單元素,寫在複雜元素的
<element name="person">
<complexType>
<sequence>
<element name="name" type="string"></element>
<element name="age" type="int"></element>
</sequence>
</complexType>
</element>
(4)在被約束檔案裡面引入約束檔案
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.itcast.cn/20151111"
xsi:schemaLocation="http://www.itcast.cn/20151111 1.xsd">
** xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-- 表示xml是一個被約束檔案
** xmlns="http://www.itcast.cn/20151111"
-- 是約束文件裡面 targetNamespace
** xsi:schemaLocation="http://www.itcast.cn/20151111 1.xsd">
-- targetNamespace 空格 約束文件的地址路徑
* <sequence>:表示元素的出現的順序
<all>: 元素只能出現一次
<choice>:元素只能出現其中的一個
maxOccurs="unbounded": 表示元素的出現的次數
<any></any>:表示任意元素
* 可以約束屬性
* 寫在複雜元素裡面
***寫在 </complexType>之前
--
<attribute name="id1" type="int" use="required"></attribute>
- name: 屬性名稱
- type:屬性型別 int stirng
- use:屬性是否必須出現 required
* 複雜的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 department.xsd"
>
* 引入多個schema檔案,可以給每個起一個別名
<employee age="30">
<!-- 部門名稱 -->
<dept:name>100</dept:name>
* 想要引入部門的約束檔案裡面的name,使用部門的別名 detp:元素名稱
<!-- 員工名稱 -->
<name>王曉曉</name>
</employee>
3、sax解析的原理(********)
* 解析xml有兩種技術 dom 和sax
* 根據xml的層級結構在記憶體中分配一個樹形結構
** 把xml中標籤,屬性,文字封裝成物件
* sax方式:事件驅動,邊讀邊解析
* 在javax.xml.parsers包裡面
** SAXParser
此類的例項可以從 SAXParserFactory.newSAXParser() 方法獲得
- parse(File f, DefaultHandler dh)
* 兩個引數
** 第一個引數:xml的路徑
** 事件處理器
** SAXParserFactory
例項 newInstance() 方法得到
* 畫圖分析一下sax執行過程
* 當解析到開始標籤時候,自動執行startElement方法
* 當解析到文字時候,自動執行characters方法
* 當解析到結束標籤時候,自動執行endElement方法
4、使用jaxp的sax方式解析xml(**會寫***)
* sax方式不能實現增刪改操作,只能做查詢操作
** 打印出整個文件
*** 執行parse方法,第一個引數xml路徑,第二個引數是 事件處理器
*** 建立一個類,繼承事件處理器的類,
***重寫裡面的三個方法
* 獲取到所有的name元素的值
** 定義一個成員變數 flag= false
** 判斷開始方法是否是name元素,如果是name元素,把flag值設定成true
** 如果flag值是true,在characters方法裡面列印內容
** 當執行到結束方法時候,把flag值設定成false
* 獲取第一個name元素的值
** 定義一個成員變數 idx=1
** 在結束方法時候,idx+1 idx++
** 想要打印出第一個name元素的值,
- 在characters方法裡面判斷,
-- 判斷flag=true 並且 idx==1,在列印內容
5、使用dom4j解析xml
* dom4j,是一個組織,針對xml解析,提供解析器 dom4j
* dom4j不是javase的一部分,想要使用第一步需要怎麼做?
*** 匯入dom4j提供jar包
-- 建立一個資料夾 lib
-- 複製jar包到lib下面,
-- 右鍵點選jar包,build path -- add to build path
-- 看到jar包,變成奶瓶樣子,表示匯入成功
* 得到document
SAXReader reader = new SAXReader();
Document document = reader.read(url);
* document的父介面是Node
* 如果在document裡面找不到想要的方法,到Node裡面去找
* document裡面的方法 getRootElement() :獲取根節點 返回的是Element
* Element也是一個介面,父介面是Node
- Element和Node裡面方法
** getParent():獲取父節點
** addElement:新增標籤
* element(qname)
** 表示獲取標籤下面的第一個子標籤
** qname:標籤的名稱
* elements(qname)
** 獲取標籤下面是這個名稱的所有子標籤(一層)
** qname:標籤名稱
* elements()
** 獲取標籤下面的所有一層子標籤
6、使用dom4j查詢xml
* 解析是從上到下解析
* 查詢所有name元素裡面的值
/*
1、建立解析器
2、得到document
3、得到根節點 getRootElement() 返回Element
4、得到所有的p1標籤
* elements("p1") 返回list集合
* 遍歷list得到每一個p1
5、得到name
* 在p1下面執行 element("name")方法 返回Element
6、得到name裡面的值
* getText方法得到值
*/
* 查詢第一個name元素的值
/*
* 1、建立解析器
* 2、得到document
* 3、得到根節點
*
* 4、得到第一個p1元素
** element("p1")方法 返回Element
* 5、得到p1下面的name元素
** element("name")方法 返回Element
* 6、得到name元素裡面的值
** getText方法
* */
* 獲取第二個name元素的值
/*
* 1、建立解析器
* 2、得到document
* 3、得到根節點
*
* 4、得到所有的p1
** 返回 list集合
* 5、遍歷得到第二個p1
** 使用list下標得到 get方法,集合的下標從 0 開始,想要得到第二個值,下標寫 1
* 6、得到第二個p1下面的name
** element("name")方法 返回Element
* 7、得到name的值
** getText方法
* */
7、使用dom4j實現新增操作
* 在第一個p1標籤末尾新增一個元素 <sex>nv</sex>
* 步驟
/*
* 1、建立解析器
* 2、得到document
* 3、得到根節點
*
* 4、獲取到第一個p1
* 使用element方法
* 5、在p1下面新增元素
* 在p1上面直接使用 addElement("標籤名稱")方法 返回一個Element
* 6、在新增完成之後的元素下面新增文字
* 在sex上直接使用 setText("文字內容")方法
* 7、回寫xml
* 格式化 OutputFormat,使用 createPrettyPrint方法,表示一個漂亮的格式
* 使用類XMLWriter 直接new 這個類 ,傳遞兩個引數
*** 第一個引數是xml檔案路徑 new FileOutputStream("路徑")
*** 第二個引數是格式化類的值
* */
8、使用dom4j實現在特定位置新增元素
* 在第一個p1下面的age標籤之前新增 <school>ecit.edu.cn</schlool>
* 步驟
/*
* 1、建立解析器
* 2、得到document
* 3、得到根節點
* 4、獲取到第一個p1
*
* 5、獲取p1下面的所有的元素
* ** elements()方法 返回 list集合
* ** 使用list裡面的方法,在特定位置新增元素
* ** 首先建立元素 在元素下面建立文字
- 使用DocumentHelper類方法createElement建立標籤
- 把文字新增到標籤下面 使用 setText("文字內容")方法
* *** list集合裡面的 add(int index, E element)
* - 第一個引數是 位置 下標,從0開始
* - 第二個引數是 要新增的元素
* 6、回寫xml
* */
** 可以對得到document的操作和 回寫xml的操作,封裝成方法
** 也可以把傳遞的檔案路徑,封裝成一個常量
*** 好處:可以提高開發速度,可以提交程式碼可維護性
- 比如想要修改檔案路徑(名稱),這個時候只需要修改常量的值就可以了,其他程式碼不需要做任何改變
9、使用dom4j實現修改節點的操作
* 修改第一個p1下面的age元素的值 <age>30</age>
* 步驟
/*
* 1、得到document
* 2、得到根節點,然後再得到第一個p1元素
* 3、得到第一個p1下面的age
element("")方法
* 4、修改值是 30
* * 使用setText("文字內容")方法
* 5、回寫xml
*
* */
10、使用dom4j實現刪除節點的操作
* 刪除第一個p1下面的<school>ecit</school>元素
* 步驟
/*
* 1、得到document
* 2、得到根節點
* 3、得到第一個p1標籤
* 4、得到第一個p1下面的school元素
* 5、刪除(使用p1刪除school)
* * 得到school的父節點
- 第一種直接得到p1
- 使用方法 getParent方法得到
* 刪除操作
- 在p1上面執行remove方法刪除節點
* 6、回寫xml
* */
11、使用dom4j獲取屬性的操作
* 獲取第一個p1裡面的屬性id1的值
* 步驟
/*
* 1、得到document
* 2、得到根節點
* 3、得到第一個p1元素
* 4、得到p1裡面的屬性值
- p1.attributeValue("id1");
- 在p1上面執行這個方法,裡面的引數是屬性名稱
* */
12、使用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
13、使用dom4j支援xpath具體操作
** 預設的情況下,dom4j不支援xpath
** 如果想要在dom4j裡面是有xpath
* 第一步需要,引入支援xpath的jar包,使用 jaxen-1.1-beta-6.jar
** 需要把jar包匯入到專案中
** 在dom4j裡面提供了兩個方法,用來支援xpath
*** selectNodes("xpath表示式")
- 獲取多個節點
*** selectSingleNode("xpath表示式")
- 獲取一個節點
** 使用xpath實現:查詢xml中所有name元素的值
** 所有name元素的xpath表示: //name
** 使用selectNodes("//name");
** 程式碼和步驟
/*
* 1、得到document
* 2、直接使用selectNodes("//name")方法得到所有的name元素
*
* */
//得到document
Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
//使用selectNodes("//name")方法得到所有的name元素
List<Node> list = document.selectNodes("//name");
//遍歷list集合
for (Node node : list) {
//node是每一個name元素
//得到name元素裡面的值
String s = node.getText();
System.out.println(s);
}
** 使用xpath實現:獲取第一個p1下面的name的值
* //p1[@id1='aaaa']/name
* 使用到 selectSingleNode("//p1[@id1='aaaa']/name")
* 步驟和程式碼
/*
* 1、得到document
* 2、直接使用selectSingleNode方法實現
* - xpath : //p1[@id1='aaaa']/name
* */
//得到document
Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
//直接使用selectSingleNode方法實現
Node name1 = document.selectSingleNode("//p1[@id1='aaaa']/name"); //name的元素
//得到name裡面的值
String s1 = name1.getText();
System.out.println(s1);
14、實現簡單的學生管理系統
** 使用xml當做資料,儲存學生資訊
** 建立一個xml檔案,寫一些學生資訊
** 增加操作
/*
* 1、建立解析器
* 2、得到document
* 3、獲取到根節點
* 4、在根節點上面建立stu標籤
* 5、在stu標籤上面依次新增id name age
** addElement方法新增
* 6、在id name age上面依次新增值
* ** setText方法
* 7、回寫xml
* */
** 刪除操作(根據id刪除)
/*
* 1、建立解析器
* 2、得到document
*
* 3、獲取到所有的id
* 使用xpath //id 返回 list集合
* 4、遍歷list集合
* 5、判斷集合裡面的id和傳遞的id是否相同
* 6、如果相同,把id所在的stu刪除
*
* */
** 查詢操作(根據id查詢)
/*
* 1、建立解析器
* 2、得到document
*
* 3、獲取到所有的id
* 4、返回的是list集合,遍歷list集合
* 5、得到每一個id的節點
* 6、id節點的值
* 7、判斷id的值和傳遞的id值是否相同
* 8、如果相同,先獲取到id的父節點stu
* 9、通過stu獲取到name age值
** 把這些值封裝到一個物件裡面 返回物件
*
* */