MyBatis源码分析——基础支持(xml文档解析支持)

141 阅读3分钟

MyBatis运行中会用大量的SQL或者配置都写在了XML文件中。而读取XML是一件非常繁琐的事,尽管JDK提供了原生支持解析XML的API,以及一些开源框架诸如dom4j等。但是为了防止繁琐的解析步骤和过量引入依赖包,MyBatis自己一套解析XML的工具。在Xpath的语法基础之上方便对XML的操作。

原生JDK操作XML(不依赖框架) - 掘金 (juejin.cn)

为什么Mybatis自己封装XML解析工具

  1. JDK自带工具过于笨重。使用步骤繁琐。
  2. 引入dom4j等依赖会导致项目体积变大,性价比不高。
  3. 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表达式获取对应的值。

image.png

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;
  .....
}