MyBatis运行中会用大量的SQL或者配置都写在了XML文件中。而读取XML是一件非常繁琐的事,尽管JDK提供了原生支持解析XML的API,以及一些开源框架诸如dom4j等。但是为了防止繁琐的解析步骤和过量引入依赖包,MyBatis自己一套解析XML的工具。在Xpath的语法基础之上方便对XML的操作。
原生JDK操作XML(不依赖框架) - 掘金 (juejin.cn)
为什么Mybatis自己封装XML解析工具
- JDK自带工具过于笨重。使用步骤繁琐。
- 引入dom4j等依赖会导致项目体积变大,性价比不高。
- mybatis中确实可能会大量的使用XML文件。所以封装一套工具解析mybatis格式的xml文件是有必要的。
xml基础
了解即可,对解析XML中的元素理解有所帮助:DTD语法基础
XPath语法基础
XPath 使用路径表达式来选取 XML 文档中的节点或节点集。节点是通过沿着路径 (path) 或者步 (steps) 来选取的。
XML实例
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>
<book>
<title lang="eng">Learning XML</title>
<price>39.95</price>
</book>
</bookstore>
| 表达式 | 描述 |
|---|---|
| nodename | 选取此节点的所有子节点。 |
| / | 从根节点选取(取子节点)。 |
| // | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置(取子孙节点)。 |
| . | 选取当前节点。 |
| .. | 选取当前节点的父节点。 |
| @ | 选取属性。 |
在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:
| 路径表达式 | 结果 |
|---|---|
| bookstore | 选取 bookstore 元素的所有子节点。 |
| /bookstore | 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! |
| bookstore/book | 选取属于 bookstore 的子元素的所有 book 元素。 |
| //book | 选取所有 book 子元素,而不管它们在文档中的位置。 |
| bookstore//book | 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 |
| //@lang | 选取名为 lang 的所有属性。 |
XPathParser
XPathParser提供了一系列的eval*方法,这些方法可以通过xpath表达式获取对应的值。
public class XPathParser {
private Document document;
private boolean validation;
private EntityResolver entityResolver;
private Properties variables;
private XPath xpath;
public Short evalShort(String expression) {
return evalShort(document, expression);
}
public Short evalShort(Object root, String expression) {
return Short.valueOf(evalString(root, expression));
}
public Integer evalInteger(String expression) {
return evalInteger(document, expression);
}
public Integer evalInteger(Object root, String expression) {
return Integer.valueOf(evalString(root, expression));
}
// 还有很多不再一一列举
}
这些eval*的方法最终都会调用evalString方法,不过他们最终调用的还是通过XPath.parse方法来实现对XML的解析。
public String evalString(Object root, String expression) {
//1.先用xpath解析
String result = (String) evaluate(expression, root, XPathConstants.STRING);
//2.再调用PropertyParser去解析,也就是替换 ${} 这种格式的字符串
result = PropertyParser.parse(result, variables);
return result;
}
private Object evaluate(String expression, Object root, QName returnType) {
return xpath.evaluate(expression, root, returnType);
}
XNode
XNode是对JDK自带的Node对象的封装。原生JDK的Node对象就相当于XML中的一个标签节点。比如下面的xml片段
<a>
<b>1</b>
</a>
是由两个Node节点嵌套而成。最内层的Node就是<b>1</b>。标签名称是b,标签的文本内容是1
public class XNode {
//org.w3c.dom.Node
private Node node;
//以下都是预先把信息都解析好,放到map等数据结构中(内存中)
private String name;
private String body;
private Properties attributes;
private Properties variables;
//XPathParser方便xpath解析
private XPathParser xpathParser;
.....
}