mybatis配置階段—— xml解析工具

概述

接下來我們進入mybatis的初始化配置階段。

配置階段就是讀取mybatis的配置文件及我們編寫的XML文件。

在講解mybatis的初始化配置之前,我們先了解初始化配置階段要用到的基礎支撐組件。

這一篇講解的是xml文件解析器組件

DOM

java編程中我們常見的XML解析方式有三種:

- DOM解析方式:加載整個XML到內存構建DOM樹,數據量較大時,較消耗內存

- SAX解析方式:基於事件模型的XML解析方式,流式處理方式,處理XML文檔只能向後單項進行,沒法自由導航,且需要開發人員自己維護節點關係,面對複雜的XML程序會比較複雜。

StAX解析方式:同時支持DOM和SAX解析方式。

上面僅對java中常見的XML解析幾種方式做簡要介紹,大致瞭解即可。

mybatis採用的是DOM解析方式,並結合了XPath工具。

XPath之於XML類似於Sql之於數據庫。就是XML的一個查詢工具。

通過一段簡單代碼瞭解DOM和XPath

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yanlink.mapper.SysUserMapper">

    <resultMap id="sysUserMap" type="com.yanlink.entity.SysUser">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="sex" column="sex"/>
        <result property="password" column="password"/>
    </resultMap>

    <select id="getUser" resultType="SysUser">
        select id,name,password,sex from sys_user where id=#{id}
    </select>
</mapper>

上面是一個我們經常編寫的操作數據庫的xml文件

下面我通過xpath來讀取這個xml文件

public class XPathDemo {
    public static void main(String[] args) {
        try {
            InputStream inputStream = XPathDemo.class.getResourceAsStream("/mapper/SysUserMapper.xml");

            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document document = db.parse(inputStream);

            XPath xPath =  XPathFactory.newInstance().newXPath();
            Node mapper = (Node) xPath.evaluate("/mapper", document, XPathConstants.NODE);
            System.out.println(mapper.getNodeName()+" "+mapper.getAttributes().getNamedItem("namespace"));
            // 輸出mapper namespace="com.yanlink.mapper.SysUserMapper"

            Node resultMap = (Node) xPath.evaluate("resultMap", mapper, XPathConstants.NODE);
            System.out.println(resultMap.getNodeName()+" "+resultMap.getAttributes().getNamedItem("id")+" "+resultMap.getAttributes().getNamedItem("type"));
            // 輸出:resultMap id="sysUserMap" type="com.yanlink.entity.SysUser"

            NodeList results = (NodeList) xPath.evaluate("result", resultMap, XPathConstants.NODESET);
            for (int i = 0; i < results.getLength(); i++) {
                Node result = results.item(i);
                NamedNodeMap nodeMap = result.getAttributes();
                System.out.println(result.getNodeName()+" "+nodeMap.getNamedItem("property")+" "+nodeMap.getNamedItem("column"));
            }
            // 輸出: result property="name" column="name"
            //result property="sex" column="sex"
            //result property="password" column="password"

            /**
             * 我們還可以直接定位到對應的node
             */
            Node select = (Node) xPath.evaluate("//select[@id='getUser']", document, XPathConstants.NODE);
            NamedNodeMap selectNameNodeMap = select.getAttributes();
            System.out.println(select.getNodeName()+" "+ selectNameNodeMap.getNamedItem("id") +" "+selectNameNodeMap.getNamedItem("resultType"));
            // 輸出:select id="getUser" resultType="SysUser"

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

相信通過上面一段代碼,我們大致可能瞭解XPath是做什麼的了。

這裏並不是要大家來深入瞭解XPath,如果對這個確實感興趣,可以去查閱相關的資料,我們這裏的目的還是介紹下XPath的概念,便於我們引入myabtis的xml解析工具XPathParser

XPathParser

XPathParser其實就是對XPath操作XML文檔的封裝。

看下XPathParser的屬性

 private final Document document;
  private XPath xpath;

其實也就兩個東西,一個document,一個xpath,document是文檔,xpath讀取文檔信息

再看看其使用率比較高的方法


public List<XNode> evalNodes(Object root, String expression) {
    List<XNode> xnodes = new ArrayList<XNode>();
    NodeList nodes = (NodeList) evaluate(expression, root, XPathConstants.NODESET);
    for (int i = 0; i < nodes.getLength(); i++) {
      xnodes.add(new XNode(this, nodes.item(i), variables));
    }
    return xnodes;
  }

public XNode evalNode(Object root, String expression) {
    Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
    if (node == null) {
      return null;
    }
    return new XNode(this, node, variables);
  }

  private Object evaluate(String expression, Object root, QName returnType) {
    try {
      return xpath.evaluate(expression, root, returnType);
    } catch (Exception e) {
      throw new RuntimeException("Error evaluating XPath.  Cause: " + e, e);
    }
  }
 

注意這裏返回的不再是Node對象,而是MyBatis封裝的XNode對象了

public class XNode {

  private final Node node;
  private final String name;
  private final String body;
  private final Properties attributes;
  private final Properties variables;
  private final XPathParser xpathParser;

  private Properties parseAttributes(Node n) {
    Properties attributes = new Properties();
    NamedNodeMap attributeNodes = n.getAttributes();
    if (attributeNodes != null) {
      for (int i = 0; i < attributeNodes.getLength(); i++) {
        Node attribute = attributeNodes.item(i);
        String value = PropertyParser.parse(attribute.getNodeValue(), variables);
        attributes.put(attribute.getNodeName(), value);
      }
    }
    return attributes;
  }
}

XNode也就是對Node進行了一次封裝,讓我們更好地操作Node的屬性,及獲取其內容

如果對我實現的簡化的XPathParser感興趣可以下載下面的項目

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章