XML
XML eXtensible Markup Language 可扩展的标记语言
它是一种数据的表示格式,可用来表示结构复杂的数据
常用于数据的存储和传输
XML的几个特点和使用场景
一是纯文本,默认使用UTF-8编码;二是可嵌套;
如果把XML内容存为文件,那么它就是一个XML文件。
XML的使用场景:XML内容经常被当成消息进行网络传输,或者作为配置文件用于存储系统的信息。
XML的语法规则
XML的创建
创建一个xml文件
语法规则:
第一行必须是文档声明
标签(元素)规则
标签由一对尖括号和合法标识符组成: ,必须存在一个根标签,有且只能有一个。
标签必须成对出现,有开始,有结束:
特殊的标签可以不成对,但是必须有结束标记,如:
标签中可以定义属性,属性和标签名空格隔开,属性值必须用引号引起来
XML的其他组成
XML文件中可以定义注释信息:<!– 注释内容 -->
XML文件中可以存在以下特殊字符
XML文件中可以存在CDATA区: <![CDATA[ …内容… ]]>
以下是xml案例
<?xml version="1.0" encoding="UTF-8" ?>
<!--文档声明必须在第一行-->
<!-- 这是一条注释信息 -->
<!-- 必须要有root标签有且只有一条 -->
<student>
<name>张无忌</name>
<age>16</age>
<hobby>练武功</hobby>
<info id = "1">
<address>武当山</address>
<sex>男</sex>
</info >
<sql>
<!-- 特殊字符与标识符冲突的如:< -->
select * form student where age < 18;
</sql>
<!--CDATA区域可以随便写内容 快捷键CD-->
<![CDATA[
撒旦放假啦附件
的房价就
select * from user where name = "张三";
]]>
</student>
文档约束
问题:由于XML是可以扩展的 标签可以自己定义。在解析时就可能不知道有哪些标签,所以需要加以约束
什么是文档约束(了解)
就是限定了xml文件中的标签及其属性如何书写
从而强制约束程序员必须按照文档约束的规定来编写xml文件。
文档约束分为两类:
DTD
schema
DTD
新建一个dtd文件格式如下
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
通过 导入DTD约束
根据约束编写xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM "data.dtd">
<书架>
<书>
<书名> 天龙八部 </书名>
<作者>金庸</作者>
<售价>99</售价>
</书>
<书>
<书名>金瓶梅</书名>
<作者>佚名</作者>
<售价>很贵</售价>
</书>
</书架>
DTD约束成功限制了xml的编写格式但也存在问题
它不能限制具体的类型
如将金瓶梅的售价改成 很贵 显然是不合理的
文档约束-schema(了解如何使用)
- schema可以约束具体的数据类型,约束能力上更强大。
- schema本身也是一个xml文件,本身也受到其他约束文件的要求,所以编写的更加严谨
schema通常由其他人写好只需调用并按照其格式编写即可
Sechema文件:hello_world_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>
导入Schema文件按照其格式编码
<?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 books02.xsd" 具体的位置 -->
<书>
<书名>神雕侠侣</书名>
<作者>金庸</作者>
<售价>399.9</售价>
</书>
<书>
<书名>神雕侠侣</书名>
<作者>金庸</作者>
<售价>19.5</售价>
</书>
</书架>
XML解析
XML是用来存储数据、做配置文件、进行数据传输的
最终是要被程序读取并解析出内容
什么是XML解析?
使用程序解析出XML中的数据
常用的解析方式:
SAX解析
DOM解析 是常用的解析方式
Dom常见的解析工具
重点掌握dom4j
百度dom4j
download 三个文件
dom4j.jar是核心jar包
dom4j.source是源代码
dom4j.javadoc是API文档
这里的id是标签的属性
解析结构
XML解析的步骤
下载Dom4j框架,官网下载。
在项目中创建一个文件夹:lib
将dom4j-2.1.1.jar文件复制到 lib 文件夹
在jar文件上点右键,选择 Add as Library -> 点击OK
在类中导包使用
解析后的元素对象都时实现了Node接口的子类
public void parseXML() throws Exception {
//1.创建一个SAXReader解析器
SAXReader saxReader = new SAXReader();
//2.把XMl文件加载到内存中成为一个Document文档对象
//都需要通过模块名去定位
// Document document = saxReader.read(new File("my-xml-app/src/Contacts.xml"));
// Document document1 = saxReader.read(new FileInputStream("my-xml-app/src/Contacts.xml\""));
//通过Class 中的getResourceAsStream 接口 使用文件名定位src目录下的文件
InputStream is = HelloWorldDom4j.class.getResourceAsStream("Contacts.xml");
Document document = saxReader.read(is); //
//3.返回根对象
Element root = document.getRootElement();
System.out.println(root.getName());
//4.通过根对象得到子元素
List<Element> elements = root.elements();
for (Element element : elements) {
System.out.println(element.getName());
}
//拿某个子元素
Element userEle = root.element("user");
System.out.println(userEle.getName());
//名字重复默认取第一个元素
Element contactEle = root.element("contact");
System.out.println(contactEle.getName());
//获取子元素文本
// System.out.println(contactEle.getText());// contact没有文本打印出与其行数相等的空行
// System.out.println(1);
System.out.println(contactEle.elementText("id"));
System.out.println(contactEle.elementText("name"));
System.out.println(contactEle.elementTextTrim("name"));
}
XPath检索
package com.myself.xpath;
import org.dom4j.*;
import org.dom4j.io.SAXReader;
import org.junit.Test;
import java.util.List;
/**
目标:XPath检索XML中的信息啊。(了解)
引入:
Dom4J可以用于解析整个XML的数据。
但是如果要检索XML中的某些信息,建议使用XPath.(Xpath依赖Dom4j技术)
Dom4J用于解析数据,Xpath用于检索数据。
XPath使用步骤:
1.导入dom4j框架。(XPath依赖于Dom4j技术,必须先导入dom4j框架!)
2.导入XPath独有的框架包。jaxen-1.1.2.jar
XPath常用API:
List<Node> selectNodes(String var1):检索出一批节点集合。
Node selectSingleNode(String var1):检索出一个节点返回。
XPath提供的四种检索数据的写法:
1.绝对路径。
2.相对路径。
3.全文搜索。
4.属性查找。
小结:
1.绝对路径: /根元素/子元素/子元素。
2.相对路径: ./子元素/子元素。 (.代表了当前元素)
3.全文搜索:
//元素 在全文找这个元素
//元素1/元素2 在全文找元素1下面的一级元素2
//元素1//元素2 在全文找元素1下面的全部元素2
4.属性查找。
//@属性名称 在全文检索属性对象。
//元素[@属性名称] 在全文检索包含该属性的元素对象。
//元素[@属性名称=值] 在全文检索包含该属性的元素且属性值为该值的元素对象。
*/
public class E1XPath {
//一、绝对路径 /根元素/子元素/子元素
@Test
public void parse01() throws Exception {
//1.获取解析器对象
SAXReader saxReader = new SAXReader();
//2.获取文件对象
Document document = saxReader.read(E1XPath.class.getResourceAsStream("/Contacts.xml"));
//3.检索节点 根据绝对路径
List<Node> nodesEle = document.selectNodes("/contactList/contact/name");
//4.遍历节点
for (Node nodeEle : nodesEle) {
//强制转换为Element类型
Element ele = (Element) nodeEle;
System.out.println(ele.getTextTrim());
}
}
//相对路径
@Test
public void parse02() throws Exception {
//1.获取解析器对象
SAXReader saxReader = new SAXReader();
//2.获取文件对象
Document document = saxReader.read(E1XPath.class.getResourceAsStream("/Contacts.xml"));
//3.获取根元素
Element root = document.getRootElement();
//4.检索节点,根据根元素 这里的 . 代表当前元素
List<Node> nodesEle = root.selectNodes("./contact/name");
//5.遍历节点
for (Node nodeEle : nodesEle) {
//强制转换为Element类型
Element ele = (Element) nodeEle;
System.out.println(ele.getTextTrim());
}
}
//全文检索
//元素 在全文document找这个元素
//元素1/元素2 在全文找元素1下面的一级元素2
//元素1//元素2 在全文找元素1下面的全部元素2
@Test
public void parse03() throws Exception {
//1.获取解析器对象
SAXReader saxReader = new SAXReader();
//2.获取文件对象
Document document = saxReader.read(E1XPath.class.getResourceAsStream("/Contacts2.xml"));
//3.获取根元素
Element root = document.getRootElement();
//4.检索节点,根据根元素 这里的 . 代表当前元素
// List<Node> nodesEle = document.selectNodes("//name");
//List<Node> nodesEle = document.selectNodes("//contact/name");
List<Node> nodesEle = document.selectNodes("//contact//name");
//5.遍历节点
for (Node nodeEle : nodesEle) {
//强制转换为Element类型
Element ele = (Element) nodeEle;
System.out.println(ele.getTextTrim());
}
}
//4.属性查找。
// 1. //@属性名称 在全文检索属性对象。
// 2. //元素[@属性名称] 在全文检索包含该属性的元素对象。
// 3. //元素[@属性名称=值] 在全文检索包含该属性的元素且属性值为该值的元素对象。
@Test
public void parse04() throws Exception{
//1.获取解析器对象
SAXReader saxReader = new SAXReader();
//2.获取Document文件对象
Document document = saxReader.read(E1XPath.class.getResourceAsStream("/Contacts2.xml"));
//3.检索数据
//查询所有的id属性
//List<Node> nodesEle = document.selectNodes("//@id");
List<Node> nodesEle = document.selectNodes("//name[@id]");
// for (Node nodeEle : nodesEle) {
// //强制转换为Attribute类型
// Attribute ele = (Attribute) nodeEle;
// System.out.println(ele.getName() + ele.getValue());
// }
for (Node nodeEle : nodesEle) {
//强制转换为Attribute类型
Element ele = (Element) nodeEle;
System.out.println(ele.getName() + ele.getTextTrim());
}
//得到单个Node对象
Node node = document.selectSingleNode("//name[@id = 888]");
System.out.println(node.getName() + node.getText());
}
}
工厂设计模式
在业务场景之中,有时不能我们自己new一个对象,如computer类所有我们需要用的工厂来产生类
工厂模式(FactoryPattern)是一种常用的设计模式,是创造型设计模式,它提供了类的获取 方式
定义了一个电脑类
package com.itheima.d3_factory_pattern;
public abstract class Computer {
private String name;
private double price;
public abstract void start();
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;
}
}
工厂类提供了方法返回Computer对象
public class FactoryPattern {
/**
定义一个方法,创建对象返回
*/
public static Computer createComputer(String info){
switch (info){
case "huawei":
Computer c = new Huawei();
c.setName("huawei pro 16");
c.setPrice(5999);
return c;
case "mac":
Computer c2 = new Mac();
c2.setName("MacBook pro");
c2.setPrice(11999);
return c2;
default:
return null;
}
}
}
/**
目标:工厂模式。
什么是工厂设计模式?
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。
这种类型的设计模式属于创建型模式,它提供了一种创建对象的方式。
之前我们创建类对象时, 都是使用new 对象的形式创建, 除new 对象方式以外,
工厂模式也可以创建对象。
工厂设计模式的作用:
1.对象通过工厂的方法创建返回,工厂的方法可以为该对象进行加工和数据注入。
2.可以实现类与类之间的解耦操作(核心思想,重点)
这样测试类与类之间的联系变少,只需要更新维护工厂类就可以
小结:
工厂模式的思想是提供一个工厂方法返回对象!
*/
public class FactoryDemo {
public static void main(String[] args) {
Computer c1 = FactoryPattern.createComputer("huawei");
c1.start();
Computer c2 = FactoryPattern.createComputer("mac");
c2.start();
}
}
装饰模式
什么是装饰类?
创建一个新类继承父类
在不改变原类的基础之上动态的扩展一个类的功能
定义父类。
定义原始类,继承父类,定义功能。
定义装饰类,继承父类,包装原始类,增强功能!!
/**
共同父类
*/
public abstract class InputStream {
public abstract int read();
public abstract int read(byte[] buffer);
}
package com.itheima.d4_decorator_pattern;
import java.util.Arrays;
/**
原始类
*/
public class FileInputStream extends InputStream{
@Override
public int read() {
System.out.println("低性能的方式读取了一个字节a");
return 97;
}
@Override
public int read(byte[] buffer) {
buffer[0] = 97;
buffer[1] = 98;
buffer[2] = 99;
System.out.println("低性能的方式读取了一个字节数组:" + Arrays.toString(buffer));
return 3;
}
}
/**
装饰类:继承InputStream 拓展原始类的功能
*/
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(buffer);
}
}
/**
装饰模式
定义父类:InputStream
定义实现类:FileInputStream 继续父类 定义功能
定义装饰实现类:BufferedInputStream 继承父类 定义功能 包装原始类,增强功能。
*/
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]));
}
}