MyBatis 技术内幕 - 基础支持层 - 解析器模块 - XML

MyBatis 技术内幕 - 基础支持层 - 解析器模块 - XML


模块功能

  1. 对XPath进行封装,为MyBatis初始化时解析mybatis-config.xml配置文件及映射配置文件提供支持
  2. 处理动态SQL语句中的占位符

XML 简介1

  1. 简介:XML(全名:EXtensible Markup Language)可扩展标记性语言
  2. 目的:用于数据传输与存储
  3. 结构:XML 文档形成了一种树结构,它从“根部”开始,然后扩展到“枝叶”
  4. 组成:
    1. 文档声明:
      1. 定义版本及编码格式
        <?xml version="1.0" encoding="ISO-8859-1"?>
        
      2. 引入文档类型定义
        <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
        
    2. 命名空间:
      1. 语法
        xmlns:namespace-prefix="namespaceURI"
        
        1. namespaceURI : 用于标示命名空间,命名空间中的地址不会被解析
        2. xmlns:(全名:XML NameSpace ,XML 命名空间)
      2. 作用
        1. 场景:当两个不同的XML中定义了相同的元素标签,比如table,在A文件中table表示表格,B文件中table表示桌子;当两个文件混合使用时会出现歧义;
        2. 解决:通过定义命名空间,设置空间的前缀名称,在 table 前通过前缀进行区分 h:table 与 f:table
    3. 元素:根元素、父元素、子元素
    4. 属性:描述元素的额外信心
    5. 实体:定义普通文本的变量(小于、大于、和、单引号、引号需要转义)
    6. 文本:XML 元素的开始标签与结束标签之间的文本,字符数据
      1. PCDATA:(全名:parsed character data,被解析的字符数据)
        1. 实体将会被转译,文本中不应包含 <、>、&、’、"
      2. CDATA: (全名:UnParsed character data ,不被解析的字符数据)
        1. 实体不会被转译,实体被当做普通文本处理
        2. <![CDATA[ 普通文本 ]]>
  5. 语言:
    1. 大小写敏感
    2. 属性值需要添加引号

XML 验证

  1. DTD 2

    1. 简介:DTD(全名:Document Type Defination ) 文档类型定义
    2. 作用:定义 XML 文档的合法构建模块
    3. 功能:
      1. 每一个XML文件都携带一个关于自身格式的描述
      2. 对内对外可以按照相同标准交换数据
    4. 示例
      1. XML 外部 DTD 引入

        1. animal.xml

          <?xml version="1.0" encoding="UTF-8" ?>
          <!-- 功能:声明文档版本 version , 编码类型 UFT-8 -->
          <!-- 位置:文档首行 -->
          
          <!-- DTD XML 文件外部声明 -->
          <!DOCTYPE animal SYSTEM "animal_dtd_outside.dtd">
          <animal>
              <category>陆地动物</category>
              <name>大象</name>
              <sex>雄性</sex>
              <age>60</age>
          </animal>
          
        2. animal_dtd_outside.dtd

          <!ELEMENT animal (category,name,sex,age)>
          <!ELEMENT category (#PCDATA)>
          <!ELEMENT name (#PCDATA)>
          <!ELEMENT sex (#PCDATA)>
          <!ELEMENT age (#PCDATA)>
          
      2. XML 内部 DTD 定义

        <?xml version="1.0" encoding="UTF-8" ?>
        <!-- 功能:声明文档版本 version , 编码类型 UFT-8 -->
        <!-- 位置:文档首行 -->
        
        <!-- DTD XML 文件内部声明 -->
        <!-- 语法格式 !DOCTYPE 根元素名称 [包含的子元素及子元素类型] -->
        <!DOCTYPE animal [
                <!ELEMENT animal (category,name,sex,age)>
                <!ELEMENT category (#PCDATA)>
                <!ATTLIST category id CDATA "0">
                <!ATTLIST category name CDATA #REQUIRED >
                <!ATTLIST category description CDATA #IMPLIED >
                <!ATTLIST category ref CDATA #FIXED "animal">
                <!ELEMENT name (#PCDATA)>
                <!ELEMENT sex (#PCDATA)>
                <!ELEMENT age (#PCDATA)>
                <!ENTITY elephant "大象" >
                ]>
        <!-- !ELEMENT 根元素 (子元素) 声明根元素包含的所有子元素名称 -->
        <!-- !ELEMENT 子元素 (类型) 声明子元素的数据类型 -->
        <!-- !ATTLIST 元素名称 属性名称 属性类型 默认参数 -->
        <!-- !ENTITY 实体名称 实体内容 >
        
        <!-- 默认参数  "" 默认数值 -->
        <!-- 默认参数  #REQUIRED 必要参数 -->
        <!-- 默认参数  #IMPLIED 可选参数 -->
        <!-- 默认参数  #FIXED 固定数值 -->
        
        <!-- 元素类型:PCDATA (全名:Parsed Character Data) 被解析的字符数据 -->
        <!-- 元素类型:CDATA (全名:Unparsed Character Data) 不应由 XML 解析器进行解析的文本数据 -->
        <!-- 元素类型:EMPTY 空,如 <br/> <p/> -->
        <!-- 元素类型:ANY 任意数据类型 -->
        
        <!-- 元素次数:+ 至少出现一次 -->
        <!-- 元素次数:* 任意次数 -->
        <!-- 元素次数:? 零次或一次 -->
        
        <!-- 实体定义: &lt; 表示 < -->
        <!-- 实体定义: &gt; 表示 > -->
        <!-- 实体定义: 自定义 -->
        <!-- 实体含义: 定义普通文本的变量 -->
        <animal>
            <category id="land" name="land" ref="animal">陆地动物</category>
            <name>&elephant;</name>
            <sex>雄性</sex>
            <age>60</age>
        </animal>
        
  2. XSD3

    1. 简介:XSD(全名:XML Schema Defination ,XML 纲要定义)
    2. 作用:描述XML文档结构;作为DTD的替代者
    3. 优势:相比与DTD
      1. 支持数据类型
      2. 支持命名空间

XML 解析

  1. DOM4(全名:Document Object Model ,文档对象模型)
    1. 实现原理:将XML文件解析成树形结构的DOM,即Document对象,将对XML各个属性节点的操作转为对DOM中各个节点(Node)的操作
      1. XML 文档 --> 文档节点
      2. XML 标签 --> 元素节点
      3. XML 属性 --> 属性节点
      4. XML 注释 --> 注释节点
    2. 方式优势
      1. 节点查询:DOM结构的特点能够定位根节点、兄弟节点、子节点
      2. 便于修改:DOM结构的特点能够增加或删除某个节点
      3. 配合XPath使用,能够查询到任意节点元素
    3. 方式劣势
      1. 内存消耗:需要一次性将整个XML文件加载到内存中并进行解析;当XML文档的数据量较大时,会造成较大的资源损耗
  2. SAX(全名:Simple API for XML)
    1. 实现原理:“推模式”,顺序读入XML文档内容,解析某一类型的节点时触发该类型节点的回调函数,即是将整个XML文档推给SAX进行处理
    2. 方式优势:
      1. 节省内存:无需加载整个XML文档,每次只加载XML文档的一部分;处理过程中内存不记录XML中的数据
    3. 方式劣势:
      1. 维护关系:因为加载过程中不记录XML文档中的内存,需要额外维护一份XML文档中各个节点之间的关系
      2. 单向处理:流式处理方式,只能从头到尾的单向处理
      3. 不支持XPath
  3. StAX(全名:Streaming API for XML)
    1. 实现原理:“拉模式”,应用程序通过StAX推进解析进程,控制整个解析进行,决定何时停止,可同时解析多个XML文档

XML 查询

  1. 语言名称:XPath5

  2. 语言语法

    表达式含义
    nodename选取指定节点的所有子节点
    /从根节点选取指定节点
    //根据指定的表达式,在整个文档中选取匹配的节点,不考虑匹配节点在文档中的位置
    .选取当前节点
    . .选取当前节点的父节点
    @选取属性
    *匹配任何元素节点
    @*匹配任何属性节点
    node()匹配任何类型的节点
    text()匹配文本节点
    []指定某个条件,用于查找某个特定节点或包含某个指定值的节点
  3. 代码示例

    1. XML 文档:book.xml

      
      <book>
          <category id="technology">
              <name>Spring</name>
              <purchaseDate>2018-11-11</purchaseDate>
          </category>
          <category id="literature">
              <name>围城</name>
              <purchaseDate>2014-10-10</purchaseDate>
          </category>
          <category id="finance">
              <name>金融</name>
              <purchaseDate>2018-12-12</purchaseDate>
          </category>
      </book>
      
      
      1. 注意事项
        1. XML 文档顶部不要加入,否则解析时会出现异常提示文档根元素 “book” 必须匹配 DOCTYPE 根 "null"

          <?xml version="1.0" encoding="UTF-8"?>
          
        2. 异常的原因在于XML文档不符合规范,需要标注文档所遵循的DTD(全名:Document Type Defination 文档类型定义),如:mapper.xml

          <?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.test.mapper.TestMapper">
          
    2. 查询测试

      package com.mybatis.test;
      
      import org.w3c.dom.Document;
      import org.w3c.dom.NodeList;
      import org.xml.sax.ErrorHandler;
      import org.xml.sax.SAXException;
      import org.xml.sax.SAXParseException;
      
      import javax.xml.parsers.DocumentBuilder;
      import javax.xml.parsers.DocumentBuilderFactory;
      import javax.xml.parsers.ParserConfigurationException;
      import javax.xml.xpath.*;
      import java.io.IOException;
      
      public class XPathTest {
      
          public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, XPathExpressionException {
      
              DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
              // 开启验证
      
              /**
               * 功能:指定由此代码生成的解析器将验证被解析的文档
               * 解释:此处“验证”是指 xml 规范中定义的验证解析器,实际上仅控制 dtd 验证
               * 更改:要使用现代模式语言(如 w3c xml schema 或 relax ng)而不使用 dtd
               *      将解析器配置为非验证解析器,方法是将 setvalidating(boolean) 方法保留为 false,
               *      然后使用 setschema(schema) 方法将一个模式与解析器关联
               */
              documentBuilderFactory.setValidating(true);
              /**
               * 功能:指示是否将工厂配置为生成具有感知命名空间功能的解析器
               * 解释:XML Namespace (xmlns) 属性,XML文档的命名空间,其作用是区分不同文档中的相同元素名称的含义
               * 举例:A文档中table表示页面结果表格,B文档中table表示桌子,当A/B文档联合使用时会出现歧义,所以需要命名空间进行标识
               * 位置:命名空间放置在文档的开始位置
               * 作用:当命名空间被定义在元素的开始标签中时,所有带有相同前缀的子元素都会与同一个命名空间相关联
               * 链接:http://www.w3school.com.cn/xml/xml_namespaces.asp
               */
              documentBuilderFactory.setNamespaceAware(false);
              /**
               * 功能:指定由此代码生成的解析器将忽略注释
               */
              documentBuilderFactory.setIgnoringComments(true);
              /**
               * 功能:指定由此工厂创建的解析器在解析 xml 文档时,必须删除元素内容中的空格(有时也可以称作“可忽略空格”,请参阅 xml rec 2.10)。
               * 注意:只有在空格直接包含在元素内容中,并且该元素内容是只有一个元素的内容模式时,才能删除空格(请参阅 xml rec 3.2.1)。
               *      由于依赖于内容模式,因此此设置要求解析器处于验证模式。
               */
              documentBuilderFactory.setIgnoringElementContentWhitespace(false);
              /**
               * 功能:指示是否将工厂配置为生成满足以下条件的解析器:该解析器将 cdata 节点转换为 text 节点,并将其附加到相邻(如果有)的 text 节点。
               */
              documentBuilderFactory.setCoalescing(false);
              /**
               * 功能:指示是否将工厂配置为生成扩展实体引用节点的解析器
               */
              documentBuilderFactory.setExpandEntityReferences(true);
      
              // 设置 DocumentBuilder
              DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
              // 设置异常处理对象
              documentBuilder.setErrorHandler(new ErrorHandler() {
                  public void warning(SAXParseException exception) throws SAXException {
                      System.out.println("warning:"+exception.getMessage());
                  }
      
                  public void error(SAXParseException exception) throws SAXException {
                      System.out.println("exception:"+exception.getMessage());
                  }
      
                  public void fatalError(SAXParseException exception) throws SAXException {
                      System.out.println("fatal:"+exception.getMessage());
                  }
              });
      
              // 将文档加载到一个Document对象中,资源查找通过绝对路径
              String resource = "src\\main\\java\\com\\mybatis\\resources\\book.xml";
              Document document = documentBuilder.parse(resource);
      
              // 创建 XPathFactory
              XPathFactory xPathFactory = XPathFactory.newInstance();
              // 创建 XPath 对象
              XPath xPath = xPathFactory.newXPath();
              // 编译 XPath 表达式
              // 1.查询书名为Spring的购买时间
              System.out.println("查询书名为Spring的购买时间:");
              xPathEvaluateResult(xPath,document,"//category[name='Spring']/purchaseDate/text()");
              // 2.查询技术类型书籍名称
              System.out.println("查询技术类型书籍名称:");
              xPathEvaluateResult(xPath,document,"//category[@id='technology']/name/text()");
              // 3.查询所有书籍名称
              System.out.println("查询所有书籍名称:");
              xPathEvaluateResult(xPath,document,"//category/name/text()");
      
          }
      
          private static void xPathEvaluateResult(XPath xPath,Document document ,String expression) throws XPathExpressionException {
              XPathExpression xPathExpression = xPath.compile(expression);
              Object evaluate = xPathExpression.evaluate(document, XPathConstants.NODESET);
              NodeList nodeList = (NodeList) evaluate;
              for(int index = 0 ; index < nodeList.getLength() ; index++){
                  System.out.println(nodeList.item(index).getNodeValue());
              }
          }
      
      }
      
      

  1. XML教程 ↩︎

  2. DTD教程 ↩︎

  3. XSD教程 ↩︎

  4. DOM教程 ↩︎

  5. XPath语法教程 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值