最近在看tomcat源代码,发现tomcat的xml文件都是通过Digester解析自动生成了对象,于是对Digester研究了下,为了防止自己忘记便记录下来。首先通过一个小程序来了解Digester,解析下面的school.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<school name="xx大学" address="xx省xx市">
<department description="计算机系">
<student name="小明" sex="男"/>
<student name="小红" sex="女"/>
<student name="小王" sex="男"/>
</department>
<department description="数学系">
<student name="小李" sex="男"/>
<student name="小新" sex="男"/>
<student name="小赵" sex="女"/>
</department>
</school>
public class DigesterForSchool {
public static void main(String[] args) throws Exception{
String path = System.getProperty("user.dir") + File.separator + "etc";
Digester digester = new Digester();
digester.addObjectCreate("school", "com.test.digester.School");
digester.addSetProperties("school");
digester.addObjectCreate("school/department", "com.test.digester.Department");
digester.addSetProperties("school/department");
digester.addSetNext("school/department", "addDepartment");
digester.addObjectCreate("school/department/student",
"com.test.digester.Student");
digester.addSetNext("school/department/student", "addStudent");
digester.addSetProperties("school/department/student");
School school = (School)digester.parse(new File(path, "school.xml"));
System.out.println(school);
}
}
输出结果如下:
school name: xx大学, address: xx省xx市
departments: [
department description: 计算机系
students: [
student name: 小明 sex: 男,
student name: 小红 sex: 女,
student name: 小王 sex: 男],
department description: 数学系
students: [
student name: 小李 sex: 男,
student name: 小新 sex: 男,
student name: 小赵 sex: 女]]
可以发现Digester将school.xml文件的内容,转换为了相对应的对象。那Digester到底是怎样工作的呢?查看Digester源代码我们发现:
import org.xml.sax.XMLReader;
public class Digester extends DefaultHandler
原来Digester是SAX解析器事件处理类DefaultHandler的子类,我们知道SAX是基于事件驱动解析xml文件,当SAX扫描到文档(document)开始、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。所以Digester在事件处理函数中做了相应的处理,让其能按照自己的规则生成对象数据。现在来看看Digester在事件处理函数中做了哪些处理:
public void startElement( String namespaceURI, String localName, String qName, Attributes list ) throws SAXException {
...
List<Rule> rules = getRules().match( namespaceURI, match, localName, list );
matches.push( rules );
...
for ( int i = 0; i < rules.size(); i++ ) {
...
Rule rule = rules.get(i);
rule.begin( namespaceURI, name, list );
...
}
}
public void characters( char buffer[], int start, int length ) throws SAXException {
...
bodyText.append( buffer, start, length );
}
public void endElement( String namespaceURI, String localName, String qName ) throws SAXException {
...
List<Rule> rules = matches.pop();
...
for ( int i = 0; i < rules.size(); i++ ) {
....
Rule rule = rules.get( i );
....
rule.body( namespaceURI, name, bodyText );
}
...
for ( int i = 0; i < rules.size(); i++ ) {
....
Rule rule = rules.get( i );
....
rule.end( namespaceURI, name, bodyText );
}
....
}
在执行startElement()方法和endElement()方法的时候都用到Rule类的相关方法,现在再看看api中对Rule类的描述:Concrete implementations of this class implement actions to be taken when a corresponding nested pattern of XML elements has been matched. 当匹配到xml某个模式时,Rule的具体实现类的动作将被执行。在解析xml文档时,当Digester实例匹配到某个模式的元素开始标签时,调用相对应的Rule对象的begin方法(见startElement()方法),当匹配到相应元素的结束标签时,调用Rule对象的body()和end()方法(见endElement()方法)。当Digester类可以包含0个或多个Rule对象。在Digester实例中,这些规则和其相关联的模式都存储在Rules接口表示的一类集合中。每当把一条规则添加到Digester实例中时,Rule对象也都会被添加到Rules对象中。当调用addObjectCreate()、addCallMethod()方法、addSetNext()方法或其他方法时,都会间接调用Digester类的addRule()方法。该方法会将一个Rule对象和它所匹配的模式添加到Digester对象的Rules集合中。
public void addObjectCreate( String pattern, String className ) {
addRule( pattern, new ObjectCreateRule( className ) );
}
public void addRule( String pattern, Rule rule ) {
rule.setDigester( this );
getRules().add( pattern, rule );
}
public Rules getRules() {
if ( this.rules == null ) {
this.rules = new RulesBase();
this.rules.setDigester( this );
}
return ( this.rules );
}
Digester已经预定义了一些规则,可以直接使用这些规则,如果这些规则仍然不满足需求,可以实现自己的规则,常用的预定义规则如下:
1.创建对象:
ObjectCreateRule:利用指定类的默认构造函数。创建该类的一个对象,并把对象压入栈,当元素处理结束时,对象被弹出。
FactoryCreateRule:利用指定的工厂类创建一个对象,用于处理没有提供默认构造函数的类。注意的是用于该规则的工厂类必须实现org.apache.commons.digester.ObjectCreationFactory接口。
2.设置属性:
SetPropertiesRule:利用指定名称的XML元素属性值,设置顶层Bean的属性。
BeanPropertySetterRule:把顶层Bean的指定名称的属性设置成当前XML元素包含的字符数据。(通常用来处理<element>10</element>之类的结构)。
SetPropertyRule:设置顶层Bean的一个属性。无论是Bean属性的名称,还是赋予该属性的值,都在当前XML元素中以属性的形式指定,例如:<student key="age" value="10" />。
3.对象之间关系:
SetNextRule:peek出栈顶对象和栈顶下一个对象,将栈顶对象作为参数传递给栈顶下一个元素。
SetTopRule:把栈顶下一个对象传递给顶层对象。
SetRootRule:调用栈底对象的一个方法,并把栈顶的对象作为参数传入。
4.调用方法:
CallMethodRule:调用顶层Bean的指定名称的方法。被调用的方法可以有任意多个参数,参数的值通过后继的CallParamRule给出。
CallParamRule:表示方法调用的参数。参数的值或者取自指定名称的XML元素的属性,或者是当前元素包含的原始字符数据。这个规则要求用一个整数指定它在参数列表中的位置。
Digester实例内部维护着一个用于临时存储创建对象的栈和一个临时存储参数的栈(这个栈主要是用于CallMethodRule和CallParamRule使用,可以自行查阅源代码),如果实现自己的Rule时使用到了Digester中的栈,在begin()方法中,将一个Object push进去,一定要记得在end()方法中pop出来。Rule的api也说道:If a rule wishes to manipulate a digester stack (the default object stack, a named stack, or the parameter stack) then it should only ever push objects in the rule's begin method and always pop exactly the same number of objects off the stack during the rule's end method. Of course peeking at the objects on the stacks can be done from anywhere. 那现在我们来实现一个自定义规则,将上面的xml文件的student元素修改下命名为school2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<school name="xx大学" address="xx省xx市">
<department id="1" description="计算机系">
<student name="小明" sex="男" birthday="1990-01-01 00:00:00"/>
<student name="小红" sex="女" birthday="1991-01-01 00:00:00"/>
<student name="小王" sex="男" birthday="1992-01-01 00:00:00"/>
</department>
<department id="2" description="数学系">
<student name="小李" sex="男" birthday="1990-01-02 00:00:00"/>
<student name="小新" sex="男" birthday="1991-01-02 00:00:00"/>
<student name="小赵" sex="女" birthday="1992-01-02 00:00:00"/>
</department>
</school>
student元素新增了一个属性"birthday",在Student类中新增了一个成员变量Date型的birthday,这时在给birthday属性赋值时就不能直接调用addSetProperties()方法了,因为从xml解析到的birthday是string类型的数据,如果直接调用addSetProperties()方法会抛出类型转换异常,所以写了一个新的设置属性规则和一个将字符串日期类型转换为Date型数据的规则,代码如下:
public class SetAllPropertiesRule extends Rule {
protected Map<String,String> excludes = new HashMap<String,String>();
public SetAllPropertiesRule() {}
/**
* 构造一个SetAllPropertiesRule
* @param exclude 不需要设置属性值的属性名数组
*/
public SetAllPropertiesRule(String[] exclude) {
for (int i=0; i<exclude.length; i++ ) {
if (exclude[i]!=null) {
this.excludes.put(exclude[i],exclude[i]);
}
}
}
@Override
public void begin(String namespace, String name, Attributes attributes)
throws Exception {
Map<String, String> values = new HashMap<String, String>();
for (int i = 0; i < attributes.getLength(); i++) {
String attributeName = attributes.getLocalName(i);
if ("".equals(attributeName)) {
attributeName = attributes.getQName(i);
}
String value = attributes.getValue(i);
if (!excludes.containsKey(attributeName)){
values.put(attributeName, value );
}
}
populate(getDigester().peek(), values);
}
}
public class ConvertStringToDateRule extends Rule {
private SimpleDateFormat format = null;;
private String attributeName = null;
/**
* 构造一个ConvertStringToDateRule
* @param pattern 需要转换的字符串日期格式
*/
public ConvertStringToDateRule(String pattern) {
this(pattern, null);
}
/**
* 构造一个ConvertStringToDateRule
* @param pattern 需要转换的字符串日期格式
* @param attributeName 需要转换的元素属性名,如果为null则将元素间的字符串转换,
* 如:</element>2012-01-01 00:00:00</element>
*/
public ConvertStringToDateRule(String pattern, String attributeName) {
this.attributeName = attributeName;
format = new SimpleDateFormat(pattern);
}
@Override
public void begin(String namespace, String name, Attributes attributes)
throws Exception {
if(attributeName == null) {
return;
}
String str = attributes.getValue(attributeName);
Date date = format.parse(str);
getDigester().push(date);
}
@Override
public void body(String namespace, String name, String text)
throws Exception {
if(attributeName == null) {
Date date = format.parse(text);
getDigester().push(date);
}
}
@Override
public void end(String namespace, String name) throws Exception {
getDigester().pop();
}
}
public class DigesterForSchool2 {
public static void main(String[] args) throws Exception {
String path = System.getProperty("user.dir") + File.separator + "etc";
Digester digester = new Digester();
digester.addObjectCreate("school", "com.test.digester.school2.School");
digester.addSetProperties("school");
digester.addObjectCreate("school/department",
"com.test.digester.school2.Department");
digester.addSetProperties("school/department");
digester.addSetNext("school/department", "addDepartment");
digester.addObjectCreate("school/department/student",
"com.test.digester.school2.Student");
digester.addSetNext("school/department/student", "addStudent");
digester.addRule("school/department/student", new SetAllPropertiesRule(
new String[] { "birthday" }));
digester.addRule("school/department/student",
new ConvertStringToDateRule("yyyy-MM-dd hh:mm:ss", "birthday"));
digester.addSetNext("school/department/student", "setBirthday");
School school = (School) digester.parse(new File(path, "school2.xml"));
System.out.println(school);
}
}
输出结果如下:
school name: xx大学 address: xx省xx市
departments: [
department id: 1 description: 计算机系
students: [
student name: 小明 sex: 男 birthday: Mon Jan 01 00:00:00 CST 1990,
student name: 小红 sex: 女 birthday: Tue Jan 01 00:00:00 CST 1991,
student name: 小王 sex: 男 birthday: Wed Jan 01 00:00:00 CST 1992],
department id: 2 description: 数学系
students: [
student name: 小李 sex: 男 birthday: Tue Jan 02 00:00:00 CST 1990,
student name: 小新 sex: 男 birthday: Wed Jan 02 00:00:00 CST 1991,
student name: 小赵 sex: 女 birthday: Thu Jan 02 00:00:00 CST 1992]]
分享到:
相关推荐
DeepSeek与AI幻觉-清华大学团队制作 一、什么是AI幻觉 (定义与基础概念) 二、DeepSeek为什么会产生幻觉 (聚焦特定AI模型的幻觉成因分析) 三、AI幻觉评测 (评估AI幻觉的频率、类型与影响的方法) 四、如何减缓AI幻觉 (解决方案与技术优化方向) 五、AI幻觉的创造力价值 (探讨幻觉在创新场景中的潜在益处,如艺术生成、灵感激发等)
协同过滤算法商品推荐系统(源码+数据库+论文+ppt)java开发springboot框架javaweb,可做计算机毕业设计或课程设计 【功能需求】 前台用户可以实现注册登录、商品浏览,在线客服,加入购物车,加入收藏,下单购买,个人信息管理,收货信息管理,收藏管理,评论功能。 后台管理员可以进行用户管理、商品分类管理、商品信息管理、订单评价管理、系统管理、订单管理。 【环境需要】 1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Eclipse,Myeclipse都可以。 3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可 4.数据库:MySql 5.7/8.0等版本均可; 【购买须知】 本源码项目经过严格的调试,项目已确保无误,可直接用于课程实训或毕业设计提交。里面都有配套的运行环境软件,讲解视频,部署视频教程,一应俱全,可以自己按照教程导入运行。附有论文参考,使学习者能够快速掌握系统设计和实现的核心技术。
MES系统数字化工厂解决方案.pptx
MUI调用照片以及裁剪和图库照片上传到服务器
GPT付费体验系统最新版系统是一款基于ThinkPHP框架开发的AI问答小程序, 是基于国外很火的ChatGPT进行开发的Ai智能问答小程序。这是一种基于人工智能技术的问答系统, 可以实现智能回答用户提出的问题。相比传统的问答系统,ChatGPT可以更加准确地理解用户的意图, 提供更加精准的答案。同时系统采用了最新的GPT3.5接口与GPT4模型,同时还支持型,文心一言,腾讯混元, 讯飞星火,通义千问,DeepSeeK,智普等等国内各种大模型,可以更好地适应不同的应用场景,支持站点无限多开, 可以说ChatGPT付费创作系统目前国内相对体验比较好的一款的ChatGPT及多接口软件系统。 新增接入DeepSeek-R1、DeepSeek-V3(Ollama自部署和第三方均支持)、高级通道增加DeepSeek、 支持AI接口输出的reasoning_content字段(新的推理输出格式)、更新模型库、修复导出Excel的bug等功能, 优化了云灵Midjourney接口,出图更快更稳定。小程序端变化不大该系统版本测试下来比较完美, 老版本升级时数据库结构同步下,同时把原来
内容概要:本文档详细介绍了一款基于Java技术的美食点餐管理平台的设计与实现。该平台旨在优化传统餐饮行业的服务流程,通过智能化的点餐系统、高效的订单处理、智能库存管理和数据分析等功能,为用户提供便捷高效的点餐体验,并提升餐厅管理效率和服务质量。系统涵盖了前端设计、后端开发、数据库设计等方面,采用了成熟的Java技术和现代Web开发框架,如Spring Boot、Vue.js或React,确保系统的高效性和稳定性。此外,文档还包括详细的用户界面设计、模块实现以及系统部署指南,帮助开发者理解和搭建该平台。 适合人群:具备一定的Java编程基础和技术经验的研发人员、IT从业者以及有意开发类似系统的企业和个人。 使用场景及目标:①为餐厅提供一个集点餐、订单处理、库存管理于一体的高效平台;②优化传统餐饮服务流程,提升客户服务体验;③利用大数据分析辅助决策,助力餐饮企业精细化运营;④通过集成多种支付方式和其他外部系统,满足多样化的商业需求。 其他说明:本项目不仅提供了完整的技术方案和支持文档,还针对实际应用场景提出了多个扩展方向和技术优化思路,旨在引导用户不断迭代和完善该平台的功能和性能。
相场模拟与激光制造技术:选择性激光烧结、激光融覆中的凝固与枝晶生长研究,相场模拟与激光制造技术:选择性激光烧结、激光融覆及凝固过程中的枝晶生长研究,相场模拟 选择性激光烧结 激光融覆 凝固 枝晶生长 ,相场模拟; 选择性激光烧结; 激光融覆; 凝固; 枝晶生长,相场模拟与激光工艺:枝晶生长的凝固过程研究
项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行;功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
关于加强新能源汽车安全管理涉及的法规标准分析.pptx
项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行,功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行;功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
UI+svg格式
关于乘用车燃料消耗量评价方法及指标强制性国家标准的分析.pptx
1、文件内容:openjpeg-1.5.1-18.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/openjpeg-1.5.1-18.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊
FPGA Verilog实现BT656与1120视频协议组帧解帧代码详解:含文档介绍与仿真验证,FPGA Verilog实现BT656与1120视频协议组帧解帧代码详解:含文档介绍与仿真验证,fpga verilog实现视频协议bt656和1120组帧解帧代码 有文档介绍协议,有mod仿真,matlab代码仿真 ,FPGA; Verilog; BT656协议; 1120组帧解帧代码; 文档介绍; Mod仿真; Matlab代码仿真,FPGA Verilog:实现BT656与1120组帧解帧代码的仿真与文档化研究
基于 RAG 与大模型技术的医疗问答系统,利用 DiseaseKG 数据集与 Neo4j 构 建知识图谱,结合 BERT 的命名实体识别和 34b 大模型的意图识别,通过精确的知识检索和问答生成, 提升系统在医疗咨询中的性能,解决大模型在医疗领域应用的可靠性问题。.zip项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行,功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行;功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
抖音视频带货:行业趋势与营销策略.pptx
西门子动态密码程序:学习随机码生成与指针存储数据,Smartline触摸屏操作指南及编程视频教程,西门子动态密码程序:学习随机码生成与存储数据的智能之旅(视频讲解),200smart动态密码程序,触摸屏是smartline,西门子动态密码程序,,随机码的产生,指针用法存储数据,非常适合学习,而且是自己程序,还专门录制了一段视频来讲解编程的思路和画面的操作步骤。 ,200smart动态密码程序; touchscreen: smartline; 西门子动态密码程序; 随机码生成; 指针用法存储数据; 自学编程; 程序录制视频讲解。,西门子动态密码程序:触摸屏Smartline随机码生成与指针存储技术解析