Java SE 学习笔记(十九)—— XML、设计模式

目录

  • [1 XML](#1 XML)
    • [1.1 XML 概述](#1.1 XML 概述)
    • [1.2 XML 语法规则](#1.2 XML 语法规则)
    • [1.3 XML 文档约束(了解)](#1.3 XML 文档约束(了解))
      • [1.3.1 DTD 约束](#1.3.1 DTD 约束)
      • [1.3.2 schema 约束](#1.3.2 schema 约束)
  • [2 XML 解析](#2 XML 解析)
    • [2.1 XML 解析概述](#2.1 XML 解析概述)
    • [2.2 Dom4J 解析 XML 文件](#2.2 Dom4J 解析 XML 文件)
    • [2.3 XML 解析案例](#2.3 XML 解析案例)
  • [3 XML 检索](#3 XML 检索)
  • [4 设计模式](#4 设计模式)
    • [4.1 工厂模式](#4.1 工厂模式)
    • [4.2 装饰模式](#4.2 装饰模式)

1 XML

在有些业务场景下,存储数据或者传输数据给别人的时候需要满足一定的规范进行组织

1.1 XML 概述

XML 的全称为(EXtensible Markup Language),是一种 可扩展标记语言,是一种数据表示格式,可以用于自定义数据格式,可以描述非常复杂的数据结构,常用于传输和存储数据。

例如:

xml 复制代码
<?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 语法规则

  1. XML 的创建

就是创建一个 XML 类型的文件,要求文件的后缀名必须使用 xml,如:helloworld.xml

  1. XML 文件的文档声明

XML 文件的文档声明必须在第一行

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>

version : XML 默认的版本号码、该属性是必须存在的
encoding :本 XML 文件的编码

  1. XML 的标签 ( 元素 ) 规则
  • 标签由一对尖括号和合法标识符组成:<name></name>,必须存在一个根标签,有且只能有一个
  • 标签必须成对出现,有开始,有结束 : <name></name>
  • 特殊的标签可以不成对,但是必须有结束标记,如 :<br/>
  • 标签中可以定义属性,属性和标签名空格隔开 ,属性值必须用引号引起来 <student id = "1"></name>
  • 标签需要正确的嵌套
  • XML 文件中可以定义注释信息: <!-- 注释内容 -->
  • XML 文件中可以存在以下特殊字符
    • &lt;< 小于
    • &gt;> 大于
    • &amp;& 和号
    • '' 单引号
    • &quot;" 引号
  • XML 文件可以存在 CDATA 区 (IDEA中输入CD再回车)

示例代码

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<student>
    <msg>
        age &gt; 18 &amp;&amp; age &lt;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 复制代码
<?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文件

java 复制代码
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 类

java 复制代码
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

java 复制代码
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 的四大检索方案

  1. 绝对路径:采用绝对路径获取从根节点开始逐层的查找 /contactList/contact/name 节点列表并打印信息
  1. 相对路径:先得到根节点 contactList,再采用相对路径获取下一级 contact 节点的 name 子节点并打印信息
  1. 全文检索:直接全文搜索所有的 name 元素并打印
  1. 属性查找:在全文中搜索属性,或者带属性的元素

示例代码

XML文件

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

java 复制代码
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 装饰模式

装饰设计模式:创建一个新类,包装原始类,从而在新类中提升原来类的功能。

装饰设计模式的作用:

  • 装饰模式指的是在不改变原类的基础上 ,动态地扩展一个类的功能
相关推荐
好奇的菜鸟15 分钟前
如何在IntelliJ IDEA中设置数据库连接全局共享
java·数据库·intellij-idea
巴伦是只猫35 分钟前
【机器学习笔记Ⅰ】13 正则化代价函数
人工智能·笔记·机器学习
DuelCode1 小时前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
优创学社21 小时前
基于springboot的社区生鲜团购系统
java·spring boot·后端
好好研究1 小时前
学习栈和队列的插入和删除操作
数据结构·学习
幽络源小助理1 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
猴哥源码1 小时前
基于Java+springboot 的车险理赔信息管理系统
java·spring boot
YuTaoShao2 小时前
【LeetCode 热题 100】48. 旋转图像——转置+水平翻转
java·算法·leetcode·职场和发展
新中地GIS开发老师2 小时前
新发布:26考研院校和专业大纲
学习·考研·arcgis·大学生·遥感·gis开发·地理信息科学
Dcs3 小时前
超强推理不止“大”——手把手教你部署 Mistral Small 3.2 24B 大模型
java