学习目标
- 能够说出 XML 的作用
- 了解 XML 的组成元素
- 能够说出有哪些 XML约束技术
- 能够说出解析 XML 文档 DOM方式原理
- 能够说出Dom4j常用的类
- 能够通过Dom4j得到文档对象(重点)
- 能够读取Dom树上的元素对象(重点)
- 能够使用 XPath 解析 XML 文档
- 能够使用Base64对基本数据、URL和MIME类型进行编解码
- 能够使用工厂模式编写java程序
学习内容
XML概述
目标
- 学习XML的概念
- 编写第1个XML文件
什么是XML
-
英文:Extensible Markup Language 可扩展的标记语言
-
标记语言:由很多的标记组成 (标签) <名字>
-
可扩展:标签名任意,但是要符合命名
<凤姐></凤姐> <name></name>
#### XML作用
<font color='red'>**XML是可以保存数据的**</font>
1) 数据交换:不同的计算机语言之间,不同的操作系统之间进行数据交换。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4842W6VQ-1597666349249)(/1552221268464.png)]
2) 配置文件:在后期我们主要用于各种框架的配置文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6t9o8uUd-1597666349255)(/1552221310087.png)]
#### 案例:编写第1个XML文件
编写xml文档,用于描述人员信息,person代表一个人员,id是人员的属性代表人员编号。人员信息包括age年龄、name姓名、sex性别信息。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cbqTKOm0-1597666349266)(/1552352318788.png)]
#### 步骤
1. 选择当前项目鼠标右键新建
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-12nsKaZ3-1597666349277)(/1552221478628.png)]
2. 编写person.xml文件
```xml
<!--描述一个人-->
<person id="1">
<name>张三</name>
<age>18</age>
<sex>男</sex>
</person>
-
通过浏览器解析XML的内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3tvofhF-1597666349282)(/1552221534649.png)]
- 注意:XML以后通过Java来进行解析,很少直接在浏览器上显示。
小结
-
什么是XML?
可扩展的标记语言
-
XML主要作用?
保存数据
XML的组成:声明和元素
目标
- 学习XML中7种组成部分
- 学习XML中文档声明和元素的作用
XML由七种组成元素构成
-
文档声明
-
标签/元素
-
属性
-
注释
-
实体字符
-
CDATA 字符数据区
-
处理指令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SSJJXsJg-1597666349286)(/1597021611780.png)]
文档声明
1.文档声明格式
<?xml version="1.0" encoding="UTF-8" ?>
作用: 告诉软件这是一个XML文件
注意:
以<?xml开头, 以 ?>结尾
必须放在第一行
声明的三种属性
文档声明的三个属性 | 说明 |
---|---|
version | 指定XML文件使用的版本,取值是1.0 |
encoding | 当前XML文件使用的编码(字符集) UTF-8/GBK |
standalone | 指定当前这个XML文件是否是一个独立的文件,省略的,默认是独立文件。 |
版本说明
W3C在1988年2月发布1.0版本,2004年2月又发布1.1版本,因为1.1版本不能向下兼容1.0版本,所以1.1没有人用。在2004年2月W3C又发布了1.0版本的第三版。我们学习的还是1.0版本。
元素
标签就是元素
元素语法格式
<元素名>内容</元素名>
<元素名>: 起始标签或开始标签
</元素名>: 结束标签
标签是成对出现的
没有内容的标签
<元素名></元素名>
没有内容的标签可以简写
<元素名/>
XML标签命名的要求
- 严格区分大小写: 不行
- 标签名不能以数字开头,只能以字母或下划线开头,可以是中文: <9miao></9miao>不行
- 标签名不能包含空格: </na me> 不行
根标签
什么是根标签?
没有被其他标签包裹的就是根标签
注意
在一个xml文档中,只允许有一个根标签
代码
<?xml version="1.0" encoding="UTF-8" ?>
<persons>
<!--描述一个人-->
<person id="1">
<name>张三</name>
<age>18</age>
</person>
<person id="2">
<name>李四</name>
<age>19</age>
</person>
</persons>
小结
-
文档声明有哪两个常用的属性?
<?xml version="1.0" encoding="UTF-8" ?> version: 版本好 encoding: 编码
-
一个XML有几个根元素?
1个
XML的组成:属性
目标
学习XML文档中属性格式
属性语法格式
<元素名 属性名="值">内容</元素名>
注意
- 属性放在开始标签中
- 属性值必须放在双引号或单引号中
- 在一个标签中,属性可以有多个,但不能出现同名的属性
小结
1.说出属性语法格式?
<元素名 属性名="值"></元素名>
XML的组成:注释
目标
学习XML文档中的注释格式
注释语法格式
<!-- 注释内容 -->
注释作用
给程序员看的
快捷键
注释: ctrl + /
嵌套
在XML中注释不能嵌套
小结
1.说出注释语法格式?
<!-- 注释内容 -->
XML的组成:实体字符/转义字符
目标
学习XML文档中实体字符的使用
为什么要实体字符
因为很多符号已经被文档结构所使用,所以在元素体或属性值中想使用这些符号就必须使用实体字符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fydbqxmE-1597666349288)(/1552353386585.png)]
语法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WJm70Pb3-1597666349291)(/1556375355138.png)]
规律
所有的实体字符都是以&开头, 以;结尾
错误写法
int age = 10;
if (age < 18) {
}
正确写法
int age = 10;
if (age < 18) {
}
小结
-
为什么要有实体字符?
有些符号XML已经作为特殊用途啦.我们不能使用
<
对应的实体字符是什么<
>
对应的实体字符是什么>
XML的组成:字符数据区
如果大量使用实体字符,会导致XML可读性降低。另一种解决方案:可以使用字符数据区包裹这些字符,
目标
学习字符数据区CDATA使用
CDATA字符数据区的概念
Character Data 字符数据区
CDATA字符数据区的作用
放在CDATA字符数据区中的数据,作为纯文本解析.原样显示
CDATA字符数据区格式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vJIyHxbm-1597666349293)(/1552225954936.png)]
快捷键: CD
小结
CDATA字符数据区作用?
放到CDATA字符数据取中的数据作为纯文本,原样显示
XML的组成:处理指令(了解)
目标
了解处理指令的使用
处理指令格式
<? xxx ?>
<?xml-stylesheet type="text/css" href="out.css"?> 导入外部css文件
小结
一个XML有哪7个组成部分?
- 文档声明
- 标签/元素
- 属性
- 注释
- 实体字符
- CDATA字符数据区
- 处理指令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DPRk6Puw-1597666349294)(/1597021611780.png)]
XML约束:DTD约束
目标
了解XML中的两种约束
了解DTD约束
XML为什么要有约束
因为XML文件的标签和属性可以随意扩展,有时我们必须要限制每个文档有哪些元素,每个元素有哪些子元素,每个元素有哪些属性,属性的值是什么类型等。
通过XML约束可以保证XML文件中的数据的正确性
<?xml version="1.0" encoding="GBK"?>
<person>
<name>柳岩</name>
<age>18</age>
<sex>女</sex>
</person>
XML的两种约束
- DTD约束,比较简单,功能相对弱
- SCHEMA,比较复杂,功能相对强
DTD约束的概念
- DTD概念: Document Type Definiation 文档类型定义
- DTD作用:限制XML只能出现指定的内容
导入DTD文件的两种格式 | 说明 |
---|---|
<!DOCTYPE 根元素 SYSTEM “DTD文件路径”> | 本地的约束,适合个人,公司小范围的使用的约束 |
<!DOCTYPE 根元素 PUBLIC “文件描述” “DTD文件路径”> | 网络上的约束,适合大范围的使用 |
如:hibernate框架的导入方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UeZU5XUs-1597666349296)(/1552227668343.png)]
DTD使用案例
步骤1:新建bookshelf.dtd文件,选择项目鼠标右键“NEW->File",文件名为“bookshelf.dtd”
步骤2:复制下面内容到bookshelf.dtd
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XBhQJ2wm-1597666349298)(/1597024845869.png)]
步骤3:新建books.xml,代码如下
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM "bookshelf.dtd">
<书架>
<书>
<书名>JavaEE SSM</书名>
<作者>张三</作者>
<售价>30</售价>
</书>
<书>
<书名>人鬼情喂鸟</书名>
<作者>李四</作者>
<售价>300</售价>
</书>
</书架>
步骤4:idea开发工具books.xml的dtd约束验证不通过的效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qiaBpXYi-1597666349303)(/1552355976703.png)]
DTD学习要求
在企业实际开发中,很少自己编写DTD约束文档,我们后期只需通过框架提供的DTD约束文档编写出相应的XML配置文档。
小结
-
DTD的作用是什么?
约束XML文件中的内容不能够乱写,保证XML数据的正确性
-
导入DTD格式
<!DOCTYPE 根标签 SYSTEM "DTD文件路径">
XML约束:Schema约束
目标
了解Schema约束
为什么要有Schema约束
DTD的不足:
- 不能验证数据类型
- 因为DTD是一个文本文件,本身不能验证是否正确。
Schema约束文件扩展名(XML Schema Definition)XML模式定义:xsd
约束文件本身也是XML文件,所以也有根元素,根元素的名字叫:schema
模式文档和实例文档
实例文档:自己编写的XML
模式文档:Schema约束文档
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pED0l2zU-1597666349306)(/1557066139347.png)]
命名空间
相当于包名
**问:如果在Java中如果使用同名的类,如何避免冲突?**比如:Date类,在java.util和java.sql包中都有
package com.itheima;
import java.sql.Date;
public class Demo1 {
public static void main(String[] args) {
// java.util.Date
// java.sql.Date
java.util.Date d1 = new java.util.Date();
System.out.println(d1);
java.sql.Date d2 = new java.sql.Date(System.currentTimeMillis());
System.out.println(d2);
}
}
如果不同的xsd约束文件出现同名的标签,如何避免冲突?
一个XML文件可以有多个约束文件,不同的Schema约束文档中出现相同的内容.给不同的Schema文档取不同的命名空间,通过命名空间可以区分使用的是哪个Schema里面的约束
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fgx7GGfm-1597666349307)(/1557067140710.png)]
- targetNamespace用来指定命名空间
- 默认命名空间,前面不需要指定前缀,直接使用<标签名>
- 一个XML文档中只能有一个默认的命名空间
- 其它命名空间中的标签,使用<前缀:标签名>来引用
Schema演示案例
- 步骤1:新建schema约束文件bookshelf.xsd,复制以下代码到bookshelf.xsd文件中:
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itcast.cn"
elementFormDefault="qualified">
<xs:element name='书架'>
<xs:complexType>
<xs:sequence maxOccurs='unbounded'>
<xs:element name='书'>
<xs:complexType>
<xs:sequence>
<xs:element name='书名' type='xs:string'/>
<xs:element name='作者' type='xs:string'/>
<xs:element name='售价' type='xs:double'/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
注意:在上面的schema约束文档中我们只需要关注targetNamespace=“http://www.itcast.cn”,就是命名空间相当于知道了包名
2. 步骤2:新建books2.xml使用schema约束文件
在自己编写的XML中引入schema约束文件的格式
<根元素 xmlns="命名空间" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="命名空间 xsd约束文件名">
</根元素>
book2.xml
<?xml version="1.0" encoding="UTF-8" ?>
<书架 xmlns="http://www.itcast.cn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.itcast.cn bookshelf.xsd">
<书>
<书名>JavaEE</书名>
<作者>张三</作者>
<售价>39</售价>
</书>
<书>
<书名>西游记</书名>
<作者>吴承恩</作者>
<售价>3000</售价>
</书>
</书架>
-
步骤3:违反约束,开发工具提示效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZVixiujB-1597666349310)(/1552357355473.png)]
Schema学习要求
虽然schema功能比dtd强大,但是编写要比DTD复杂,同样以后我们在企业开发中也很少会自己编写schema文件。我们只需要借助开发工具,在现有的xsd约束下,写出正确的xml文件即可。
小结
-
XML有哪两种约束?
DTD约束
SCHEMA约束
-
Schema约束相比DTD有哪些优点?
- 可以验证数据类型
-
Schema约束是一个XML,有官方约束来限制,不容易写错
XML的SAX解析
目标
了解XML的SAX解析方式
什么是XML的解析
使用程序读取XML中的数据
两种解析方式
- SAX解析
- DOM解析
SAX解析
- 优点:事件驱动型解析方式,读取一行就解析一行,释放内存。理论上可以解析任意大小的XML文件。
- 缺点:使用过的元素不能再访问了,不能修改元素,只能查找。
DOM解析原理(重要)
目标
学习DOM解析的原理
DOM的概念
Document Object Model: 文档对象模型
DOM解析原理
DOM 将整个XML文档加载到内存,生成一个DOM树,并获得一个Document对象,通过Document对象就可以对DOM进行操作。以下面books.xml文档为例。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NyiDMwNL-1597666349311)(/1552305143011.png)]
XML文件
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="0001">
<name>JavaWeb开发教程</name>
<author>高斯林</author>
<sale>100.00元</sale>
</book>
<book id="0002">
<name>三国演义</name>
<author>罗贯中</author>
<sale>100.00元</sale>
</book>
</books>
生成的DOM树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CNn4vBbr-1597666349315)(/1552305350183.png)]
DOM解析优缺点
优点:将整个XML文件加载到内存中,生成一棵DOM树。随意访问树上任何一个节点,可以修改和删除节点,程序开发比较方便。
缺点:占内存,如果XML文件很大,可能出现内存溢出。
Java中DOM解析开发包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vDseScGm-1597666349317)(/1552305195234.png)]
由于DOM方式解析XML文档所有都是节点Node,所有节点又都被封装到Document对象中,所以解析的重点就是获取Document对象。
小结
有哪两种XML的解析方式
SAX解析
DOM解析
DOM解析解析原理
将文件中的所有数据加载到内存中,生成一颗DOM树
dom4j:获取Document对象和根元素
目标
- dom4j得到Document对象
- 得到根元素
导入dom4j的步骤
-
去官网下载 zip 包。http://www.dom4j.org/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-10suuvlv-1597666349319)(/1552305595501.png)] -
在项目中创建一个文件夹:lib
-
将dom4j-2.1.1.jar文件复制到 lib 文件夹
-
在jar文件上点右键,选择 Add as Library -> 点击OK
-
在类中导包使用
得到Document对象
步骤
文件Contact.xml放在src目录下
- 创建一个SAXReader对象,用于读取 xml 文件
- 从类路径下加载xml文件,得到输入流对象
- 通过 SAXReader对象的read(InputStream in )方法,从输入流中读取,生成文档对象
代码
package com.itheima;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
/**
1. 得到文档对象
2. 得到根元素
*/
public class Demo3Document {
public static void main(String[] args) throws FileNotFoundException, DocumentException {
//1. 创建类: 读取XML文件
SAXReader reader = new SAXReader();
//不建议这么写
//FileInputStream in = new FileInputStream("D:\\IdeaWork\\JavaEE105\\day23-xml\\src\\Contacts.xml");
//src目录就是编译以后的类路径,从类路径下得到输入。
InputStream in = Demo3Document.class.getResourceAsStream("/Contacts.xml");
//2.通过reader来读取xml, 生成了一个document对象
Document document = reader.read(in);
//3. 输出文档
System.out.println(document);
//4. 得到文档以后,通过文档得到根元素
Element rootElement = document.getRootElement();
System.out.println(rootElement);
}
}
Document常用方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JF3TrShD-1597666349323)(/1552305787000.png)]
小结
-
如何得到Document对象
SAXReader reader = new SAXReader(); // 2.使用DOM解析器解析一个XML文件,会返回Document Document document = reader.read(new FileInputStream("day13demo/src/Contact.xml"));
-
调用哪个方法得到根元素:
Element root = document.getRootElement();
dom4j:元素对象Element(重要)
目标
学习Element对象的方法
什么是Element
Element就是元素对象,即标签
Element常用方法
方法名 | 功能说明 |
---|---|
String getName() | 得到元素名字 |
List elements() | 得到当前元素下所有子元素 |
List elements(String name) | 得到当前元素下指定名字的子元素返回集合 |
Element element(String name) | 得到当前元素下指定名字的子元素,如果有很多名字相同的返回第一个 |
元素使用的案例
需求
使用元素方法的,得到第一个contact下所有的子元素,并且输出元素名
步骤
- 得到SAXReader对象
- 得到Document对象
- 得到根元素
- 得到第一个contact元素
- 得到第一个contact元素下所有的子元素,并输出子元素的名字
代码
package com.itheima;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.List;
/**
元素方法的使用
*/
public class Demo3Element {
public static void main(String[] args) throws DocumentException {
//1. 得到SAXReader对象
SAXReader reader = new SAXReader();
InputStream in = Demo3Element.class.getResourceAsStream("/Contacts.xml");
//2. 得到Document对象
Document document = reader.read(in);
//3. 得到根元素
Element rootElement = document.getRootElement();
//4. 得到contact元素
Element contact = rootElement.element("contact");
//System.out.println(contact);
//5. 得到contact下所有的子元素,并输出子元素的名字
List<Element> elements = contact.elements();
for (Element element : elements) {
//只输出标签名
System.out.println(element.getName());
}
}
}
小结
Element对象的方法
方法名 | 功能说明 |
---|---|
String getName() | 获取元素的名字 |
Element element(子元素名称) | 获取一个指定名称的子元素,如果有个多,返回第一个 |
List<Element> elements() | 获取所有子元素 |
List<Element> elements(String name) | 获取所有指定名字的子元素 |
dom4j:属性对象Attribute
目标
学习得到元素中的属性并使用
什么是Attribute对象
属性对象
<contact id="1" vip="true">
如:id=“1”
Element中与属性相关方法
得到属性的前提是:先得到元素
Element中的方法 | 功能说明 |
---|---|
String attributeValue(String name) | 通过属性名直接得到属性值 |
Attribute attribute(String name) | 通过属性名得到属性对象 |
List attributes() | 得到当前元素所有的属性对象 |
Attribute常用方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xwOLXQyi-1597666349326)(/1552306372013.png)]
属性的案例
步骤
- 创建DOM解析器
- 调用read 方法,读取 xml 文件
- 得到根元素
- 获得第2个contact元素对象
- 通过方式1:得到contact上id属性值
- 通过方式2:得到contact上id属性值
- 得到contact上所有的属性名和属性值
效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jVMC2Fn0-1597666349328)(/1552306491790.png)]
代码
package com.itheima;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.List;
public class Demo4Attribute {
public static void main(String[] args) throws DocumentException {
//1. 创建SAXReader
SAXReader reader = new SAXReader();
//2. 调用read 方法,读取 xml 文件
Document document = reader.read(Demo4Attribute.class.getResourceAsStream("/Contacts.xml"));
//3. 得到根元素
Element rootElement = document.getRootElement();
//4. 获得第1个contact元素对象
Element contact = rootElement.element("contact");
//5. 通过方式1:得到contact上id属性值
Attribute idAttr = contact.attribute("id");
String idValue = idAttr.getValue();
System.out.println(idValue);
//6. 通过方式2:得到contact上id属性值
String id = contact.attributeValue("id");
System.out.println(id);
//7. 得到contact上所有的属性名和属性值
List<Attribute> attributes = contact.attributes();
for (Attribute attribute : attributes) {
System.out.println("属性名:" + attribute.getName());
System.out.println("属性值:" + attribute.getValue());
}
}
}
小结
Element中的方法 | 功能说明 |
---|---|
String attributeValue(String name) | 通过属性名得到属性值 |
Attribute attribute(String name) | 通过属性名得到属性对象 |
List<Attribute> attributes() | 得到所有的属性对象 |
得到属性值的两种方式:
- 先得到Attribute对象,再通过Attribute对象得到属性的值
- 通过方法attributeValue()直接得到属性值
dom4j:获取文本内容
目标
通过元素对象得到文本字符串
文本内容
得到文本元素的前提:先得到元素对象
- 注:空格、换行、制表符:也是属于文本的一部分,所以在解析xml文件的时候,格式化XML文件要注意。
元素中得到文本有关的方法
Element元素中的方法 | 说明 |
---|---|
String getText() | 得到文本 |
String elementText(元素名) | 得到指定名称的子元素的文本 |
String elementTextTrim(元素名) | 得到指定名称的子元素的文本,去掉前后空格 |
案例:对文本的操作
步骤
- 解析XML得到Document对象
- 得到根元素
- 得到第一个contact标签
- 得到name标签中的文本
- 得到name标签
- 再得到name中的文本
代码
package com.itheima;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
得到文本内容
*/
public class Demo5Text {
public static void main(String[] args) throws DocumentException {
// 1.创建SAXReader
SAXReader reader = new SAXReader();
// 2.调用read 方法,读取 xml 文件
Document document = reader.read(Demo5Text.class.getResourceAsStream("/Contacts.xml"));
// 3.得到根元素
Element rootElement = document.getRootElement();
// 得到contact标签
Element contact = rootElement.element("contact");
// 得到name标签中的文本
Element name = contact.element("name");
System.out.println(name.getText());
// 得到子元素的文本
System.out.println(contact.elementText("name"));
// 得到子元素的文本并且去掉前后空格
System.out.println(contact.elementTextTrim("name"));
}
}
小结
Element元素中的方法 | 说明 |
---|---|
String getText() | 得到元素本身的文本 |
String elementText(子元素名) | 得到指定名称的子元素的文本 |
String elementTextTrim(子元素名) | 得到指定名称的子元素的文本,去掉前后的空格,回车 |
案例:XML解析案例(重点)
目标
利用Dom4j 的知识,将Contact.xml 文件中的联系人数据封装成List集合,其中每个元素是实体类Contact。打印输出 List 中的每个元素。
运行效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zdQz6u8z-1597666349331)(/1552307147703.png)]
数据准备
Contact.xml
<?xml version="1.0" encoding="UTF-8"?>
<contactList>
<contact id="1">
<name>潘金莲</name>
<gender>女</gender>
<email>panpan@itcast.cn</email>
</contact>
<contact id="2">
<name>武松</name>
<gender>男</gender>
<email>wusong@itcast.cn</email>
</contact>
<contact id="3">
<name>武大狼</name>
<gender>男</gender>
<email>wuda@itcast.cn</email>
</contact>
</contactList>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MfVKAqUx-1597666349334)(/1592723161442.png)]
步骤
- 创建联系人Contact类
- 创建集合保存多个联系人
- 获得所有的contact元素
- 遍历contact元素集合
- 得到contact下的子元素的文本
- 将联系人对象添加到集合中
代码
Contact.java实体类
package com.itheima.entity;
/**
* 联系人实体类
*/
public class Contact {
private int id;
private String name;
private String gender;
private String email;
@Override
public String toString() {
return "Contact{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", email='" + email + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
测试类
package com.itheima;
import com.itheima.entity.Contact;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.ArrayList;
import java.util.List;
public class Demo6Contact {
public static void main(String[] args) throws DocumentException {
//1. 得到SaxReader
SAXReader reader = new SAXReader();
//2. 得到文档对象
Document document = reader.read(Demo6Contact.class.getResourceAsStream("/Contact.xml"));
//3. 得到根元素
Element rootElement = document.getRootElement();
//4. 创建集合
List<Contact> list = new ArrayList<>();
//5. 得到所有联系人
List<Element> contactElements = rootElement.elements();
//每个就是一个联系人
for (Element contactElement : contactElements) {
//创建一个联系人
Contact contact = new Contact();
//System.out.println(contactElement.getName()); //打印标签名
//得到id属性值,将字符串转成int类型
int id = Integer.parseInt(contactElement.attributeValue("id"));
contact.setId(id);
//得到子元素中文本
contact.setName(contactElement.elementText("name"));
contact.setGender(contactElement.elementText("gender"));
contact.setEmail(contactElement.elementText("email"));
//将当前对象添加到集合中
list.add(contact);
}
//打印集合中所有的联系人
for (Contact contact : list) {
System.out.println(contact);
}
}
}
dom4j中与XPath表达式有关的方法
目标
- 学习XPath的概念
- 学习Dom4j与XPath相关的方法
什么是XPath
XPath:路径表达式
作用:方便的解析XML中的数据
XPath表达式分类
- 绝对路径
- 相对路径
- 全文搜索
- 属性查找
什么是Node对象
DOM树中的每个节点就是Node
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LcGBoX2L-1597666349338)(/1552308501088.png)]
dom4j中与XPath相关的方法
注:使用XPath需要另外导入 jaxen-1.1.2.jar包[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YH9f3KzK-1597666349339)(/1557216821239.png)]
Node对象的方法 | 功能说明 |
---|---|
Node selectSingleNode(String xpath) | 通过xpath得到一个节点 |
List selectNodes(String xpath) | 通过xpath得到一组节点 |
小结
Node对象的方法 | 功能说明 |
---|---|
Node selectSingleNode(String xpath) | 通过XPATH表达式获取单个节点 |
List selectNodes(String xpath) | 通过XPATH表达式获取多个节点 |
XPath:绝对路径和相对路径
目标
- 学习XPath绝对路径的使用
- 学习XPath相对路径的使用
绝对路径语法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-szsKtzvX-1597666349341)(/1552308629483.png)]
绝对路径示例
需求
采用绝对路径获取从根节点开始逐层的查找/contactList/contact/name 节点列表并打印信息
步骤
- 读取 XML 文档并获得Document对象
- 定义 Xpath 表达式:/contactList/contact/name
- 调用Document对象的selectNodes()方法执行Xpath获得节点集合
- 遍历输出每个节点
代码
package com.itheima;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
/**
使用xpath
*/
public class Demo7Xpath {
private Document document;
//在每个测试方法之前执行的方法
@Before
public void init() throws DocumentException {
//1. 得到SaxReader
SAXReader reader = new SAXReader();
//2. 得到文档对象
document = reader.read(Demo7Xpath.class.getResourceAsStream("/Contact.xml"));
}
/**
使用绝对路径
*/
@Test
public void testAbsolute() {
String xpath = "/contactList/contact/name";
//得到所有name元素
List<Node> nodeList = document.selectNodes(xpath);
for (Node node : nodeList) {
System.out.println(node.getText());
}
}
}
相对路径的语法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4B8gF6fv-1597666349343)(/1552308854372.png)]
相对路径的示例
需求
- 先采用绝对路径获取 contactList 节点
- 再采用相对路径获取下一级contact 节点的name子节点并打印信息
步骤
- 定义 Xpath 表达式:/contactList
- 调用Document对象的 selectSingleNode 方法执行Xpath获得根节点对象
- 通过根节点对象调用selectNodes方法执行相对路径表达式:./contact/name
- 打印输出所有的节点
代码
/**
使用相对路径
*/
@Test
public void testRelative() {
//通过绝对路径得到/contactList
Node node = document.selectSingleNode("/contactList");
//通过相对路径得到name
Node nameNode = node.selectSingleNode("./contact/name");
System.out.println(nameNode.getText());
}
小结
-
什么是XPath的绝对路径?
/根元素/子元素/孙元素 /开头就是绝对路径
-
什么是XPath的相对路径?
./子元素/孙元素 ./开头就是相对路径
XPath:全文搜索和属性查找
目标
- 学习XPath全文搜索的使用
- 学习XPath属性查找的使用
全文搜索语法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZPz2K69F-1597666349345)(/1552310075137.png)]
举例
举例 | 说明 |
---|---|
//contact | 找contact元素,无论元素在哪里 |
//contact/name | 找contact,无论在哪一级,但name一定是contact的子节点 |
//contact//name | contact无论在哪一种,name只要是contact的子孙元素都可以找到 |
全文搜索示例
需求
直接全文搜索所有的name元素并打印
步骤
- 创建Xpath表达式 //name
- 使用selectNodes()方法查询所有的name节点
代码
/**
全文搜索
*/
@Test
public void testGlobalSearch() {
List<Node> nodes = document.selectNodes("//name");
for (Node node : nodes) {
System.out.println(node.getText());
}
}
属性查找语法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f7GrLRU4-1597666349348)(/1552310301097.png)]
步骤
- 创建Xpath表达式
- 查找所有id属性节点
- 查找包括id属性的contact元素
- 使用selectNodes()方法查询所有的节点
代码
/**
属性查找
*/
@Test
public void testAttributeFind() {
//1. 查找所有id属性节点
/*List<Node> nodes = document.selectNodes("//@id");
//是属性对象Attribute
for (Node node : nodes) {
//输出属性值
Attribute a = (Attribute) node;
System.out.println("属性值:" + a.getValue());
}*/
//2. 查找包括id属性的contact元素
/*List<Node> nodeList = document.selectNodes("//contact[@id]");
for (Node node : nodeList) {
System.out.println(node.getName());
}*/
//3. 查找包括id属性且属性名为的contact元素
Node node = document.selectSingleNode("//contact[@id=2]");
System.out.println(node.getName());
}
小结
XPath表达式分类 | 语法 |
---|---|
绝对路径 | /根元素/子元素/孙元素 /开头就是绝对路径 |
相对路径 | ./子元素/孙元素 ./开头就是相对路径 |
全文搜索 | //元素 全文搜索 |
属性查找 | //@属性名 找属性 //元素名[@属性名] 找有指定属性的元素 //元素名[@属性名=值] 找有指定属性名和值的元素 |
Base64
目标
了解Base 64的作用
了解Base 64的编码和解码
Base 64的作用
Base64 并非安全领域下的加密解密算法。虽然经常遇到所谓的base64的加密解密。但base64只能算是一个编码算法,对数据内容进行编码来方便在网络上传输。
Base64就是一种基于64个可打印字符来表示二进制数据的方法。
private static final char[] toBase64 = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
private static final char[] toBase64URL = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TtBTGWQq-1597666349352)(/1575121918007.png)]
在Java 8中,Base64编码已经成为Java类库的标准。Java 8 内置了 Base64 编码的编码器和解码器。
编码: 文字变成特殊字符
解码: 特殊字符变成文字
Base64工具类提供了一套静态方法获取下面三种BASE64编解码器:
- **基本:**输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/。
- **URL:**输出映射到一组字符A-Za-z0-9-_,输出是URL和文件。
- **MIME:**输出映射到MIME友好格式。输出每行不超过76字符。
Base64内嵌类和方法描述
内嵌类
序号 | 内嵌类 & 描述 |
---|---|
1 | static class Base64.Decoder该类实现一个解码器用于,使用 Base64 编码来解码字节数据。 |
2 | static class Base64.Encoder该类实现一个编码器,使用 Base64 编码来编码字节数据 |
方法
1.static Base64.Decoder getDecoder() 返回一个 Base64.Decoder,解码使用基本型 base64 编码方案。
2.static Base64.Encoder getEncoder() 返回一个 Base64.Encoder,编码使用基本型 base64 编码方案。
3.static Base64.Decoder getMimeDecoder() 返回一个 Base64.Decoder,解码使用 MIME 型 base64 编码方案。
4.static Base64.Encoder getMimeEncoder() 返回一个 Base64.Encoder,编码使用 MIME 型 base64 编码方案。
5.static Base64.Encoder getMimeEncoder(int lineLength, byte[] lineSeparator) 返回一个 Base64.Encoder,编码使用 MIME 型 base64 编码方案,可以通过参数指定每行的长度及行的分隔符。
6.static Base64.Decoder getUrlDecoder() 返回一个 Base64.Decoder,解码使用 URL 和文件名安全型 base64 编码方案。
7.static Base64.Encoder getUrlEncoder() 返回一个 Base64.Encoder,编码使用 URL 和文件名安全型 base64 编码方案。
Base64代码演示
public static void main(String args[]) {
try {
// 使用基本编码
String base64encodedString = Base64.getEncoder().encodeToString("itheima?java8".getBytes("utf-8"));
System.out.println("Base64 编码字符串 (基本) :" + base64encodedString);
// 解码
byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
System.out.println("原始字符串: " + new String(base64decodedBytes, "utf-8"));
// URL
base64encodedString = Base64.getUrlEncoder().encodeToString("itheima?java8".getBytes("utf-8"));
System.out.println("Base64 编码字符串 (URL) :" + base64encodedString);
// MIME
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 10; ++i) {
stringBuilder.append(UUID.randomUUID().toString());
}
byte[] mimeBytes = stringBuilder.toString().getBytes("utf-8");
String mimeEncodedString = Base64.getMimeEncoder().encodeToString(mimeBytes);
System.out.println("Base64 编码字符串 (MIME) :" + mimeEncodedString);
}catch(UnsupportedEncodingException e){
System.out.println("Error :" + e.getMessage());
}
}
运行结果:
Base64 编码字符串 (基本) :aXRoZWltYT9qYXZhOA==
原始字符串: itheima?java8
Base64 编码字符串 (URL) :aXRoZWltYT9qYXZhOA==
Base64 编码字符串 (MIME) :ODM1MWI4MzMtZGZmZi00MDAwLTkwNTAtZjUxMjkzODMwY2E2YTVjZmMwN2QtYzM0My00ZjdhLTll
MDktMDFkMWZmZjA0MWRkOTE5Nzk0YzMtNTkyOC00Yjk0LThhYWEtMmIyNmFhN2Y3YzFmY2I2NDNl
ZmEtY2ZmNC00NTU4LWIzZDktZjAzMmE1M2FiOWM1ZDAyMzAyYzktZTM3MS00MDk3LWI2YWEtZTMz
MzZlMjE4NDdkZmEzYTA0NjktYWFhZC00M2ZiLTkzYTQtYTA0ZDIzMjIxY2RiMTMxYTU1MzgtZjZi
OS00NDcyLWJjOTYtZjViODVkNzdkNjMyODNhZTJhNDktZmU0Ni00ZDI5LWI0MDUtZWRkZGFmYjM2
MDliZTcyNWMxY2ItMWE3Ny00NmM4LTk2ZWUtZjBhYjY4YzgwMzU3N2Q3YWFiMTYtNzBjYi00MzNh
LTkxN2UtNzJmNWE0MjQzMGUx
小结
Base64是有基本的64个字符组成
基本的Base64: a-zA-Z0-9+/
URL的Base64: a-zA-Z0-9-_
MIME的Base64: 一行不超过76个字符
工厂设计模式
设计模式: 编写代码时的套路, Java中有23种设计模式
目标
学习工厂设计模式的使用
工厂设计模式概述
工厂设计模式(Factory Pattern)是 Java 中最常用的设计模式之一。简单工厂模式用于创建对象的。通过专门定义一个类来负责创建其他类的实例。
工厂设计模式作用
解决类与类之间的耦合问题,屏蔽了外界对具体类的依赖,让类的创建更加简单。
工厂设计模式实现步骤
- 编写一个Car接口, 提供run方法
- 编写一个Falali类实现Car接口,重写run方法
- 编写一个Benchi类实现Car接口,重写run方法
- 提供一个CarFactory(汽车工厂),用于生产汽车对象
- 定义CarFactoryTest测试汽车工厂
工厂模式实现代码
1.编写一个Car接口, 提供run方法
public interface Car {
public abstract void run();
}
2.编写一个Falali类实现Car接口,重写run方法
public class Falali implements Car {
@Override
public void run() {
System.out.println("法拉利以每小时500公里的速度在奔跑.....");
}
}
3.编写一个Benchi类实现Car接口
public class Benchi implements Car {
@Override
public void run() {
System.out.println("奔驰汽车以每秒1米的速度在挪动.....");
}
}
4.提供一个CarFactory(汽车工厂),用于生产汽车对象
public class CarFactory {
/**
* @param id : 车的标识
* benchi : 代表需要创建Benchi类对象
* falali : 代表需要创建Falali类对象
* 如果传入的车标识不正确,代表当前工厂生成不了当前车对象,则返回null
* @return
*/
public Car createCar(String id){
if ("falali".equals(id)) {
return new Falali();
} else if ("benchi".equals(id)) {
return new Benchi();
}
return null;
}
}
5.定义CarFactoryTest测试汽车工厂
public class CarFactoryTest {
public static void main(String[] args) {
CarFactory carFactory = new CarFactory();
Car benchi = carFactory.createCar("benchi");
benchi.run();
Car falali = carFactory.createCar("falali");
falali.run();
}
}
小结
工厂模式的存在可以改变创建类的方式,解决类与类之间的耦合.
实现步骤:
- 编写一个Car接口, 提供run方法
- 编写一个Bmw类实现Car接口,重写run方法
- 编写一个Benz类实现Car接口
- 提供一个CarFactory(汽车工厂),用于生产汽车对象
- 定义CarFactoryTest测试汽车工厂
工厂类
public class CarFactory {
public static Car createCar(String id) {
if ("benz".equals(id)) {
return new Benz();
} else if ("BMW".equals(id)) {
return new BMW();
} else if ("hc".equals(id)) {
return new 恒驰();
}
return null;
}
}
测试类
public class Demo08 {
public static void main(String[] args) {
// 通过工厂类得到汽车,主要使用汽车
// 让我们的代码解耦,创建对象和使用对象是分开的
Car bmw = CarFactory.createCar("BMW");
bmw.run();
Car hc = CarFactory.createCar("hc");
hc.run();
Car benz = CarFactory.createCar("benz");
benz.run();
Car hehe = CarFactory.createCar("hehe");
System.out.println("hehe = " + hehe);
}
}
学习总结
-
能够说出 XML 的作用
保存数据
-
了解 XML 的组成元素
1.文档声明 2.元素/标签 3.属性 4.注释 5.实体字符 6.CDATA字符数据区 7.处理指令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TitlX99D-1597666349356)(/1597021611780.png)]
-
能够说出有哪些 XML约束技术
DTD约束, 比较弱
SCHEMA约束, 比较强
-
能够说出解析 XML 文档 DOM方式原理
将整个文件的所有数据一次性加载到内存中形成一颗DOM树
-
能够使用dom4j解析XML文档
// 创建解析器 SAXReader reader = new SAXReader(); // 解析文档得到Document文档对象 Document document = reader.read(字节输入流); // 得到根元素 Element rootElement = document.getRootElement(); // 得到子元素 // 得到属性 // 得到文本
-
能够使用xpath解析XML或HTML文档
Node对象的方法 功能说明 Node selectSingleNode(String xpath) 通过xpath得到一个节点 List selectNodes(String xpath) 通过xpath得到多个节点
XPath表达式分类 | 语法 |
---|---|
绝对路径 | /根元素/子元素/孙元素 |
相对路径 | ./子元素/孙元素 |
全文路径 | //元素 |
属性查找 | //@属性名 获取指定名称的属性对象 //元素名[@属性名] 获取有指定属性名的元素 //元素名[@属性名=值] 获取有指定属性名和值的元素 |
-
能够使用Base64对基本数据、URL和MIME类型进行编解码
String parameter = "password=123&56"; // 基本的Base64编码 String encodeToString = Base64.getEncoder().encodeToString(parameter.getBytes()); System.out.println("基本的Base64编码 = " + encodeToString); // cGFzc3dvcmQ9MTIzJjU2 // 基本的Base64解码 byte[] decode = Base64.getDecoder().decode(encodeToString); System.out.println("基本的Base64解码 = " + new String(decode)); // password=123&56 // ================================================= // URL的Base64编码 String encodeToStringURL = Base64.getUrlEncoder().encodeToString(parameter.getBytes()); System.out.println("URL的Base64编码 = " + encodeToStringURL); // cGFzc3dvcmQ9MTIzJjU2 // URL的Base64解码 byte[] decodeURL = Base64.getUrlDecoder().decode(encodeToStringURL); System.out.println("URL的Base64解码 = " + new String(decodeURL)); // password=123&56 // UUID String uuid = UUID.randomUUID().toString(); System.out.println("uuid = " + uuid); // 4ad5b59e-68a0-4e0f-896f-f5e9a5a5a997 32为的随机的数据唯一的 StringBuilder sb = new StringBuilder(); for (int i = 0; i < 20; i++) { sb.append(UUID.randomUUID().toString()); } System.out.println(sb.toString()); // MIME的Base64编码 String encodeToStringMIME = Base64.getMimeEncoder().encodeToString(sb.toString().getBytes()); System.out.println("MIME的Base64编码 = " + encodeToStringMIME); // MIME的Base64解码 byte[] decodeMIME = Base64.getMimeDecoder().decode(encodeToStringMIME); System.out.println("MIME的Base64解码 = " + new String(decodeMIME));
-
能够使用工厂模式编写java程序
工厂类 // 汽车工厂,专门用于创建汽车对象 public class CarFactory { public static Car createCar(String id) { if ("benz".equals(id)) { return new Benz(); } else if ("BMW".equals(id)) { return new BMW(); } else if ("hc".equals(id)) { return new 恒驰(); } return null; } }