DOM解析

原文链接http://zhhll.icu/2020/08/16/xml/DOM/DOM%E8%A7%A3%E6%9E%90/

DOM解析

DOM解析介绍

DOM是基于属性结构的XML解析方式,会将整个XML文档读入内存并构建一个DOM树,基于这棵树型结构对各个节点进行操作。XML文档中每个成分都是一个节点,整个文档是一个文档节点,每个XML标签对应一个元素节点,包含在XML标签中的文本是文本节点,每一个XML属性是一个属性节点,注释属于注释节点。

DOM树所提供的随机访问方式很灵活方便,可以任意地控制整个XML文档中的内容,但是DOM分析器把整个XML文件转化为DOM树放到了内存中,当文档比较大或者结构比较复杂时,对内存需求比较高。

DOM解析示例

xml文件示例

下面以mybatis的一个mapper.xml为例讲解各个方法

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
    <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="funkyNumber" property="funkyNumber"/>
        <result column="roundingMode" property="roundingMode"/>
    </resultMap>

    <select id="getUser" resultMap="usermap">
select * from users
</select>
    <insert id="insert">
    insert into users (id, name, funkyNumber, roundingMode) values (
    #{id}, #{name}, #{funkyNumber}, #{roundingMode}
    )
</insert>

    <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="funkyNumber" property="funkyNumber"/>
        <result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
    </resultMap>
    <select id="getUser2" resultMap="usermap2">
select * from users2
</select>
    <insert id="insert2">
    insert into users2 (id, name, funkyNumber, roundingMode) values (
    #{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
    )
</insert>

</mapper>

DOM接口介绍

介绍一下DOM解析中的核心接口

  • Document:代表了整个XML文档,表示整棵DOM树的根,常用方法

    • public NodeList getElementsByTagName(String tagname); 取得指定节点名称的NodeList
    • public Element createElement(String tagName) 创建一个指定名称的节点
    • public Text createTextNode(String data) 创建一个文本内容节点
    • public Attr createAttribute(String name) 创建一个属性
  • NodeList: 表示一个节点的集合
    • public int getLength(); 取得节点的个数
    • public Node item(int index); 根据索引取得节点对象
  • Node:每一个Node代表了DOM树中的一个节点
    • public Node appendChild(Node newChild) 在当前节点下增加一个新的节点
    • public NodeList getChildNodes() 得到本节点下的全部子节点
    • public Node getFirstChild() 得到本节点下的第一个子节点
    • public Node getLastChild() 得到本节点下最后一个子节点
    • public boolean hasChildNodes() 判断是否还有其他节点
    • public boolean hasAttributes() 判断是否还有其他属性
    • public String getNodeValue() 获取节点内容
  • NamedNodeMap:表示一组节点和其唯一名称对应的一一对应关系,主要用于属性节点的表示

方法使用示例

将xml文件转为dom树
public static Document getDefaultDocument(File file) throws ParserConfigurationException, IOException, SAXException {
  // 创建DocumentBuilderFactory,用于取得DocumentBuilder
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
  // 使用DocumentBuilder进行DOM树的转换操作,读取指定的xml文件
    return builder.parse(file);
}
操作dom树读取节点内容
// 获取mapper节点
NodeList mapperList = document.getElementsByTagName("mapper");
for(int i = 0;i<mapperList.getLength();i++){
  Node mapperNode = mapperList.item(i);
  if(mapperNode.hasAttributes()){
    // 找到mapper节点的namespace属性节点
    Node namespace = mapperNode.getAttributes().getNamedItem("namespace");
    // namespace属性节点内容
    System.out.println(namespace.getNodeValue());
  }
  if(mapperNode.hasChildNodes()){
    // mapper节点的子节点
    NodeList childNodes = mapperNode.getChildNodes();
    // 遍历子节点
    for(int j = 0;j<childNodes.getLength();j++){
      Node childNode = childNodes.item(j);
      if("resultMap".equals(childNode.getNodeName())){
        //TODO
      } else if("select".equals(childNode.getNodeName())){
        //TODO
      } else if("insert".equals(childNode.getNodeName())){
        //TODO
      }
    }
  }
}
创建dom节点
// 创建test节点作为根节点
Element root = document.createElement("test");

// 创建type属性
Attr type = document.createAttribute("type");
type.setNodeValue("test");
// 创建id节点
Element id = document.createElement("id");
// 创建文本节点,并放到id节点中
id.appendChild(document.createTextNode("001"));
// 创建name节点
Element name = document.createElement("name");
// 创建文本节点,并放到name节点中
name.appendChild(document.createTextNode("张三"));
// 设置属性节点
root.setAttributeNode(type);
// 将节点放入父节点中
root.appendChild(id);
root.appendChild(name);
document.appendChild(root);

DOM持久化

将生成的xml保存到文件中,需要使用TransformerFactory、Transformer、DOMSource和StreamResult四个类来完成

类介绍

  • TransformerFactory 取得一个Transformer对象
  • DOMSource 接收Document对象
  • StreamResult 指定要使用的输出流对象(可以向文件输出,也可以指定其他输出流)
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer;
try {
    transformer = factory.newTransformer();
} catch (TransformerConfigurationException e) {
    throw new RuntimeException("创建Transformer失败",e);
}
// 设置xml属性 只设置了version和ecoding  还需要设置其他属性可以从OutputKeys中查找
transformer.setOutputProperty(OutputKeys.VERSION,"1.0");
transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
// dom数据源
DOMSource source = new DOMSource(document);
// 目的地
StreamResult result = new StreamResult(new File(fileName));
try {
    // 进行转换
    transformer.transform(source,result);
} catch (TransformerException e) {
    throw new RuntimeException("输出文件错误",e);
}

解析器自定义设置方法介绍

下面介绍一些DocumentBuilderFactory中用来设置解析器行为的一些配置可能会用到的方法,但是就不写代码示例了

// 该方法指定解析器是否将CDATA节点转换为文本节点,以及是否将它和周围的文本节点合并,默认false
public void setCoalescing(boolean coalescing)

// 指定解析器是否展开外部实体引用,如果为true,外部数据将插入文档,默认true
public void setExpandEntityReferences(boolean expandEntityRef)

// 指定解析器是否忽略文档中的注释。默认false
public void setIgnoringComments(boolean ignoreComments)

// 指定是否忽略元素内容中的空白。默认false
public void setIgnoringElementContentWhitespace(boolean whitespace) 

// 指定是否支持XML的名称空间。默认false
public void setNamespaceAware(boolean awareness)

// 是否验证文档,默认false
public void setValidating(boolean validating)

DOM解析的优缺点

  • 优点:可以根据需求在树形结构的各节点之间导航,轻易获取到所要的数据,也可以很容易地添加和修改树中的元素。
  • 缺点: 需要将整个XML加载到内存中并构造树形结构,当XML文档的数据量较大时,会造成较大的内存消耗。

由于本身的博客百度没有收录,博客地址http://zhhll.icu

(0)

相关推荐

  • Mybatis中SqlSource解析流程详解

    前面几篇文章都在详细分析mapper的加载过程,但是始终没有看到sql的解析过程,今天来详细分析下. 解析sql的位置 前面分析到不管是通过注解还是通过xml方式生成mapper,最终都是调用Mapp ...

  • Mybatis对mapper的加载流程详解

    今天来分析Configuration初始化的最后一部分mapper的加载. 加载方法mapperElement XMLConfigBuilder配置Configuration的parseConfigu ...

  • Mybatis初始化过程简单总结

    前面连续多篇文章都是在数据mybatis的初始化过程,目前基本完成,是时候做一个总结了. 总览 首先回顾下最上层的测试代码,实际上目前分析的还在测试代码中与mybatis相关的第一步,具体如下图: 目 ...

  • <script>和<link>标签对DOM解析和渲染的影响

    https://juejin.cn/post/6844903936877395981 之前也看过一些关于<script>标签和<link>标签对DOM解析和渲染影响的文章,但总 ...

  • 《中医舌诊》,26张临床高清舌诊图,附带解析,史上最全!

    掌纹医学,看手知健康,疾病早知道..... 舌质 色:淡紫.淡白: 形:偏嫩.少量瘀点.轻度齿痕. 舌苔 苔质:薄.润: 苔色:白. [临床意义] 阳虚.气虚.气滞等原因导致的气血瘀滞. 舌质 色:淡 ...

  • 初中数学:二次根式的考点解析 常见误区 隐含条件 经典例题

    成才路上 初中精品学习资料 104篇原创内容 公众号 二次根式是初中数学的一个重要内容,要求了解二次根式和最简二次根式的概念,理解二次根式的性质,熟练地进行二次根式的加减乘除及混合运算. 今天方法君就 ...

  • 高考物理11类重点题型全解析! 附经典例题&详解

    高考理科综合卷中,物理部分选择题有单项和双项选择题两种题型.从最近几年的试题看: 4道单项选择难度低,考查的考点相对稳定且相对单一,涉及的知识点主要有共点力平衡.热力学第一定律.气体状态方程.分子动理 ...

  • 中医解析:指甲半月痕暗藏健康秘密

    医学指导:广东省中医院大德路总院传统疗法中心主任陈秀华教授 "哎呀!我的指甲没有月牙痕,是不是最近我的身体不太好?" 不少朋友开始关注自己指甲上的月牙痕,还有不少人照着网上的一些描 ...

  • 解析52年西南局与西南军政委员会领导人的构成与职级统计(之四)

    (接前文) 第一部分,西南局书记.副书记的评级统计: 刘伯承(52年大军区司令员政委级,55年军委主席副主席级):西南局第二书记(49.10-54.12) 早期革命资历:1926年5月入党,1927年 ...

  • 初中数学重难点解析—几何代数最值问题!

    i初中数学 公众号 几何最值问题是指在一定的条件下,求平面几何图形中某个确定的量(如线段长度.角度大小.图形面积等)的最大值或最小值.在中考中常以填空选择及解答题形式出现,难易程度多为难题.压轴题.务 ...

  • 国家级名老中医毛德西教授:王清任逐瘀汤类方解析

    王清任(1768~1831年)是一位革新派的医学家,他的<医林改错>虽然只有3万余字,但在中医学发展历程中有着举足轻重的作用.特别是他所拟定的逐瘀汤类方,极大地丰富了中医血瘀理论与活血化瘀 ...

  • 关于“炁”的解析与借鉴

    古为今用,洋为中用,取长补短,中西合璧,依然可作为科学探索的一个原则. 1 炁的字理,国学厉害 炁 =旡[ji]/既(原已) 灬(火) =屰[ji]/逆(还原) 燃烧分解 =因燃烧而还原为无形的气 = ...