目录
- 1 XML
- 1.1 XML 概述
- 1.2 XML 语法规则
- 1.3 XML 文档约束(了解)
- 1.3.1 DTD 约束
- 1.3.2 schema 约束
- 2 XML 解析
- 2.1 XML 解析概述
- 2.2 Dom4J 解析 XML 文件
- 2.3 XML 解析案例
- 3 XML 检索
- 4 设计模式
- 4.1 工厂模式
- 4.2 装饰模式
1 XML
在有些业务场景下,存储数据或者传输数据给别人的时候需要满足一定的规范进行组织
1.1 XML 概述
XML 的全称为(EXtensible Markup Language),是一种 可扩展 的 标记语言,是一种数据表示格式,可以用于自定义数据格式,可以描述非常复杂的数据结构,常用于传输和存储数据。
例如:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<sender> 张三 </sender>
<receiver> 李四 </receiver>
<src>
<addr> 北京 </addr>
<date>2022-11-11 11:11:11</date>
</src>
<current> 武汉 </current>
<dest> 广州 </dest>
</data>
XML 的几个特点和使用场景
- 一是纯文本,默认使用
UTF-8
编码;二是可嵌套; - 如果把 XML 内容存为文件,那么它就是一个 XML 文件。
- XML 内容经常被 当成消息进行网络传输,或者 作为配置文件用于存储系统的信息。
1.2 XML 语法规则
- XML 的创建
就是创建一个 XML 类型的文件,要求文件的后缀名必须使用 xml
,如:helloworld.xml
。
- XML 文件的文档声明
XML 文件的文档声明必须在第一行
<?xml version="1.0" encoding="UTF-8" ?>
version
: XML 默认的版本号码、该属性是必须存在的
encoding
:本 XML 文件的编码
- XML 的标签 ( 元素 ) 规则
- 标签由一对尖括号和合法标识符组成:
<name></name>
,必须存在一个根标签,有且只能有一个 - 标签必须成对出现,有开始,有结束 :
<name></name>
- 特殊的标签可以不成对,但是必须有结束标记,如 :
<br/>
- 标签中可以定义属性,属性和标签名空格隔开 ,属性值必须用引号引起来
<student id = “1”></name>
- 标签需要正确的嵌套
- XML 文件中可以定义注释信息:
<!-- 注释内容 -->
- XML 文件中可以存在以下特殊字符
<
:<
小于>
:>
大于&
:&
和号'
:'
单引号"
:"
引号
- XML 文件可以存在 CDATA 区 (IDEA中输入CD再回车)
示例代码
<?xml version="1.0" encoding="UTF-8" ?>
<student>
<msg>
age > 18 && age <24
<![CDATA[
age>18 && age<24
]]>
</msg>
</student>
1.3 XML 文档约束(了解)
问题:由于 XML 文件可以自定义标签,导致 XML 文件可以随意定义,程序在解析的时候可能出现问题。
文档约束是用来限定 XML 文件中的标签以及属性应该怎么写,以此强制约束程序员必须按照文档约束的规定来编写 XML 文件中
文档约束可以分为:DTD和 schema 两种
1.3.1 DTD 约束
需求:利用 DTD 文档约束,约束一个 XML 文件的编写。
分析:
- 编写 DTD 约束文档,后缀必须是
.dtd
- 在需要编写的 XML 文件中导入该 DTD 约束文档
- 按照约束的规定编写 XML 文件的内容
示例代码
XML 的文档约束 -DTD 的作用和问题?
- 可以约束 XML 文件的编写。
- 不能约束具体的数据类型。
1.3.2 schema 约束
schema 可以约束具体的数据类型,约束能力上更强大,但由于其本身也是一个 XML 文件,也受到其他约束文件的要求,所以编写地更严谨
需求:利用 schema 文档约束,约束一个 XML 文件的编写。
分析:
- 编写 schema 约束文档,后缀必须是
.xsd
- 在需要编写的 XML 文件中导入该 schema 约束文档
- 按照约束内容编写 XML 文件的标签。
示例代码
2 XML 解析
2.1 XML 解析概述
XML 的数据的作用是什么,最终需要怎么处理?
- 存储数据、做配置信息、进行数据传输。
- 最终需要被程序进行读取,解析里面的信息。
主要有两种解析方式: SAX 解析、DOM 解析
Dom 常见的解析工具
DOM 解析解析文档对象模型
Document
对象:整个 xml 文档
Node
对象
Element
对象:标签Attribute
对象:属性Text
对象:文本内容
2.2 Dom4J 解析 XML 文件
需求:使用 Dom4J 把一个 XML 文件的数据进行解析
分析:
- 下载 Dom4j 框架,官网下载。
- 在项目中创建一个文件夹: lib
- 将 dom4j-2.1.1.jar 文件复制到 lib 文件夹
- 在 jar 文件上点右键,选择 Add as Library -> 点击 OK
- 在类中导包使用
Dom4j 解析 XML- 得到 Document 对象
SAXReader类
Document 类
Dom4j 解析 XML 的元素、属性、文本
示例代码
XML文件
<?xml version="1.0" encoding="UTF-8"?>
<contactList>
<contact id="1" vip="true">哈哈哈
<name> 潘金莲 </name>
<gender>女</gender>
<email>panpan@it.cn</email>
</contact>
<contact id="2" vip="false">
<name>武松</name>
<gender>男</gender>
<email>wusong@it.cn</email>
</contact>
<contact id="3" vip="false">
<name>武大狼</name>
<gender>男</gender>
<email>wuda@it.cn</email>
</contact>
<user>
</user>
</contactList>
解析XML文件
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
import java.io.InputStream;
public class Dom4jDemo {
@Test
public void parseXML() throws Exception{
// 1. 创建一个Dom4j解析器对象,代表了整个Dom4j框架
SAXReader saxReader = new SAXReader();
// 2. 把XML文件加载到内存中称为一个Document对象
// Document document = saxReader.read("xml\\src\\Contacts.xml");
// Document document = saxReader.read(new File("xml\\src\\Contacts.xml"));
// Document document = saxReader.read(new FileInputStream("xml\\src\\Contacts.xml"));
// getResourceAsStream 中的/是直接去src下寻找文件
InputStream is = Dom4jDemo.class.getResourceAsStream("/Contacts.xml");
Document document = saxReader.read(is);
// 3. 获取根元素对象
Element rootElement = document.getRootElement();
System.out.println(rootElement.getName()); // contactList
// 4. 获取子元素
// 4.1 获取根元素下所有的子元素(一级)
// List<Element> elements = rootElement.elements();
// for (Element element : elements) {
// System.out.println(element.getName());
// }
// 4.2 获取某个子元素(若同名,默认提取第一个子元素对象)
Element contact = rootElement.element("contact");
System.out.println(contact.getName()); // contact
// 4.3 获取当前元素的文本
System.out.println(contact.getText());
// 去掉前后空格
System.out.println(contact.getTextTrim()); // 哈哈哈
// 4.4 获取子元素文本
System.out.println(contact.elementText("name"));
// 去掉前后空格
System.out.println(contact.elementTextTrim("name")); // 潘金莲
// 4.5 根据元素获取属性值
Attribute id = contact.attribute("id");
// 打印属性名和属性值
System.out.println(id.getName()+":"+id.getValue());
// 4.6 直接获取属性值
System.out.println(contact.attributeValue("id")); // 1
System.out.println(contact.attributeValue("vip")); // true
}
}
2.3 XML 解析案例
需求 : 利用 Dom4J 的知识,将 Contact.xml 文件中的联系人数据封装成 List 集合,其中每个元素是实体类 Contact 。打印输出 List 中的每个元素。
案例用到的 XML 文件见上文
创建 Contact 类
public class Contact {
private String name;
private int id;
private boolean vip;
private char gender;
private String email;
public Contact() {
}
public Contact(String name, int id, boolean vip, char gender, String email) {
this.name = name;
this.id = id;
this.vip = vip;
this.gender = gender;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isVip() {
return vip;
}
public void setVip(boolean vip) {
this.vip = vip;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Contact{" +
"name='" + name + '\'' +
", id=" + id +
", vip=" + vip +
", gender=" + gender +
", email='" + email + '\'' +
'}';
}
}
解析XML
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
import java.lang.invoke.StringConcatException;
import java.util.ArrayList;
import java.util.List;
public class TestDemo {
@Test
public void parseToList() throws Exception {
// 1. 创建saxReader对象
SAXReader saxReader = new SAXReader();
// 2. 加载XML文件成为Document对象
Document document = saxReader.read(TestDemo.class.getResourceAsStream("/Contacts.xml"));
// 3. 先获取根元素
Element rootElement = document.getRootElement();
// 4. 获取所有的contact子元素
List<Element> contactEles = rootElement.elements("contact");
// 5. 准备一个ArrayList集合封装联系人信息
ArrayList<Contact> contactsList = new ArrayList<>();
// 6. 遍历每一个contact子元素
for (Element contactEle : contactEles) {
// 7. 每一个contact子元素都是一个联系人对象
Contact contact = new Contact();
// 8. 提取信息并给对象赋值
contact.setId(Integer.valueOf(contactEle.attributeValue("id")));
contact.setVip(Boolean.valueOf(contactEle.attributeValue("vip")));
contact.setName(contactEle.elementTextTrim("name"));
contact.setGender(contactEle.elementTextTrim("gender").charAt(0));
contact.setEmail(contactEle.elementTextTrim("email"));
// 9.把联系人对象放入List集合
contactsList.add(contact);
}
// 10. 遍历集合
for (Contact contact : contactsList) {
System.out.println(contact);
}
}
}
输出结果
总结
- Dom4J 解析 XML 文件的核心思想
- 得到文档对象 Document ,从中获取元素对象和内容。
- Dom4J 的解析后的数据形式。
- 通常数据会封装成 Java 的对象,如单个对象,或者集合对象形
式。
3 XML 检索
如果需要从 XML 文件中检索需要的某个信息(如 name )怎么解决?
- Dom4j 需要进行文件的全部解析,然后再寻找数据。
- Xpath 技术更加适合做信息检索。
XPath 在解析 XML 文档方面提供了一独树一帜的路径思想,更加优雅,高效。XPath 使用路径表达式来定位 XML 文档中的元素节点或属性节点。
使用 Xpath 检索出 XML 文件
需求:使用 Dom4J 把一个 XML 文件的数据进行解析
分析:
- 导入 jar 包 (dom4j 和 jaxen-1.1.2.jar) , Xpath 技术依赖 Dom4j 技术
- 通过 dom4j 的 SAXReader 获取 Document 对象
- 利用 XPath 提供的 API, 结合 XPath 的语法完成选取 XML 文档元素节点进行解析操作。
Document 中与 Xpath 相关的 API
Xpath 的四大检索方案
- 绝对路径:采用绝对路径获取从根节点开始逐层的查找 /contactList/contact/name 节点列表并打印信息
- 相对路径:先得到根节点 contactList,再采用相对路径获取下一级 contact 节点的 name 子节点并打印信息
- 全文检索:直接全文搜索所有的 name 元素并打印
- 属性查找:在全文中搜索属性,或者带属性的元素
示例代码
XML文件
<?xml version="1.0" encoding="UTF-8"?>
<contactList>
<contact id="1" vip="true">
<name> 潘金莲 </name>
<gender>女</gender>
<email>panpan@itcast.cn</email>
</contact>
<contact id="2" vip="false">
<name>武松</name>
<gender>男</gender>
<email>wusong@itcast.cn</email>
</contact>
<contact id="3" vip="false">
<name>武大狼</name>
<gender>男</gender>
<email>wuda@itcast.cn</email>
</contact>
<user>
<contact>
<info>
<name id="666">西门庆</name>
</info>
</contact>
</user>
</contactList>
检索XML
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Test;
import java.util.List;
public class XPathDemo {
// 1. 绝对路径
@Test
public void parse01() throws Exception {
// 创建解析器对象
SAXReader saxReader = new SAXReader();
// 将XML文件加载成Document对象
Document document = saxReader.read(XPathDemo.class.getResourceAsStream("/Contacts2.xml"));
// 检索全部名称:name值
List<Node> nodes = document.selectNodes("/contactList/contact/name");
for (Node node : nodes) {
Element nameEle = (Element) node;
System.out.println(nameEle.getTextTrim());
}
}
// 2. 相对路径
@Test
public void parse02() throws Exception {
// 创建解析器对象
SAXReader saxReader = new SAXReader();
// 将XML文件加载成Document对象
Document document = saxReader.read(XPathDemo.class.getResourceAsStream("/Contacts2.xml"));
Element rootElement = document.getRootElement();
// 检索全部名称:name值
List<Node> nodes = rootElement.selectNodes("./contact/name");
for (Node node : nodes) {
Element nameEle = (Element) node;
System.out.println(nameEle.getTextTrim());
}
}
// 3. 全文搜素
@Test
public void parse03() throws Exception {
// 创建解析器对象
SAXReader saxReader = new SAXReader();
// 将XML文件加载成Document对象
Document document = saxReader.read(XPathDemo.class.getResourceAsStream("/Contacts2.xml"));
// 检索数据
// List<Node> nodes = document.selectNodes("//name");// 会找"西门庆"
// List<Node> nodes = document.selectNodes("//contact/name");// 不会找"西门庆"
List<Node> nodes = document.selectNodes("//contact//name");// 会找"西门庆"
for (Node node : nodes) {
Element nameEle = (Element) node;
System.out.println(nameEle.getTextTrim());
}
}
// 4. 属性查找
@Test
public void parse04() throws Exception {
// 创建解析器对象
SAXReader saxReader = new SAXReader();
// 将XML文件加载成Document对象
Document document = saxReader.read(XPathDemo.class.getResourceAsStream("/Contacts2.xml"));
// 检索数据
// 在全文中检索属性对象
List<Node> nodes = document.selectNodes("//@id");
for (Node node : nodes) {
Attribute attr = (Attribute) node;
System.out.println(attr.getName()+":"+attr.getValue());
}
// 在全文中检索包含该属性的元素对象(若有多个只返回第一个)
// 查询name元素(包含id属性的)
// Node node = document.selectSingleNode("//name[@id]");
// 在全文中检索属性对象且属性值为该值的元素对象
Node node = document.selectSingleNode("//name[@id=666]");
Element ele = (Element) node;
System.out.println(ele.getTextTrim());
}
}
Element
和继承Node
4 设计模式
4.1 工厂模式
之前我们创建类对象时,都是使用 new 对象的形式创建,在很多业务场景下也提供了不直接 new 的方式 。
工厂模式( Factory Pattern )是 Java 中最常用的设计模式之一, 这种类型的设计模式属于创建型模式,它提供了一种获取对象的方式。
工厂设计模式的作用:
- 工厂的方法可以封装对象的创建细节,比如:为该对象进行加工和数据注入。
- 可以实现类与类之间的解耦操作(核心思想)
4.2 装饰模式
装饰设计模式:创建一个新类,包装原始类,从而在新类中提升原来类的功能。
装饰设计模式的作用:
- 装饰模式指的是在不改变原类的基础上 ,动态地扩展一个类的功能