网站首页 > java教程 正文
在前面的文章中,我们介绍了XML文件的规范与使用。而且XML应用非常广泛,在很多的软件中,会使用XML作为配置文档。那这些配置文档是如何被解析的呢?本文我们将参考《通用源码阅读指导书——MyBatis源码详解》一书介绍如何使用Java解析XML文件。
前面的文章中我们已经说明XML表述了一种树状结构,并通过给出了XML片段的结构树。而XPath(XML Path Language,即,XML路径语言)作为一种小型的查询语言能够根据XML结构树在树中寻找节点。
XPath定义了一组语法,能够从结构树中筛选出满足要求的节点。如果读者对CSS选择器或者jQuery选择器比较熟悉的话,那掌握XPath的语法还是非常简单的,因为这些选择器的语法思路是相通的。
例如XML片段如下:
<?xml version="1.0" encoding="UTF-8"?>
<members>
<user type="student">
<id>1</id>
<name>易哥</name>
<shcool>Sunny School</shcool>
</user>
<user type="student">
<id>2</id>
<name>莉莉</name>
<shcool>Garden School</shcool>
</user>
</members>
我们可以通过下表所示的例子来简单了解下XPath的语法。
路径表达式 含义 . 当前元素 .. 当前元素的父元素 user user元素 /user user根元素 user/id user元素的名为id的直接子元素 user//id user元素的名为id的直接或间接子元素 user/id[1] user元素的名为id的直接子元素中的第一个 user/*[1] user元素的第一个子元素 user/id[last()-1] user元素的名为id的直接子元素中的倒数第二个 //user[@type='student'] 所有type属性值为“student”的user元素 //user[id>3] 所有id子元素值大于3的的user元素
javax.xml.xpath包提供了强大的XPath解析功能,因此我们可以基于它实现XML的解析。
我们可以通过下面的代码解析该XML片段。
String resource = "info.xml";
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream(resource));
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression compile = xpath.compile("/members/user[id=1]");
System.out.println(compile.evaluate(doc));
得到下图所示的输出
在代码中,我们通过“/members/user[id=1]”定位出了一个user元素,该元素满足以下条件:
- 该元素是根元素members的直接子元素
- 该元素含有id子元素,且id子元素值为1
以上内容均参考《通用源码阅读指导书——MyBatis源码详解》一书,接下来,我们跟随本书看MyBatis如何解析配置文件。
MyBatis的配置文件与映射文件均是XML文件,因此解析并读取XML文档中的内容是MyBatis展开后续工作的基础。
MyBatis中的parsing包就是用来进行XML文件解析的包。在解析XML文件的过程,XPathParser类与XNode类是两个最为关键的类,下图给出了这两个类主要关系的类图。
通过图可以看出,XPathParser类中封装了“javax.xml.xpath.XPath”类的对象。我们已经知道XPath对象是XML解析的利器,因此XPathParser类便具有了XML解析的能力。
下面代码给出了XPathParser类的带注释的属性。
// 代表要解析的整个XML文档
private final Document document;
// 是否开启验证
private boolean validation;
// EntityResolver,通过它可以声明寻找DTD文件的方法,例如通过本地寻找,而不是只能通过网络下载DTD文件
private EntityResolver entityResolver;
// MyBatis配置文件中的properties节点的信息
private Properties variables;
// javax.xml.xpath.XPath工具
private XPath xpath;
有必要说明一下,上述“private Properties variables”属性存储的内容就是MyBatis配置文件中properties节点的信息。properties节点会在解析配置文件的最开始就被解析,然后相关信息会被放入“private Properties variables”属性并在解析后续节点时发挥作用,这一点我们不再展开,感兴趣的读者可以参考《通用源码阅读指导书——MyBatis源码详解》一书的“11.3 文档解析中的变量替换”章节。
XPathParser存在多个重载的构造方法,它们均是根据传入的参数完成属性的初始化并构造出XML文档对应的Document对象。除去构造方法外,便是大量提供XML文档中节点解析功能的“eval*”方法,这些方法最后都调用了如下代码所示的evaluate方法。
/**
* 进行XML节点的解析
* @param expression 解析的语句
* @param root 解析根
* @param returnType 返回值类型
* @return 解析结果
*/
private Object evaluate(String expression, Object root, QName returnType) {
try {
// 对指定节点root运行解析语法expression,获得returnType类型的解析结果
return xpath.evaluate(expression, root, returnType);
} catch (Exception e) {
throw new BuilderException("Error evaluating XPath. Cause: " + e, e);
}
}
在evaluate方法中,使用“javax.xml.xpath.XPath”对象进行了节点的解析。因此,整个XPathParser类本质就是对“javax.xml.xpath.XPath”的封装和调用,可以把XPathParser类看作是javax.xml.xpath.XPath类的包装类。
同样地,parsing包中的XNode类可以看作是“org.w3c.dom.Node”类的包装类。“org.w3c.dom.Node”类是用来表示DOM中节点的类,而XNode类只是在“org.w3c.dom.Node”类的基础上提取和补充了几个属性。下面给出了XNode对象的属性。
// org.w3c.dom.Node 表示是XML中的一个节点
private final Node node;
// 节点名,可以从org.w3c.dom.Node中获取
private final String name;
// 节点体,可以从org.w3c.dom.Node中获取
private final String body;
// 节点的属性,可以从org.w3c.dom.Node中获取
private final Properties attributes;
// MyBatis配置文件中的properties信息
private final Properties variables;
// XML解析器XPathParser
private final XPathParser xpathParser;
XNode对象的上述属性中,name、body、attributes这三个属性是从“org.w3c.dom.Node”对象中提取出来的,variables、xpathParser这两个属性补充的。而我们知道XPathParser类具有解析XML节点的能力,也就是说,XNode类中封装了自身了的解析器。在一个类中封装自己的解析器,这是一种非常常见的做法,如此一来这个类不需要外界的帮助便可以解析自身,即获得了自解析能力。
大家可能会有过这样的经历:新安装的电脑上没有解压软件,于是从网络或者朋友那里得到了一份解压软件。可是,拿到手的解压软件安装包却是一个压缩文件。尚未安装解压软件的你必然没法打开压缩文件获得安装包。而自解压文件(SelF-eXtracting,简称SFX)能够帮助你摆脱这个困境。自解析类也有类似的优点,它减少了对外部类的依赖,具有更高的内聚性,也更为易用。
正是得益于XNode类的自解析特性,它本身提供了一些“eval*”方法,从而能够解析自身节点内的信息。
以上内容均参考《通用源码阅读指导书——MyBatis源码详解》一书。
阅读源码确实对编程能力的提升有很大的帮助。把《通用源码阅读指导书——MyBatis源码详解》推荐给大家。这是一本以MyBatis的源码为实例讲述源码阅读方法的书籍,并且附带有示例项目源码,MyBatis的全中文注解。书籍还总结了大量的编程知识和架构经验,对提升编程和架构能力十分有用。
最后,我是高级架构师易哥,这里是架构研究所。真心希望本文能让大家有所收获。
欢迎关注我们,我会偶尔出没分享软件架构和编程相关的干货知识。
猜你喜欢
- 2024-10-17 Qt开发-DOM方式解析XML(qt开发工具)
- 2024-10-17 JAVA 操作笔记-XML(六)(xml在java中怎么用)
- 2024-10-17 作为一名程序猿,你不可不知的Java基础知识的三十个经典问答
- 2024-10-17 Android中XML文件解析,现在了解还不晚
- 2024-10-17 JSP 标准标签库(JSTL)(jsp标签库有哪些)
- 2024-10-17 Spring源码阅读:Spring XML解析机制
- 2024-10-17 XML文件(xml文件怎么打开)
- 2024-10-17 Python如何解析HTML和XML数据(python解析html xml最好的模块)
- 2024-10-17 深入解析Python中的XML处理:理论与实践的结合
- 2024-10-17 XML的解析方式(xml的解析方式有哪些)
你 发表评论:
欢迎- 05-15java使用iText解析PDF文件
- 05-15java 将pdf 形成的图片,每页一张图片 保存为pdf文件
- 05-15Java学习123——虚拟方法调用(Virtual Method Invocation)
- 05-15什么是JNI?为什么会有Native层?如何使用?
- 05-15Socket通信
- 05-15译文:理解Java中的弱引用
- 05-15Java 调用 DeepSeek 模型的完整示例及特点
- 05-15Java 对象和类
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)