DOM4J解析XML文件
dom4j是一个Java的XML API,是jdom的升级品,用来读写XML文件的。另外对比其他API读写XML文件,dom4j是一个十分优秀的JavaXML API,具有性能优异、功能强大和极其易使用的特点,它的性能超过sun公司官方的dom技术!如今越来越多的Java软件、Java框架都在使用dom4j来读写XML文件,例如Sun公司的JAXM、Hinernate等都是使用dom4j来读取并解析配置文件。
作为一名Java 开发者,非常推荐去学习XML 文件的解析方式,无论是深入理解框架底层的解析方式(你就知道怎么编写配置文件了,例如Spring底层的解析方式)、还是在工作中自定义一些特定的配置文件(例如SQL映射文件、数据映射文件等)非常的灵活与实用!
当然这里主要是以解析xml配置文件的方式去介绍dom4j 的在实际项目开发中运用方式,更多写的操作可以自行学习。另外如果单纯的只是解析配置文件非常推荐使用dom4j,性能完全够用!但是要解析有大量数据的xml文件时,就要考虑内存溢出问题,此时dom4j就不怎么合适了,要用SAX 事件驱动解析方式(采用事件驱动模式,对内存消耗较小适用于处理拥有大量数据的xml文件),这种解析方式在另外一篇博客有介绍。
jar 获取 / 引入方式:
1、maven
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.1</version>
</dependency>
2、gradle
implementation group: 'org.dom4j', name: 'dom4j', version: '2.1.1'
implementation group: 'jaxen', name: 'jaxen', version: '1.1.1'
引入jaxen 的依赖是因为使用dom4j的xpath查询xml节点时,需要jaxen 提供支持!否则会抛会java.lang.ClassNotFoundException: org.jaxen.JaxenException 的异常。
这里为什么要提一下gradle 呢?Gradle 抛弃了基于XML的各种繁琐配置,确实更优秀、更简洁,并且SpringBoot 3.0 默认的版本管理器也换成Gradle 了(但是国内Gradle从中央仓库下载依赖是真的慢),未来可能会成为趋势!
1、环境准备
1.1、常用类及方法介绍
DOM4J 常用的类
类名 | 用途 |
---|
Attribute | 定义了 XML 的属性。 | Branch | 指能够包含子节点的节点。如XML元素(Element)和文档(Docuemnts)定义了一个公共的行为 | CDATA | 定义了 XML CDATA 区域 | CharacterData | 是一个标识接口,标识基于字符的节点。如CDATA,Comment, Text. | Comment | 定义了 XML 注释的行为 | Document | 定义了XML 文档 | DocumentType | 定义 XML DOCTYPE 声明 | Element | 定义XML 元素 | ElementHandler | 定义了Element 对象的处理器 | ElementPath | 被 ElementHandler 使用,用于取得当前正在处理的路径层次信息 | Entity | 定义 XML entity | Node | 为dom4j中所有的XML节点定义了多态行为 | NodeFilter | 定义了在dom4j 节点中产生的一个滤镜或谓词的行为(predicate) | ProcessingInstruction | 定义 XML 处理指令 | Text | 定义 XML 文本节点 | Visitor | 用于实现 Visitor模式 | XPath | 在分析一个字符串后会提供一个 XPath 表达式 |
Element 类常见的方法。我们解析XML文件最终都会把标签对转成Element 节点对象,去读取节点属性与节点元素所含有的text 内容,所以这个类非常重要。
方法名 | 含义 |
---|
getQName() | 元素的QName对象 | getNamespace() | 元素所属的Namespace对象 | getNamespacePrefix() | 元素所属的Namespace对象的prefix | getNamespaceURI() | 元素所属的Namespace对象的URI | getName() | 元素的local name | getQualifiedName() | 元素的qualified name | getText() | 元素所含有的text内容,如果内容为空则返回一个空字符串而不是null | getTextTrim() | 元素所含有的text内容,其中连续的空格被转化为单个空格,该方法不会返回null | attributeIterator() | 元素属性的iterator,其中每个元素都是Attribute对象 | attributeValue() | 元素的某个指定属性所含的值 | elementIterator() | 元素的子元素的iterator,其中每个元素都是Element对象 | element() | 元素的某个指定(qualified name或者local name)的子元素 | elementText() | 元素的某个指定(qualified name或者local name)的子元素中的text信息 | getParent | 元素的父元素 | getPath() | 元素的XPath表达式,其中父元素的qualified name和子元素的qualified name之间使用"/"分隔 | isTextOnly() | 是否该元素只含有text或是空元素 |
1.2、项目环境搭建
这里主要已Gradle 来构建一个测试工程,当然也可以使用Maven 来构建,没有任何区别的除了引入jar包的方式。例如项目结构与引入的GAV 坐标如下: 暂时先引入这几个依赖坐标,后面用到什么添加什么即可。搭建好基础环境后,我们用一个完整的项目功能案例,来体验dom4j 的解析过程,与在项目上的使用方式。
2、功能实现
2.1、功能简要说明
我们要完成的项目功能为,基于XML 配置文件完成Excel 数据的导入与导出功能(从前端传入Excel文件完成数据入库或导出表数据至Excel文件)。这个功能看似简单其实做起来会涉及到非常多的东西,例如
1、持久层框架JPA集成(数据库我们采用Oracle ,当然也可以使用MyBatis-Plus+MySQL 看自己的选择)
2、设计XML映射 / 配置文件(实体、Excel标题、数据库表字段的映射关系。通过XML文件实现)最终Excel数据通过xml配置文件获取需要保存到数据库的实体集合。
3、XML文件的解析方式(使用DOM4J 解析)
4、通用工具类的封装(通用的XML解析器)
5、解析Excel文件数据(通过Apache POI 解析)
等等
重要的是学会一种思想,自定义配置文件,自己去解析!去满足特定的场景,例如我们想通过JPA执行复杂原生SQL,或完成自己的动态SQL,就可以把SQL语句写在特定的XML标签上,自己去解析与获取。在来说动态SQL,学会XML文件解析后,完全可以实现MyBatis 的动态SQL功能,只需要设计特定的标签,SQL传参的时候判断有没有这个参数,有则拼接上SQL,没有则不拼接SQL。
2.2、SpringBoot集成JPA
关于更多的JPA知识这里就不多说了。
1、引入相关依赖(JPA/数据库驱动),注意最后两个是最新引入的。
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12';
implementation group: 'org.dom4j', name: 'dom4j', version: '2.1.1';
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.5.5';
compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.20';
implementation group: 'com.alibaba', name: 'fastjson', version: '1.2.75';
implementation group: 'jaxen', name: 'jaxen', version: '1.1.1';
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa';
implementation group: 'com.oracle.database.jdbc', name: 'ojdbc6', version: '11.2.0.4';
}
2、编写application.properties 文件(数据库的连接信息的)
server.port=8080
spring.application.name=example
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@122.41.571.179:1521:helowin
spring.datasource.username=LN
spring.datasource.password=LN
spring.jpa.show-sql=true
3、编写实体类(注意注解的使用方式,SQL脚本在后面)
@Entity
@Table(name = "LN_USER", schema = "LN")
@JsonIgnoreProperties(value = {"hibernateLazyInitializer", "handler"})
public class UserEntity implements Serializable {
private static final long serialVersionUID = 7521045049709813121L;
private Integer id;
private String username;
private String password;
@Id
@Column(name = "ID", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "LN_USER_ID")
@SequenceGenerator(name = "LN_USER_ID", schema = "LN", sequenceName = "S_LN_USER", allocationSize = 1)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "USERNAME")
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Column(name = "PASSWORD")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
SQL脚本
CREATE TABLESPACE LN_TEST
DATAFILE '/home/oracle/app/oracle/oradata/helowin/ln_test.dbf'
SIZE 100M
AUTOEXTEND ON
NEXT 10M
ALTER USER LN DEFAULT TABLESPACE LN_TEST;
CREATE SEQUENCE "LN"."S_LN_USER" MINVALUE 1 MAXVALUE 99999 INCREMENT BY 1 CACHE 20;
CREATE TABLE "LN"."LN_USER" (
"ID" NUMBER(10,0) NOT NULL,
"USERNAME" VARCHAR2(255 BYTE),
"PASSWORD" VARCHAR2(255 BYTE),
CONSTRAINT "SYS_C0011150" PRIMARY KEY ("ID"),
CONSTRAINT "SYS_C0011149" CHECK ("ID" IS NOT NULL) NOT DEFERRABLE INITIALLY IMMEDIATE NORELY VALIDATE
)
TABLESPACE "LN_TEST"
LOGGING
NOCOMPRESS
PCTFREE 10
INITRANS 1
STORAGE (
BUFFER_POOL DEFAULT
)
PARALLEL 1
NOCACHE
DISABLE ROW MOVEMENT
4、编写Dao接口,需要继承JPA提供的JpaRepository<T, ID> 接口
public interface UserDao extends JpaRepository<UserEntity, Integer> {
}
5、编写测试方法,数据库访问是否正常
@RestController
@RequestMapping(value = "/user")
public class UserController {
@Autowired
private UserDao userDao;
@RequestMapping(value = "/getList", method = RequestMethod.GET)
public R getUserList() {
return R.ok().put("data", userDao.findAll());
}
}
|