Java的XML和设计模式
# XML和设计模式
# 1.XML
# 1.1XML概述
XML是可扩展标记语言(eXtensible Markup Language)的缩写,它是是一种数据表示格式
,可以描述非常复杂的数据结构,常用于传输和存储数据。XML是可扩展标记语言(eXtensible Markup Language)的缩写,它是是一种数据表示格式,可以描述非常复杂的数据结构,常用于传输和存储数据。
<?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>
</user>
</contactList>
XML的几个特点和使用场景
一是纯文本,默认使用UTF-8编码;二是可嵌套;
如果把XML内容存为文件,那么它就是一个XML文件。
XML的使用场景:XML内容经常被当成消息进行网络传输,或者作为配置文件用于存储系统的信息。
# 1.2XML的使用
XML的创建使用:
就是创建一个XML类型的文件,要求文件的后缀必须使用xml,如hello_world.xml
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文件中可以存在以下特殊字符
< < 小于
> > 大于
& & 和号
' ' 单引号
" " 引号
XML文件中可以存在CDATA区: <![CDATA[ …内容… ]]>
# 1.3XML文档约束
由于XML文件可以自定义标签,导致XML文件可以随意定义,程序在解析的时候可能出现问题。
文档约束:是用来限定xml文件中的标签以及属性应该怎么写。
文档约束的分类:
DTD
schema
XML文档约束-DTD的使用(了解)
**需求:**利用DTD文档约束,约束一个XML文件的编写。
分析:
①:编写DTD约束文档,后缀必须是.dtd
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
②:在需要编写的XML文件中导入该DTD约束文档
③:按照约束的规定编写XML文件的内容。
使用xml规范的时候:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM "data.dtd">
<书架>
<书>
<书名>精通JavaSE</书名>
<作者>鲁迅</作者>
<售价>99</售价>
</书>
</书架>
文档约束-schema
- schema可以约束具体的数据类型,约束能力上更强大。
- schema本身也是一个xml文件,本身也受到其他约束文件的要求,所以编写的更加严谨
需求:利用schema文档约束,约束一个XML文件的编写。
分析:
①:编写schema约束文档,后缀必须是.xsd,具体的形式到代码中观看。
②:在需要编写的XML文件中导入该schema约束文档
③:按照约束内容编写XML文件的标签。
<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itcast.cn"
elementFormDefault="qualified" >
<!-- targetNamespace:申明约束文档的地址(命名空间)-->
<element name='书架'>
<!-- 写子元素 -->
<complexType>
<!-- maxOccurs='unbounded': 书架下的子元素可以有任意多个!-->
<sequence maxOccurs='unbounded'>
<element name='书'>
<!-- 写子元素 -->
<complexType>
<sequence>
<element name='书名' type='string'/>
<element name='作者' type='string'/>
<element name='售价' type='double'/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
# 1.4XML解析技术
XML的数据的作用是什么,最终需要怎么处理?
存储数据、做配置信息、进行数据传输。
最终需要被程序进行读取,解析里面的信息。
使用程序读取XML中的数据被称为XML解析。有如下两种方式:
SAX解析
DOM解析
Dom常见的解析工具
名称 | 说明 |
---|---|
JAXP | SUN公司提供的一套XML的解析的API |
JDOM | JDOM是一个开源项目,它基于树型结构,利用纯JAVA的技术对XML文档实现解析、生成、序列化以及多种操作。 |
dom4j | 是JDOM的升级品,用来读写XML文件的。具有性能优异、功能强大和极其易使用的特点,它的性能超过sun公司官方的dom 技术,同时它也是一个开放源代码的软件,Hibernate也用它来读写配置文件。 |
jsoup | 功能强大DOM方式的XML解析开发包,尤其对HTML解析更加方便 |
Dom4J解析XML文件
**需求:**使用Dom4J把一个XML文件的数据进行解析
分析:
①下载Dom4j框架,官网下载。
②在项目中创建一个文件夹:lib
③将dom4j-2.1.1.jar文件复制到 lib 文件夹
④在jar文件上点右键,选择 Add as Library -> 点击OK
⑤在类中导包使用
Dom4j解析XML-得到Document对象
SAXReader类
构造器/方法 | 说明 |
---|---|
public SAXReader() | 创建Dom4J的解析器对象 |
Document read(String url) | 加载XML文件成为Document对象 |
Document类
方法名 | 说明 |
---|---|
Element getRootElement() | 获得根元素对象 |
准备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>
</user>
</contactList>
package com.example.d1_junit.demo6;
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;
import java.util.List;
public class HelloWordDemoXml {
@Test
public void parseXMLData() throws Exception{
// 1.创建一个Dom4j的解析器对象 代表了整个dom4j框架
SAXReader saxReader = new SAXReader();
// 2.把XML文件加载到内存中成为一个Document文档对象
// 注意: getResourceAsStream中的/是直接去src下面找的文件
InputStream is = HelloWordDemoXml.class.getResourceAsStream("/Contacts.xml");
Document document = saxReader.read(is);
// 3.获取根元素
Element root = document.getRootElement();
System.out.println(root.getName());
// 4.拿根元素下的全部子元素对象(一级)
// list<Element> sonELes = root.elements();
List<Element> sonELes = root.elements("contact");
for (Element sonELe : sonELes) {
System.out.println(sonELe.getName());
}
// 拿某个子元素
Element userELe = root.element("user");
System.out.println(userELe.getName());
// 默认提取第一个元素对象
Element contact = root.element("contact");
// 获取子元素文本
System.out.println(contact.elementText("name"));
// 去掉空格
System.out.println(contact.elementTextTrim("name"));
// 根据元素获取属性值
Attribute idAttr = contact.attribute("id");
System.out.println(idAttr.getName() + "-->" + idAttr.getValue());
// 直接提取属性值
System.out.println(contact.attributeValue("id"));
System.out.println(contact.attributeValue("vip"));
// 获取当前的元素下的子元素对象
Element email = contact.element("email");
System.out.println(email.getText());
}
}
运行结果:
contactList
contact
contact
contact
user
潘金莲
潘金莲
id-->1
1
true
panpan@itcast.cn
XML解析案例
需求:利用Dom4J的知识,将Contact.xml文件中的联系人数据封装成List集合,其中每个元素是实体类Contact。打印输出 List 中的每个元素。
使用上面的xml解析文件然后创建测试类:
package com.example.d1_junit.demo6;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class ContactTest {
@Test
public void parseToList() throws Exception{
// 需求: 解析XML中的数据成为一个List集合对象
// 1.导入框架(做过)
// 2.创建SaxReader对象
SAXReader saxReader = new SAXReader();
// 3.加载XML文件成为文档对象Document对象。
Document document =
saxReader.read(ContactTest.class.getResourceAsStream("/Contacts.xml"));
// 先拿根元素
Element root = document.getRootElement();
// 提取contact的子元素
List<Element> contactEles = root.elements("contact");
// 准备一个ArrayList集合封装联系人信息
List<Contact> contacts = new ArrayList<>();
// 遍历Contact子元素
for (Element contactEle : contactEles) {
Contact contact = new Contact();
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.elementText("email"));
// 把联系人对象数据添加到List集合
contacts.add(contact);
}
// 遍历list集合
for (Contact contact : contacts) {
System.out.println(contact);
}
}
}
运行结果:
Contact{name='潘金莲', id=1, vip=true, gender=女, email='panpan@itcast.cn'}
Contact{name='武松', id=2, vip=false, gender=男, email='wusong@itcast.cn'}
Contact{name='武大狼', id=3, vip=false, gender=男, email='wuda@itcast.cn'}
如果需要从XML文件中检索需要的某个信息(如name)怎么解决?
- Dom4j需要进行文件的全部解析,然后再寻找数据。
- Xpath技术更加适合做信息检索。
# 1.5XPath解析技术
XPath介绍
- XPath在解析XML文档方面提供了一独树一帜的路径思想,更加优雅,高效
- XPath使用
路径表达式
来定位XML文档中的元素节点或属性节点。
示例
/元素/子元素/孙元素
//子元素//孙元素
Xpath的四大检索方案
- 绝对路径
- 相对路径
- 全文检索
- 属性查找
XPath:绝对路径
采用绝对路径获取从根节点开始逐层的查找/contactList/contact/name节点列表并打印信息
方法名 | 说明 |
---|---|
/根元素/子元素/孙元素 | 从根元素开始,一级一级向下查找,不能跨级 |
XPath:相对路径
先得到根节点contactList
再采用相对路径获取下一级contact 节点的name子节点并打印信息
方法名 | 说明 |
---|---|
./子元素/孙元素 | 从当前元素开始,一级一级向下查找,不能跨级 |
XPath:全文搜索
直接全文搜索所有的name元素并打印
方法名 | 说明 |
---|---|
//contact | 找contact元素,无论元素在哪里 |
//contact/name | 找contact,无论在哪一级,但name一定是contact的子节点 |
//contact//name | contact无论在哪一种,name只要是contact的子孙元素都可以找到 |
XPath:属性查找
在全文中搜索属性,或者带属性的元素
方法名 | 说明 |
---|---|
//@属性名 | 查找属性对象,无论是哪个元素,只要有这个属性即可。 |
//元素[@属性名] | 查找元素对象,全文搜索指定元素名和属性名。 |
//元素//[@属性名=‘值’] | 查找元素对象,全文搜索指定元素名和属性名,并且属性值相等。 |
使用Xpath检索出XML文件
需求:使用Dom4J把一个XML文件的数据进行解析
分析:
①导入jar包(dom4j和jaxen-1.1.2.jar),Xpath技术依赖Dom4j技术
②通过dom4j的SAXReader获取Document对象
③利用XPath提供的API,结合XPath的语法完成选取XML文档元素节点进行解析操作。
④Document中与Xpath相关的API如下:
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 = "888">我是西门庆</name>
</info>
</contact>
</user>
</contactList>
XPath的使用
package com.example.d1_junit.demo6;
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;
import java.util.concurrent.CountDownLatch;
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"));
// 检索全部的名称
List<Node> nameNodes = document.selectNodes("/contactList/contact/name");
for (Node nameNode : nameNodes) {
Element nameELe = (Element) nameNode;
System.out.println(nameELe.getTextTrim());
}
}
// 相对路径: ./子元素/子元素 (.代表了当前的元素)
@Test
public void parse02() throws Exception{
// 创建解析器对象
SAXReader saxReader = new SAXReader();
// 把XML加载成Document文档对象
Document document = saxReader.read(XPathDemo.class.getResourceAsStream("/Contacts2.xml"));
Element root = document.getRootElement();
// 检索全部的名称
List<Node> nameNodes = root.selectNodes("./contact/name");
for (Node nameNode : nameNodes) {
Element nameELe = (Element) nameNode;
System.out.println(nameELe.getTextTrim());
}
}
// 全文搜索
// 元素 在全文找这个元素
// 元素1/元素2 在全文找元素1下面的一级元素2
// 元素1//元素2 在全文找元素1下面的全部元素2
@Test
public void parse03() throws Exception{
// 创建解析器对象
SAXReader saxReader = new SAXReader();
// 把XML加载成Document文档对象
Document document = saxReader.read(XPathDemo.class.getResourceAsStream("/Contacts2.xml"));
// 检索数据
List<Node> nameNodes = document.selectNodes("//name");
for (Node nameNode : nameNodes) {
Element nameEle = (Element) nameNode;
System.out.println(nameEle.getTextTrim());
}
}
// 属性查找
// @属性名称 子啊全文检索属性对象
// 元素[@属性对象] 在全文检索包含该属性元素对象
// 元素[@属性名称=值] 在全文检索包含该属性的元素且属性值为该值的元素对象
@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=888]");
Element ele = (Element) node;
System.out.println(ele.getTextTrim());
}
}
# 2.设计模式
# 2.1设计模式概述
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。
# 2.2设计模式的三大类
总体来说设计模式分为三大类:
创建型模式(5种)
:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式(7种)
:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式(11种)
:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
装饰设计模式的作用
作用:
装饰模式指的是在不改变原类的基础上, 动态地扩展一个类的功能。
- InputStream(抽象父类)
- FileInputStream(实现子类,读写性能较差)
- BufferedInputStream(实现子类,装饰类,读写性能高)
①定义父类。
②定义原始类,继承父类,定义功能。
③定义装饰类,继承父类,包装原始类,增强功能!!
# 2.3工厂方法模式
普通工厂模式
,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图:
通过一个例子说明:
1.Computer作为父类计算机类型
2.其中Huawei和Mac作为子类继承,我们每次创建新的类型的时候,通过工厂模式配置好run接口。
3.每次使用Huawei和Mac的子类的时候,只需要调用工厂模式的内容。
定义Computer父类:
package com.example.d1_junit.demo7;
public abstract class Computer {
private String name;
private double price;
public Computer() {
}
public Computer(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Computer{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
public abstract void run();
}
分别定义Huawei和Mac的类:
package com.example.d1_junit.demo7;
public class Huawei extends Computer{
@Override
public void run() {
System.out.println("开机了,Huawei!");
}
}
package com.example.d1_junit.demo7;
public class Mac extends Computer{
@Override
public void run() {
System.out.println("开机了,MaC!");
}
}
创建一个工厂模式的类:
package com.example.d1_junit.demo7;
public class FactoryPattern {
public static Computer createComputer(String info){
switch (info){
case "huawei":
Computer c1 = new Huawei();
c1.setName("Huawei");
c1.setPrice(5999);
return c1;
case "mac":
Computer c2 = new Mac();
c2.setName("Mac");
c2.setPrice(1999);
return c2;
default:
return null;
}
}
}
在使用测试类进行调用:
package com.example.d1_junit.demo7;
public class test {
public static void main(String[] args) {
Computer c1 = FactoryPattern.createComputer("huawei");
Computer c2 = FactoryPattern.createComputer("mac");
c1.run();
c2.run();
}
}
运行结果:
开机了,Huawei!
开机了,MaC!
更多详解可以查阅大佬笔记: [🔒点击这里🗝️] (opens new window)