一、XML
1.XML概述
- 可扩展标记语言(eXtensible Markuo Language)的缩写,一种数据表示格式,可以描述非常复杂的数据结构,常用于传输和存储数据;
- 纯文本,默认使用UTF—8编码;可嵌套
- XML内容存为文件,就是一个XML文件
- 使用场景:
- XML内容常常被当成消息进行网络传输;
- 作为配置文件用于存储系统的消息;
2.XML的创建
-
创建XML类型文件,文件后缀为.xml
-
文档声明必须在第一行
-
<?xml version="1.0" encoding="UTF-8" ?> version:XML默认版本号,该属性必须存在 encoding:本XML文件编码格式
-
2.1 XML标签(元素)规则
-
标签由一对尖括号和合法标识符组成,必须存在一个根标签,有且只有一个;
-
标签需成对出现,开始结束
<name></name> -
特殊标签单独出现,必须有结束标签
<br/> -
标签中可以定义属性,属性和标签名空格隔开,属性值必须用引号引起来;
<Studnet id="1">
-
标签需要正确的嵌套;
-
定义注释信息:<!-注释内容-->
-
可以存在以下特殊字符
-
< < 小于 > > 大于 & & ' ‘ 单引号 " "
-
-
可以存在CDATA区:
-
<![CDATA[...内容...]]>
-
<?xml version="1.0" encoding="UTF-8" ?>
<Student>
<name>张三</name>
<sex>男</sex>
<info>
<addr>哪里</addr>
<hobby>刑法</hobby>
</info>
<sql>
<!--注释信息:<小于 >大于 &&为&& -->
select name from student where age < 30;
select name from student where age > 18;
select name from student where age < 30 && age > 18;
<!-- 字符数据区:内部可以正常使用特殊字符 -->
<![CDATA[
select name from student where age < 30 && age > 18;
]]>
</sql>
</Student>
3.XML文档约束
- 文档约束:用来限定xml文件中的标签和属性要怎么写;
- 强制约束程序员必须按照文档约束的规定来编写xml文件;
3.1约束方式一:DTD
- DTD约束文档,后缀必须是.dtd;
- 需要编写的xml文件中导入该DTD约束文档;
- 按照约束的规定编写xml文件中内容;
- 优点:
- 可以约束书写格式;
- 缺点:
- 无法约束属性类型
3..1.1 data.dtd文件
<!ELEMENT书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
3.1.2 helloword_dtd.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM "data.dtd">
<书架>
<书>
<书名>java基础</书名>
<作者>黑马</作者>
<售价>暂无</售价>
</书>
<书>
<书名>禅与摩托车维修艺术</书名>
<作者>不知道</作者>
<售价>暂无</售价>
</书>
</书架>
3.2约束方式二:schema
- 可以约束具体数据类型,约束能力更强,文档后缀必须是.xsd;
- schema本身是xml文件,本身受其他约束文件要求,编写更加严格;
3.2.1 data.xsd
<?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>
3.2.2 helloword_schema.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 data.xsd">
<!-- xmlns="http://www.itcast.cn" 基本位置
xsi:schemaLocation="http://www.itcast.cn data.xsd"> 具体位置
-->
<书>
<书名>java</书名>
<作者>黑</作者>
<售价>99.9</售价>
</书>
<书>
<书名>仁</书名>
<作者>人</作者>
<售价>999</售价>
</书>
</书架>
二、XML解析技术
1.解析概述
1.1两种解析方式
| 解析方式 | |
|---|---|
| SAX解析 | 读一行,解析一行 |
| DOM解析 | 文件加载到内存,用树解析 以文档Document方式存储 |
1.2Dom常见解析工具
| 名称 | 说明 |
|---|---|
| JAXP | SUN提供的xml解析API |
| JDOM | 开源项目,基于树形结构,纯java技术对XML文档实现解析、生成、序列化及各种操作 |
| dom4j | 是JDOM升级品,读写xml文件,性能优异、功能强大、方便使用,性能超过官方的dom,源代码开放,框架用来读写配置文件**(重点)** |
| jsoup | 功能强大的DOM方式的xml解析开发包,对HTML解析更方便 |
1.3 DOM解析文档对象模型
-
Document对象:整个xml文档
-
元素属性对象都继承Node接口
- 以下都是节点类型
| 节点类型 | |
|---|---|
| Element对象 | 标签 |
| Attribute对象 | 属性 |
| Text | 文本内容 |
2.Dom4j解析xml文件
/**
* Dom4j解析xml文件
*/
public class Dom4jHelloWorldDemo01 {
@Test
public void parseXMLDate() throws Exception {
//1.创建一个Dom4j的解析器对象,代表整个dom4j对象
SAXReader saxReader = new SAXReader();
//2.xml文件加载到内存,成为一个Document文档对象
//Document document1 = saxReader.read(new File("day13_xml_app\src\Contacts.xml"));//需要通过模块名定位,改变影响
//Document document2 = saxReader.read(new FileInputStream(""));
//注意:getResourceAsStream("");中的/是直接去src下找文件
InputStream is = Dom4jHelloWorldDemo01.class.getResourceAsStream("/Contacts.xml");
Document document = saxReader.read(is);
//3.获取根元素对象
Element root = document.getRootElement();
System.out.println(root.getName());//contactList
//4.根元素下所有子元素
List<Element> sonEles = root.elements();
//可以拿指定标签的所有子元素
//List<Element> sonEles = root.elements("contact");
for (Element sonEle : sonEles) {
System.out.println(sonEle.getName());
}
// 5.根元素下某个子元素;有多个默认取第一个
Element contact = root.element("contact");
System.out.println(contact.getName());
// 6.获取子元素文本
System.out.println(contact.elementText("name"));
// 7.文本去掉前后空格
System.out.println(contact.elementTextTrim("name"));
// 8.根据元素获取属性值
Attribute idAttr = contact.attribute("id");
System.out.println(idAttr.getName()+idAttr.getValue());
//直接获取属性值
System.out.println(contact.attributeValue("id"));
// 9.获取当前元素下子元素对象
Element email = contact.element("email");
System.out.println(email.getText());
System.out.println(email.getTextTrim());
}
}
Contacts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<contactList>
<contact id="1" vip="true">
<name>曲云</name>
<gender>女</gender>
<email>123@qq.com</email>
</contact>
<contact id="2" vip="false">
<name>公孙二</name>
<gender>女</gender>
<email>123456@qq.com</email>
</contact>
<user>
<contact>
<infor>
<name id="8">天工万里鸽</name>
</infor>
</contact>
</user>
<name id="99">一级名</name>
</contactList>
3.案例:XML解析
/**
* 案例:XML解析
*/
public class Dom4jDemo02 {
@Test
public void parseToList() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(Dom4jDemo02.class.getResourceAsStream("/Contacts.xml"));
Element root = document.getRootElement();
List<Element> contactEles = root.elements("contact");
List<Contact> contacts = new ArrayList<>();
for (Element contactEle : contactEles) {
Integer id = Integer.valueOf(contactEle.attributeValue("id"));
boolean vip = Boolean.parseBoolean(contactEle.attributeValue("vip"));
String name = contactEle.elementText("name");
char gender = contactEle.elementText("gender").charAt(0);
String email = contactEle.elementText("email");
Contact contact = new Contact(id, vip, name, gender, email);
contacts.add(contact);
}
for (Contact contact : contacts) {
System.out.println(contact);
}
/**
* Contact{id=1, vip=true, name='曲云', gender=女, email='123@qq.com'}
* Contact{id=2, vip=false, name='公孙二', gender=女, email='123456@qq.com'}
*/
}
}
三、Xpath检索XML文件
- XPath:使用路径表达式来定位XML文档中的元素节点或属性节点;
- 示例:
- /元素/子元素/孙元素
- //子元素//孙元素
1.检索准备
- 导入jar包(dom4j和jaxen-1.1.2.jar),Xpath技术依赖Dom4j技术;
- 通过dom4j的SAXReader获取Document对象;
- 利用XPath的API,选取XML文档元素节点进行解析操作;
- Documnet与XPath相关API:
Node selectSingleNode("表达式")获取符合表达式的唯一元素List<Node> selectNodes("表达式")获取符合表达式的元素集合
2.检索的四种方式
/**
* 检索的四种方式
*/
public class XPathDemo {
/**
* 绝对路径:/根元素/子元素/子元素
*/
@Test
public void parse01() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(XPathDemo.class.getResourceAsStream("/Contacts.xml"));
//检索全部内容
List<Node> nameNodes = document.selectNodes("/contactList/contact/name");
for (Node node : nameNodes) {
Element nameFile = (Element) node;
System.out.println(nameFile.getTextTrim());
}
}
/**
* 相对路径:./子元素/子元素(.代表了当前元素)
*/
@Test
public void parse02() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(XPathDemo.class.getResourceAsStream("/Contacts.xml"));
//root代表contactList
Element root = document.getRootElement();
List<Node> nameNodes = root.selectNodes("./contact/name");
for (Node node : nameNodes) {
Element nameFile = (Element) node;
System.out.println(nameFile.getTextTrim());
}
}
/**
* 全文搜索:
* //元素, 全文中检索
* //元素1/元素2 全文找元素1下面的一级元素2
* //元素1//元素2 全文找元素1下面的全部元素2
*
*/
@Test
public void parse03() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(XPathDemo.class.getResourceAsStream("/Contacts.xml"));
//检索全部内容
//List<Node> nameNodes = document.selectNodes("//name");//文件下所有name
//List<Node> nameNodes = document.selectNodes("//contact/name");//contact下直属的一级name
List<Node> nameNodes = document.selectNodes("//contact//name");//contact下所有name
for (Node node : nameNodes) {
Element nameFile = (Element) node;
System.out.println(nameFile.getTextTrim());
}
}
/**
* 属性查找:
* @属性名 全文检索属性对象
* //元素[@属性名] 全文检索包含该属性的元素对象
* //元素[@属性名=值] 全文检索包含该属性的元素对象
*
*/
@Test
public void parse04() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(XPathDemo.class.getResourceAsStream("/Contacts.xml"));
//查询id属性
List<Node> nameNodes = document.selectNodes("//@id");
for (Node node : nameNodes) {
Attribute attr = (Attribute) node;
System.out.println(attr.getName()+attr.getValue());
}
//查询name元素(含有id属性)
Node node = document.selectSingleNode("//name[@id]");
Element element = (Element) node;
System.out.println(element.getTextTrim());//天工万里鸽
//查询name元素(含有id属性且有值)
Node node1 = document.selectSingleNode("//name[@id=99]");
Element element1 = (Element) node1;
System.out.println(element1.getTextTrim());//一级名
}
}
四、设计模式:工厂模式
- 工厂模式(Factory Pattern):是java最常用的设计模式之一,属于创建型模式,提供了一种获取对象的方式;
- 作用:工厂方法可以封装对象创建细节,为该对象进行加工和数据注入;
- 实现类与类之间的解耦操作(核心思想)
- 降低类间关联
- 修改创建只需要在FactoryPatten即可
/**
* 由工厂通过选择创建对象
*/
public class FactoryPatten {
/**
* 定义创建方法,返回创建对象
*/
public static Computer createComputer(String info){
switch (info){
case "Mi":
Computer mi = new Mi();
mi.setName("Mi U11");
mi.setPrice(2999.0);
return mi;
case "HW":
Computer hw = new HW();
hw.setName("HW 5");
hw.setPrice(3999.9);
return hw;
default:
return null;
}
}
}
/**
* 示例
*/
public class FactoryDemo {
public static void main(String[] args) {
Computer mi = FactoryPatten.createComputer("Mi");
mi.start();//Mi开机了
Computer hw = FactoryPatten.createComputer("HW");
hw.start();
}
}
/**
* 定义电脑抽象类
*/
public abstract class Computer {
private String name;
private double price;
public abstract void start();
public Computer() {
}
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;
}
}
/**
* 定义实现类
*/
public class Mi extends Computer{
@Override
public void start() {
System.out.println("Mi开机了");
}
}
五、设计模式:装饰模式
- 装饰模式:创建新类,包装原始类,在新类中提升类的功能;
- 作用:不改变原类,动态扩展类的功能;
- 步骤:
- 定义父类
- 定义原始类,继承父类,定义功能
- 定义装饰类,继承父类,包装原始类,增强功能
/**
* 装饰模式
*/
public class DecoratorPattern {
public static void main(String[] args) {
InputStream is = new BufferedInputStream(new FileInputStream());
System.out.println(is.read());
System.out.println(is.read(new byte[3]));
/**
* 创建8KB缓冲区,提高读取效率
* FileInputStream低性能读取一个字节
* 97
* 创建8KB缓冲区,提高读取效率
* FileInputStream低性能读取一个字节数组:[96, 97, 98]
* 3
*/
}
}
/**
* 定义父类
*/
public abstract class InputStream {
public abstract int read();
public abstract int read(byte[] buffer);
}
/**
* 定义原始类,继承父类,定义功能
*/
public class FileInputStream extends InputStream{
@Override
public int read() {
System.out.println("FileInputStream低性能读取一个字节");
return 97;
}
@Override
public int read(byte[] buffer) {
for (int i = 0; i < 3; i++) {
buffer[i] = (byte) (96+i);
}
System.out.println("FileInputStream低性能读取一个字节数组:"+ Arrays.toString(buffer));
return buffer.length;
}
}
/**
* 定义装饰类,继承父类,包装原始类,增强功能
*/
public class BufferedInputStream extends InputStream{
private InputStream is;
public BufferedInputStream(InputStream is){
this.is = is;
}
@Override
public int read() {
System.out.println("创建8KB缓冲区,提高读取效率");
return is.read();
}
@Override
public int read(byte[] buffer) {
System.out.println("创建8KB缓冲区,提高读取效率");
return is.read(new byte[3]);
}
}
此处略抽象,后续在设计模式的笔记中再详细展示。
RecordDate:2021/08/23