一、基本介绍
1. 概念解释
在 XML
文件中有一个十分重要的概念 XPath
,简单而言即用于定义元素的位置,下面通过示例从而更直观的了解 XPath
的定义。
如一个 XML
的文件内容如下,其中 <name></name>
等通常称其为标签组,而 id
标签中的 type
称之为 tag
。且值 Alex
对应的标签 name
其相应的 XPath
则为 student/name
,即用于定位元素的路径。
<student>
<id type=string>1</id>
<name>Alex</name>
</student>
2. 依赖导入
Apache digester
是 Java
中一种 XML
解析框架,能够在耗费最低系统资源的前提下实现高效 XML
文件解析。
使用方法简单快捷,在 Maven
项目中引入下述依赖即可开箱即用。
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-digester3</artifactId>
<version>3.2</version>
</dependency>
3. 文件数据
在开始之前先准备一个 XML
数据文件,文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<entityContainer>
<entity>
<id>1</id>
<name>alex</name>
<attribute>
<key>math</key>
<value>80</value>
</attribute>
</entity>
<entity>
<id>2</id>
<name>beth</name>
<attribute>
<key>math</key>
<value>85</value>
</attribute>
</entity>
</entityContainer>
二、基础操作
1. 实体对象
相对应于 XML
文件,需要创建对应的 Java
实体类用作载体。
同上述准备的 XML
文件内容此处创建了三个对应的实体类 EntityContainer
,Entity
与 Attribute
。
@Data
public class EntityContainer {
private List<Entity> entityList = new ArrayList<>();
public void addEntity(Entity entity) {
entityList.add(entity);
}
}
@Data
public class Entity {
private String id;
private String name;
private Attribute attribute;
public void setAttribute(Attribute attribute) {
this.attribute = attribute;
}
}
@Data
public class Attribute {
private String key;
private String value;
}
2. 规则配置
完成上述步骤后即可开始正式的文件内容解析,Digester
解析工具其提供的规则配置方法参考下表:
方法 | 作用 |
---|---|
addObjectCreate() | 设置与 Java 对象的映射关系。 |
addBeanPropertySetter() | 设置 XPath 与实体对象属性的匹配。 |
addSetProperties() | 设置 tag 与类属性的映射关系。 |
addSetNext() | 标签内嵌套单个或多个标签时用于指定添加方法。 |
3. 读取示例
因此,之前提到的 XML
文件其对应的解析示例如下,其中 parse()
方法支持输入文件流与文本块的方式,前者基于事件驱动后者基于内存驱动,在解析大文件的情况下前者显然能够占用更少的资源。
public class DigestXmlTest {
private final String location = "src\\main\\resources\\xml\\data.xml";
@Test
public void basicTest() {
Digester digester = new Digester();
digester.addObjectCreate("entityContainer", EntityContainer.class);
digester.addSetProperties("entityContainer");
digester.addObjectCreate("entityContainer/entity", Entity.class);
// addBeanPropertySetter(): march xml label with bean field
digester.addBeanPropertySetter("entityContainer/entity/id", "id");
digester.addBeanPropertySetter("entityContainer/entity/name", "name");
// addSetNext(): when march multiple item then put to collection
digester.addSetNext("entityContainer/entity", "addEntity");
digester.addObjectCreate("entityContainer/entity/attribute", Attribute.class);
digester.addBeanPropertySetter("entityContainer/entity/attribute/key", "key");
digester.addBeanPropertySetter("entityContainer/entity/attribute/value", "value");
digester.addSetNext("entityContainer/entity/attribute", "setAttribute");
try (FileReader reader = new FileReader(location)) {
EntityContainer container = digester.parse(reader);
System.out.println(container);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
三、进阶配置
1. 规则定义
在上述的示例中通过配置的规则即可实现数据文件的解析,但每次使用都需定义解析规则,显然过于繁杂。
因此,在 Digester
中提供了 AbstractRulesModule
可实现规则配置的统一管理,一次定义即可全局使用。
public class MyRuleModule extends AbstractRulesModule {
@Override
protected void configure() {
forPattern("entityContainer").createObject().ofType(EntityContainer.class);
forPattern("entityContainer/entity").createObject().ofType(Entity.class);
forPattern("entityContainer/entity/id").setBeanProperty();
forPattern("entityContainer/entity/name").setBeanProperty();
forPattern("entityContainer/entity").setNext("addEntity");
forPattern("entityContainer/entity/attribute").createObject().ofType(Attribute.class);
forPattern("entityContainer/entity/attribute/key").setBeanProperty();
forPattern("entityContainer/entity/attribute/value").setBeanProperty();
forPattern("entityContainer/entity/attribute").setNext("setAttribute");
}
}
2. 读取示例
上述配置方式相对应的读取示例代码如下:
public class DigestXmlTest {
private final String location = "src\\main\\resources\\xml\\data.xml";
@Test
public void ruleTest() {
// write once, use anywhere
final DigesterLoader loader = DigesterLoader.newLoader(new MyRuleModule());
final Digester digester = loader.newDigester();
// read and parse
try (FileReader reader = new FileReader(location)) {
EntityContainer container = digester.parse(reader);
System.out.println(container);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
四、注解方式
1. 注解介绍
除了代码配置解析规则之外,在 3.x
版本中提供了注解的方法,从而实现更便捷配置。
Digester
解析规则相配套的注解及其描述参考下表:
注解 | 描述 |
---|---|
@ObjectCreate | 匹配的 XPath 开始标识。 |
@BeanPropertySetter | 匹配标签对应的 XPath。 |
@SetProperty | 匹配标签的 tag,通过 attributeName 属性配置。 |
@SetNext | 作用于方法,用于赋值标签组,即嵌套的子标签组。 |
2. 对象定义
修改之前创建的实体类,通过注解方式配置 XPath
的值实现映射,对应代码如下:
@Data
@ObjectCreate(pattern = "entityContainer")
public class EntityContainer {
private List<Entity> entityList = new ArrayList<>();
@SetNext
public void addEntity(Entity entity) {
entityList.add(entity);
}
}
@Data
@ObjectCreate(pattern = "entityContainer/entity")
public class Entity {
@BeanPropertySetter(pattern = "entityContainer/entity/id")
private String id;
@BeanPropertySetter(pattern = "entityContainer/entity/name")
private String name;
private Attribute attribute;
@SetNext
public void setAttribute(Attribute attribute) {
this.attribute = attribute;
}
}
@Data
@ObjectCreate(pattern = "entityContainer/entity/attribute")
public class Attribute {
@BeanPropertySetter(pattern = "entityContainer/entity/attribute/key")
private String key;
@BeanPropertySetter(pattern = "entityContainer/entity/attribute/value")
private String value;
}
3. 规则定义
类似的通过继承 FromAnnotationsRuleModule
配置读取实体类的注解信息。
public class MyAnnotationModule extends FromAnnotationsRuleModule {
@Override
protected void configureRules() {
bindRulesFrom(EntityContainer.class);
}
}
4. 读取示例
上述步骤完成之后即可实现文件解析,同样是一次定义全局可用,对应的示例代码如下:
public class DigestXmlTest {
private final String location = "src\\main\\resources\\xml\\data.xml";
@Test
public void annotationTest() {
// write once, use anywhere
final DigesterLoader loader = DigesterLoader.newLoader(new MyAnnotationModule());
final Digester digester = loader.newDigester();
// read and parse
try (FileReader reader = new FileReader(location)) {
EntityContainer container = digester.parse(reader);
System.out.println(container);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
参考文章