使用 XML 工具: digester
小于 1 分钟
Digester 最初是 Struct MVC 框架的一个模块,后加入到 Apache Commons 组件库中,形成了一个功能强悍的 XML 解析库。
Digester 底层基于 SAX + 事件驱动 + 栈的方式实现的,这三个技术作用如下:
- SAX —— 解析 XML
- 事件驱动 —— 在 SAX 解析的过程中加入事件来了支持对象映射
- 栈 —— 解析 XML 元素的开始和结束时,需要通过 XML 元素映射的类对象入栈和出栈来完成事件的调用
Digester 解析 XML 的核心流程:
- 开始解析节点,是否需要创建一个类
- 开始解析节点,是否需要入栈操作
- 结束解析节点,是否需要执行某个方法
- 结束解析节点,是否需要出栈操作
读
XML 文件
<?xml version="1.0" encoding="utf-8" ?>
<my-content>
<web-site>http://www.example.org</web-site>
<owner>steven</owner>
<description>原生 java xml 操作测试消息</description>
<posts>
<!-- 我是注释 -->
<post id="P001">
<title>文章标题01</title>
<content>hello world 01!</content>
</post>
<post id="P002">
<title>文章标题02</title>
<content>hello world 02!</content>
</post>
</posts>
</my-content>
测试用例
package org.example;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.digester3.BeanPropertySetterRule;
import org.apache.commons.digester3.Digester;
import org.apache.commons.digester3.Rule;
import org.example.entity.MyContent;
import org.example.entity.Post;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.UUID;
@Slf4j
public class XmlDigesterReadTest {
@Test
void test() {
Digester digester = new Digester();
try {
File file = new File(Objects.requireNonNull(getClass().getResource("/")).getFile(), "message001.xml");
Assertions.assertTrue(file.exists());
// 映射
// 当使用 addObjectCreate() 方法时,会创建一个对象进栈,许多重要的方法都是相对于栈顶元素或次栈顶元素来进行的。
digester.addObjectCreate("my-content", MyContent.class); // 入栈
digester.addObjectCreate("my-content/posts", ArrayList.class); // 入栈
digester.addObjectCreate("my-content/posts/post", Post.class); // 入栈
digester.addSetNext("my-content/posts/post", "add"); // 出栈
digester.addSetNext("my-content/posts", "setPosts"); // 出栈
// 设置元素值映射
digester.addBeanPropertySetter("my-content/web-site", "webSite");
digester.addBeanPropertySetter("my-content/description", "description");
digester.addBeanPropertySetter("my-content/posts/post/title", "title");
// 设置元素上的属性值映射
digester.addSetProperties("my-content/posts/post", "id", "id");
// 添加自定义映射规则
final String random = UUID.randomUUID().toString();
digester.addRule("my-content/owner", new BeanPropertySetterRule("owner"));
digester.addRule("my-content/posts/post/content", new Rule() {
@Override
public void body(String namespace, String name, String text) throws Exception {
System.out.println("name = " + name);
System.out.println("text = " + text);
BeanUtils.populate(getDigester().peek(), new HashMap() {
{
this.put("content", text+random);
}
});
}
});
// 解析
MyContent parse = digester.parse(file);
log.info("{}", parse);
// 校验
Assertions.assertEquals("http://www.example.org", parse.getWebSite());
Assertions.assertEquals("steven", parse.getOwner());
Assertions.assertEquals(2, parse.getPosts().size());
Assertions.assertArrayEquals(new String[] {"P001", "P002"}, parse.getPosts().stream().map(Post::getId).toArray());
Assertions.assertArrayEquals(new String[] {"文章标题01", "文章标题02"}, parse.getPosts().stream().map(Post::getTitle).toArray());
Assertions.assertArrayEquals(new String[] {"hello world 01!"+random, "hello world 02!"+random}, parse.getPosts().stream().map(Post::getContent).toArray());
} catch (IOException | SAXException e) {
throw new RuntimeException(e);
}
}
}