來自拉鉤教育-JAVA就業(yè)集訓(xùn)營
1. XML基本介紹
1.1 概述
-
XML即可擴展標(biāo)記語言(Extensible Markup Language)
- W3C在1998年2月發(fā)布1.0版本,2004年2月又發(fā)布1.1版本,但因為1.1版本不能向下兼容1.0版本,所以1.1沒有人用。同時,在2004年2月W3C又發(fā)布了1.0版本的第三版。我們要學(xué)習(xí)的還是1.0版本 !
-
特點
- 可擴展的, 標(biāo)簽都是自定義的
- 語法十分嚴(yán)格
1.2 XML的作用
- XML能做什么?
| 功能 | 說明 |
|---|---|
| 存儲數(shù)據(jù) | 通常,我們在數(shù)據(jù)庫中存儲數(shù)據(jù)。不過,如果希望數(shù)據(jù)的可移植性更強,我們可以把數(shù)據(jù)存儲 XML 文件中 |
| 配置文件 | 作為各種技術(shù)框架的配置文件使用 (最多) |
| 在網(wǎng)絡(luò)中傳輸 | 客戶端可以使用XML格式向服務(wù)器端發(fā)送數(shù)據(jù),服務(wù)器接收到xml格式數(shù)據(jù),進(jìn)行解析 |
2. XML的語法
2.1 XML文檔聲明格式
- 文檔聲明必須為結(jié)束;
- 文檔聲明必寫在第一行;
- 語法格式:
<?xml version="1.0" encoding="UTF-8"?>
- 屬性說明:
- versioin:指定XML文檔版本。必須屬性,因為我們不會選擇1.1,只會選擇1.0;
- encoding:指定當(dāng)前文檔的編碼??蛇x屬性,默認(rèn)值是utf-8;
2.2 元素
- Element 元素: 是XML文檔中最重要的組成部分
- 元素的命名規(guī)則
- 不能使用空格,不能使用冒號
- xml 標(biāo)簽名稱區(qū)分大小寫
- XML 必須有且只有一個根元素
- 語法格式:
<users><users>
- XML 必須有且只有一個根元素,它是所有其他元素的父元素,比如以下實例中 users 就是根元素:
<?xml version="1.0" encoding="utf-8" ?>
<users>
</users>
- 普通元素的結(jié)構(gòu)開始標(biāo)簽、元素體、結(jié)束標(biāo)簽組成。
<hello> 大家好 </hello>
- 元素體:元素體可以是元素,也可以是文本
<hello>
<a>你好</a>
</hello>
- 空元素:空元素只有開始標(biāo)簽,而沒有結(jié)束標(biāo)簽,但元素必須自己閉合
<close/>
2.3 屬性
<bean id="" class=""> </bean>
- 屬性是元素的一部分,它必須出現(xiàn)在元素的開始標(biāo)簽中
- 屬性的定義格式:屬性名=屬性值,其中屬性值必須使用單引或雙引
- 一個元素可以有0~N個屬性,但一個元素中不能出現(xiàn)同名屬性
- 屬性名不能使用空格、冒號等特殊字符,且必須以字母開頭
2.4 注釋
XML的注釋,以“ ”結(jié)束。注釋內(nèi)容會被XML解析器忽略!
2.5 使用XML 描述數(shù)據(jù)表中的數(shù)據(jù)

image-20210228162952954.png
<?xml version="1.0" encoding="UTF-8" ?>
<employees>
<employee eid="2">
<ename>林黛玉</ename>
<age>20</age>
<sex>女</sex>
<salary>5000</salary>
<empdate>2019-03-14</empdate>
</employee>
<employee eid="3">
<ename>杜甫</ename>
<age>40</age>
<sex>男</sex>
<salary>15000</salary>
<empdate>2010-01-01</empdate>
</employee>
</employees>
3. XML約束
- 在XML技術(shù)里,可以編寫一個文檔來約束一個XML文檔的書寫規(guī)范,這稱之為XML約束。
- 常見的xml約束:
- DTD
- Schema
- 作為程序員只要掌握兩點
- 會閱讀
- 會引入
- 不用自己編寫

image-20210228163002242.png
3.1 DTD約束
DTD(Document Type Definition),文檔類型定義,用來約束XML文檔。規(guī)定XML文檔中元素的名稱,子元素的名稱及順序,元素的屬性等。
3.1.1 編寫DTD
開發(fā)中,我們不會自己編寫DTD約束文檔
常情況我們都是通過框架提供的DTD約束文檔,編寫對應(yīng)的XML文檔。常見框架使用DTD約束有:Struts2、hibernate等。
創(chuàng)建約束文件 student.dtd
<!ELEMENT students (student+) >
<!ELEMENT student (name,age,sex)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ATTLIST student number ID #REQUIRED>
<!--
ELEMENT: 用來定義元素
students (student+) : 代表根元素 必須是 <students>
student+ : 根標(biāo)簽中至少有一個 student子元素, + 代表至少一個
student (name,age,sex): student 標(biāo)簽中包含的子元素,按順序出現(xiàn)
#PCDATA: 是普通文本內(nèi)容
ATTLIST: 用來定義屬性
student number ID student子元素中 有一個ID屬性叫做 number
#REQUIRED 是必須填寫的
ID: 唯一 值只能是字母或者下劃線開頭
-->
3.1.2 引入DTD
-
引入dtd文檔到xml文檔中,兩種方式
- 內(nèi)部dtd:將約束規(guī)則定義在xml文檔中
- 外部dtd:將約束的規(guī)則定義在外部的dtd文件中
本地:<!DOCTYPE 根標(biāo)簽名 SYSTEM "dtd文件的位置">
網(wǎng)絡(luò):<!DOCTYPE 根標(biāo)簽名 PUBLIC "dtd文件名字" "dtd文件的位置URL">
student.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE students SYSTEM "student.dtd">
<students>
<student number="s1">
<name>小斌</name>
<age>22</age>
<sex>男</sex>
</student>
<student number="s2">
<name>廣坤</name>
<age>55</age>
<sex>男</sex>
</student>
</students>
3.2 Schema約束
3.2.1 什么是Schema
- Schema是新的XML文檔約束, 比DTD強大很多,是DTD 替代者;
- Schema本身也是XML文檔,但Schema文檔的擴展名為xsd,而不是xml。
- Schema 功能更強大,內(nèi)置多種簡單和復(fù)雜的數(shù)據(jù)類型
- Schema 支持命名空間 (一個XML中可以引入多個約束文檔)
3.2.2 Schema約束示例
student.xsd
<?xml version="1.0"?>
<xsd:schema xmlns="http://www.lagou.com/xml"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.lagou.com/xml"
elementFormDefault="qualified">
<xsd:element name="students" type="studentsType"/>
<xsd:complexType name="studentsType">
<xsd:sequence>
<xsd:element name="student" type="studentType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="studentType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="ageType" />
<xsd:element name="sex" type="sexType" />
</xsd:sequence>
<xsd:attribute name="number" type="numberType" use="required"/>
</xsd:complexType>
<xsd:simpleType name="sexType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="male"/>
<xsd:enumeration value="female"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ageType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="200"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="numberType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="hehe_\d{4}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
**Xml Schema的根元素: **

image-20210228163013307.png
3.2.3 XML引入Schema約束
xml中引入schema約束的步驟:
- 查看schema文檔,找到根元素,在xml中寫出來
<?xml version="1.0" encoding="UTF-8" ?>
<students>
</students>
- 根元素來自哪個命名空間。使用xmlns指令來聲明
<?xml version="1.0" encoding="UTF-8" ?>
<students xmlns="http://www.lagou.com/xml" >
</students>
- 引入 w3c的標(biāo)準(zhǔn)命名空間, 復(fù)制即可
<?xml version="1.0" encoding="UTF-8" ?>
<students
xmlns="http://www.lagou.com/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
</students>
- 引入的命名空間跟哪個xsd文件對應(yīng)?
使用schemaLocation來指定:兩個取值:第一個為命名空間 第二個為xsd文件的路徑
<?xml version="1.0" encoding="UTF-8" ?>
<students
xmlns="http://www.lagou.com/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.lagou.com/xml student.xsd"
>
</students>
- 命名空間
指的是一個環(huán)境,所用的標(biāo)簽來自于哪個環(huán)境定義的。
- student.xml
<?xml version="1.0" encoding="UTF-8" ?>
<students xmlns="http://www.lagou.com/xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.lagou.com/xml student.xsd" >
<student number="hehe_1234">
<name>張百萬</name>
<age>25</age>
<sex>female</sex>
</student>
<student number="hehe_0000">
<name>小斌</name>
<age>20</age>
<sex>male</sex>
</student>
</students>
4. XML 解析
4.1 解析概述
- 當(dāng)將數(shù)據(jù)存儲在XML后,我們就希望通過程序獲得XML的內(nèi)容。如果我們使用Java基礎(chǔ)所學(xué)習(xí)的IO知識是可以完成的,不過你需要非常繁瑣的操作才可以完成,且開發(fā)中會遇到不同問題(只讀、讀寫)。人們?yōu)椴煌瑔栴}提供不同的解析方式,并提交對應(yīng)的解析器,方便開發(fā)人員操作XML。
4.2 XML解析方式
- 開發(fā)中比較常見的解析方式有兩種,如下:
- DOM:要求解析器把整個XML文檔裝載到內(nèi)存,并解析成一個Document對象。
- 優(yōu)點:元素與元素之間保留結(jié)構(gòu)關(guān)系,故可以進(jìn)行增刪改查操作。
- 缺點:XML文檔過大,可能出現(xiàn)內(nèi)存溢出顯現(xiàn)。
- SAX:是一種速度更快,更有效的方法。它逐行掃描文檔,一邊掃描一邊解析。并以事件驅(qū)動的方式進(jìn)行具體解析,每執(zhí)行一行,都將觸發(fā)對應(yīng)的事件。(了解)
- 優(yōu)點:占用內(nèi)存少 處理速度快,可以處理大文件
- 缺點:只能讀,逐行后將釋放資源。
- DOM:要求解析器把整個XML文檔裝載到內(nèi)存,并解析成一個Document對象。

image-20210228163021812.png
4.3 XML常見的解析器
- 解析器:就是根據(jù)不同的解析方式提供的具體實現(xiàn)。有的解析器操作過于繁瑣,為了方便開發(fā)人員,有提供易于操作的解析開發(fā)包
- JAXP:sun公司提供的解析器,支持DOM和SAX兩種思想
- DOM4J:一款非常優(yōu)秀的解析器 , Dom4j是一個易用的、開源的庫,用于XML,XPath和XSLT。它應(yīng)用于Java平臺,采用了Java集合框架并完全支持DOM,SAX和JAXP。
- Jsoup:jsoup 是一款Java 的HTML解析器 ,也可以解析XML
- PULL:Android內(nèi)置的XML解析方式,類似SAX。
4.4 dom4j 的使用
4.4.1 導(dǎo)入JAR包

image-20210228163030085.png
4.4.2 API介紹
- 使用核心類SaxReader加載xml文檔獲得Document,通過Document 對象獲得文檔的根元素,然后就可以操作了
- 常用API如下:
- SaxReader對象
- read(…) 加載執(zhí)行xml文檔
- Document對象
- getRootElement() 獲得根元素
- Element對象
- elements(…) 獲得指定名稱的所有子元素。可以不指定名稱
- element(…) 獲得指定名稱的第一個子元素。可以不指定名稱
- getName() 獲得當(dāng)前元素的元素名
- attributeValue(…) 獲得指定屬性名的屬性值
- elementText(…) 獲得指定名稱子元素的文本值
- getText() 獲得當(dāng)前元素的文本內(nèi)容
- SaxReader對象
4.4.3 準(zhǔn)備xml文件
- 編寫user.xsd schema約束
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://www.lagou.com/xml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.lagou.com/xml" elementFormDefault="qualified">
<xsd:element name="users" type="usersType"/>
<xsd:complexType name="usersType">
<xsd:sequence>
<xsd:element name="user" type="userType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="userType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="ageType" />
<xsd:element name="hobby" type="hobbyType" />
</xsd:sequence>
<xsd:attribute name="id" type="numberType" use="required"/>
</xsd:complexType>
<xsd:simpleType name="ageType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="100"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="hobbyType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="抽煙"/>
<xsd:enumeration value="喝酒"/>
<xsd:enumeration value="燙頭"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="numberType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
編寫user.xml 引入約束
<?xml version="1.0" encoding="UTF-8" ?>
<users xmlns="http://www.lagou.com/xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.lagou.com/xml user.xsd">
<user id="1">
<name>張百萬</name>
<age>20</age>
<hobby>抽煙</hobby>
</user>
<user id="2">
<name>于謙</name>
<age>50</age>
<hobby>喝酒</hobby>
</user>
<user id="3">
<name>劉能</name>
<age>40</age>
<hobby>燙頭</hobby>
</user>
</users>
4.4.4 讀取XML
public class TestDOM4j {
//獲取XML文件中的 所有的元素名稱(標(biāo)簽)
@Test
public void test1() throws DocumentException {
//1.獲取XML解析對象
SAXReader reader = new SAXReader();
//2.解析XML 獲取 文檔對象 document
Document document = reader.read("H:\\jdbc_work\\xml_task03\\src\\com\\lagou\\xml03\\user.xml");
//3.獲取根元素
Element rootElement = document.getRootElement();
//獲取根元素名稱
System.out.println(rootElement.getName());
//獲取 根元素下的標(biāo)簽
List<Element> elements = rootElement.elements();
for (Element element : elements) {
System.out.println("根標(biāo)簽下的子節(jié)點: " + element.getName());
List<Element> eList = element.elements();
for (Element e : eList) {
System.out.println("user標(biāo)簽下的子節(jié)點" + e.getName());
}
break;
}
}
/**
* 獲取具體的節(jié)點內(nèi)容 獲取張百萬的所有信息
*/
@Test
public void test2() throws DocumentException {
//1.創(chuàng)建XML文檔解析對象
SAXReader sr = new SAXReader();
//2.讀取XML獲取到document對象
Document document = sr.read("src\\com\\lagou\\xml02\\user.xml");
//3.獲取根節(jié)點
Element rootElement = document.getRootElement();
//4.得到當(dāng)前節(jié)點的 所有子節(jié)點
List<Element> elements = rootElement.elements();
//5.獲取第一個子節(jié)點
Element user = elements.get(0);
//6.獲取所有信息
String id = user.attributeValue("id");
String name = user.elementText("name");
String age = user.elementText("age");
//使用getText獲取當(dāng)前元素的文本內(nèi)容
String hobby = user.element("hobby").getText();
//打印
System.out.println(id+" " + name +" " + age +" " + hobby);
}
}
4.5 xpath方式讀取xml
4.5.1 xpath介紹
- XPath 是一門在 XML 文檔中查找信息的語言。 可以是使用xpath查找xml中的內(nèi)容。
- XPath 的好處
- 由于DOM4J在解析XML時只能一層一層解析,所以當(dāng)XML文件層數(shù)過多時使用會很不方便,結(jié)合XPATH就可以直接獲取到某個元素

image-20210228163042769.png
1)需要再導(dǎo)入 jaxen-1.1-beta-6.jar

image-20210228163056510.png
4.5.2 XPath基本語法介紹
使用dom4j支持xpath的操作的幾種主要形式
| 語法 | 說明 |
|---|---|
| /AAA/DDD/BBB | 表示一層一層的,AAA下面 DDD下面的BBB |
| //BBB | 表示和這個名稱相同,表示只要名稱是BBB,都得到 |
| /* | 所有元素 |
| BBB[1] , BBB[last()] | 第一種表示第一個BBB元素, 第二種表示最后一個BBB元素 |
| //BBB[@id] | 表示只要BBB元素上面有id屬性,都得到 |
| //BBB[@id='b1'] | 表示元素名稱是BBB,在BBB上面有id屬性,并且id的屬性值是b1 |
4.5.3 API介紹
- 常用方法:
- selectSingleNode(query): 查找和 XPath 查詢匹配的一個節(jié)點。
- 參數(shù)是Xpath 查詢串。
- selectNodes(query): 得到的是xml根節(jié)點下的所有滿足 xpath 的節(jié)點;
- 參數(shù)是Xpath 查詢串。
- Node: 節(jié)點對象
4.5.4 Xpath讀取XML
- 數(shù)據(jù)準(zhǔn)備 book.xml
<?xml version="1.0" encoding="UTF-8" ?>
<bookstore>
<book id="book1">
<name>金瓶梅</name>
<author>金圣嘆</author>
<price>99</price>
</book>
<book id="book2">
<name>紅樓夢</name>
<author>曹雪芹</author>
<price>69</price>
</book>
<book id="book3">
<name>Java編程思想</name>
<author>埃克爾</author>
<price>59</price>
</book>
</bookstore>
- 代碼示例
- 使用selectSingleNode方法 查詢指定節(jié)點中的內(nèi)容
/*
* 1. 使用selectSingleNode方法 查詢指定節(jié)點中的內(nèi)容
* */
@Test
public void test1() throws DocumentException {
//1.創(chuàng)建解析器對象
SAXReader sr = new SAXReader();
//2.獲取文檔對象
Document document =
sr.read("H:\\jdbc_work\\xml_task03\\src\\com\\lagou\\xml03\\book.xml");
//3.調(diào)用 selectSingleNode() 方法,獲取name節(jié)點對象
Node node1 = document.selectSingleNode("/bookstore/book/name");
System.out.println("節(jié)點: " + node1.getName());
System.out.println("書名: " + node1.getText());
//4.獲取第二本書的名稱
Node node2 = document.selectSingleNode("/bookstore/book[2]/name");
System.out.println("第二本書的書名為: " + node2.getText());
}
2.使用selectSingleNode方法 獲取屬性值,或者屬性值對應(yīng)的節(jié)
/*
* 2.使用selectSingleNode方法 獲取屬性值,或者屬性值對應(yīng)的節(jié)點
* */
@Test
public void test2() throws DocumentException {
//1.創(chuàng)建解析器對象
SAXReader sr = new SAXReader();
//2.獲取文檔對象
Document document =
sr.read("H:\\jdbc_work\\xml_task03\\src\\com\\lagou\\xml03\\book.xml");
//3.獲取第一個book節(jié)點的 id屬性的值
Node node1 = document.selectSingleNode("/bookstore/book/attribute::id");
System.out.println("第一個book的id值為: " + node1.getText());
//4.獲取最后一個book節(jié)點的 id屬性的值
Node node2 = document.selectSingleNode("/bookstore/book[last()]/attribute::id");
System.out.println("最后一個book節(jié)點的id值為: " + node2.getText());
//5.獲取id屬性值為 book2的 書名
Node node3 = document.selectSingleNode("/bookstore/book[@id='book2']");
String name = node3.selectSingleNode("name").getText();
System.out.println("id為book2的書名是: " + name);
}
- 使用 selectNodes()方法 獲取對應(yīng)名稱的所有節(jié)點
/*
* 3.使用 selectNodes()方法 獲取對應(yīng)名稱的所有節(jié)點
*
* */
@Test
public void test3() throws DocumentException {
//1.創(chuàng)建解析器對象
SAXReader sr = new SAXReader();
//2.獲取文檔對象
Document document =
sr.read("H:\\jdbc_work\\xml_task03\\src\\com\\lagou\\xml03\\book.xml");
//3.獲取所有節(jié)點,打印節(jié)點名
List<Node> list = document.selectNodes("http://*");
for (Node node : list) {
System.out.println("節(jié)點名: " + node.getName());
}
//4.獲取所有的書名
List<Node> names = document.selectNodes("http://name");
for (Node name : names) {
System.out.println(name.getText());
}
//5.獲取指定 id值為book1的節(jié)點的所有 內(nèi)容
List<Node> book1 = document.selectNodes("/bookstore/book[@id='book1']//*");
for (Node node : book1) {
System.out.println(node.getName()+" = " + node.getText());
}
}
5. JDBC自定義XML
5.1 定義配置文件
- 創(chuàng)建自定義xml 文件, 保存 數(shù)據(jù)庫連接信息
jdbc-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<jdbc>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db5?characterEncoding=UTF-8</property>
<property name="user">root</property>
<property name="password">123456</property>
</jdbc>
5.2 編寫工具類(配置式)
- 編寫工具類 ,使用xpath 讀取數(shù)據(jù)庫信息
public class JDBCUtils {
//1. 定義字符串變量, 記錄獲取連接所需要的信息
public static String DRIVERNAME;
public static String URL;
public static String USER;
public static String PASSWORD;
//2.靜態(tài)代碼塊
static {
try {
//使用 xpath讀取 xml中的配置信息
SAXReader sr = new SAXReader();
Document document = sr.read("H:\\workspace01\\JDBC_day02\\src\\com\\lagou\\xml03\\jdbc-config.xml");
Node node = document.selectSingleNode("/jdbc/property[@name='driverClass']");
//System.out.println(node.getText());
DRIVERNAME = node.getText();
URL = document.selectSingleNode("/jdbc/property[@name='jdbcUrl']").getText();
USER = document.selectSingleNode("/jdbc/property[@name='user']").getText();
PASSWORD = document.selectSingleNode("/jdbc/property[@name='password']").getText();
//注冊驅(qū)動
Class.forName(DRIVERNAME);
} catch (Exception e) {
e.printStackTrace();
}
}
//3.獲取連接的靜態(tài)方法
public static Connection getConnection(){
try {
//獲取連接對象
Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
//返回連接對象
return connection;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
}
5.3 測試工具類
- 測試 : 獲取所有員工的姓名
//獲取所有員工的姓名
public static void main(String[] args) {
try {
//1.獲取連接
Connection connection = JDBCUtils.getConnection();
//2.獲取 statement ,執(zhí)行SQL
Statement statement = connection.createStatement();
String sql = "select * from employee";
//3.處理結(jié)果集
ResultSet resultSet = statement.executeQuery(sql);
while(resultSet.next()){
String ename = resultSet.getString("ename");
System.out.println(ename);
}
} catch (SQLException e) {
e.printStackTrace();
}
}