如何使用Dom4J解析XML文档

news2024/11/29 6:38:25

文章目录

  • XML解析的方式
  • 使用Dom4J解析XML文档
  • Dom4J结合XPath解析XML

最近在手写MyBatis的源码,在写到XMLConfigBuilder的时候,其中要解析xml文件构建Configuration。在MyBatis的早期版本中使用了DOM4J来解析配置文件和映射文件。但是从3.x版本开始,MyBatis已经切换到使用XPath解析器(XPathParser,其底层依赖的JAXP),不再使用重量级的DOM4J。

XML解析的方式

XML常见的两种解析方式:

  1. DOM: 要求解析器将整个XML文件全部加载到内存中,生成一个Document对象

    • 优点:元素和元素之间保留结构、关系,可以针对元素进行增删查改操作
    • 缺点:如果XML文件过大,可能会导致内存溢出
  2. SAX:是一种速度更快,更加高效的解析方式。它是逐行扫描,边扫描边解析,并且以事件驱动的方式来进行具体的解析,每解析一行都会触发一个事件

    • 优点: 不会出现内存溢出的问题,可以处理大文件
    • 缺点:只能读,不能写

概念辨析:

  • 解析器就是根据不同的解析方式提供具体的实现。
  • 为了方便开发人员来解析XML,有一些方便操作的类库。例如Dom4j其中就包含了很多解析器。

使用Dom4J解析XML文档

依赖:

        <dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>2.1.3</version>
        </dependency>

使用方法:

  • 创建解析器对象
  • 使用解析器对象读取XML文档生成Document对象
  • 根据Document对象获取XML的元素(标签)

常用的方法:
在这里插入图片描述

我们来看一段代码:

xml文件

<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<contactList>
    <contact id="1" vip="true">
        <name>   张三  </name>
        <gender></gender>
        <email>panpan@qq.cn</email>
    </contact>
    <contact id="2" vip="false">
        <name>李四</name>
        <gender></gender>
        <email>wusong@qq.cn</email>
    </contact>
    <contact id="3" vip="false">
        <name>王五</name>
        <gender></gender>
        <email>wuda@qq.cn</email>
    </contact>
    <user>
    </user>
</contactList>

测试代码:

public class Dom4jParseTest {

    public static void main(String[] args) throws FileNotFoundException, DocumentException {
        InputStream xmlFile = Dom4jParseTest.class.getClassLoader().getResourceAsStream("Contacts.xml");
        //创建解析器对象
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(xmlFile);
        // 获取根元素对象
        Element root = document.getRootElement();
        //获取根元素名字
        System.out.println("root.getName() ---> " + root.getName());

        // 4、拿根元素下的全部子元素对象(一级)
        // List<Element> sonEles =  root.elements();
        List<Element> sonEles =  root.elements("contact");
        for (Element sonEle : sonEles) {
            System.out.println("sonEle.getName() ---> " + sonEle.getName());
        }

        // 拿某个子元素
        Element userEle = root.element("user");
        System.out.println("userEle.getName() ---> " + userEle.getName());

        // 默认提取第一个子元素对象 (Java语言。)
        Element contact = root.element("contact");
        // 获取子元素文本
        System.out.println("contact.elementText('name') ---> " + contact.elementText("name"));
        // 去掉前后空格
        System.out.println("contact.elementTextTrim('name') ---> " + contact.elementTextTrim("name"));
        // 获取当前元素下的子元素对象
        Element email = contact.element("email");
        System.out.println("email.getText() ---> " + email.getText());
        // 去掉前后空格
        System.out.println("email.getTextTrim() ---> " + email.getTextTrim());

        // 根据元素获取属性值
        Attribute idAttr = contact.attribute("id");
        System.out.println(idAttr.getName() + "-->" + idAttr.getValue());
        // 直接提取属性值
        System.out.println("contact.attributeValue('id') ---> " + contact.attributeValue("id"));
        System.out.println("contact.attributeValue('vip') ---> " + contact.attributeValue("vip"));

    }
}

结果:

在这里插入图片描述

Dom4J结合XPath解析XML

XPath使用路径表达式来定位XML文档中的元素节点或属性节点

依赖:

        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.1.6</version>
        </dependency>

常见的方法

在这里插入图片描述
解释一下这里的Node:

在dom4j中,Node是通用的节点抽象,他有几个具体的实现类:

  • Element - 代表具体的XML元素
  • Attribute - 表示元素的属性
  • Text - 表示文本信息
  • CDATA - 表示CDATA块
  • Entity - 表示实体
  • Comment - 表示注释
  • Document - 表示整个文档

我们举几个例子:

  1. Element - 代表一个XML元素

    <student>
        <name>Tom</name>
    </student>
    

    上例中,<student><name>都可以表示为Element。

  2. Attribute - 元素的属性

    <student gender="male">
       <name>Tom</name> 
    </student>
    

    上例中,gender="male"可以表示为一个Attribute节点。

  3. Text - 元素中的文本内容

    <name>Tom</name>
    

    <name>元素中的Tom可以表示为一个Text节点。

  4. CDATA - CDATA块内容

    <desc><![CDATA[Tom is a good student.]]></desc>
    

    上例中的<![CDATA[Tom is a good student.]]>可以表示为一个CDATA节点。

  5. Comment - 注释内容

    <!-- comment test -->
    

    上述注释可以表示为一个Comment节点。

  6. Document - 代表整个XML文档

表达式

  • 绝对路径:/根元素/子元素/孙元素。采用绝对路径获取从根节点开始逐层的查找节点列表并返回信息。从根元素开始,一级一级向下查找,不能跨级。

  • 相对路径:./子元素/孙元素。先得到当前节点,再采用相对路径获取下一级节点的子节点并返回信息。从当前元素开始,一级一级向下查找,不能跨级。

  • 全文检索:直接全文搜索所有的指定元素并返回
    在这里插入图片描述

  • 属性查找:在全文中搜索属性,或者带属性的元素
    在这里插入图片描述

接下来我们还是看一段代码:

xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<contactList>
    <contact id="1" vip="true">
        <name>   潘金莲  </name>
        <gender></gender>
        <email>panpan@qq.cn</email>
    </contact>
    <contact id="2" vip="false">
        <name>武松</name>
        <gender></gender>
        <email>wusong@qq.cn</email>
    </contact>
    <contact id="3" vip="false">
        <name>武大狼</name>
        <gender></gender>
        <email>wuda@qq.cn</email>
    </contact>
    <user>
        <contact>
            <info>
                <name id="888">我是西门庆</name>
            </info>
        </contact>
    </user>
</contactList>

测试绝对路径:

    /**
     1.绝对路径: /根元素/子元素/子子元素。
     */
    @Test
    public void parse01() throws Exception {
        // a、创建解析器对象
        SAXReader saxReader = new SAXReader();
        // b、把XML加载成Document文档对象
        Document document = saxReader.read(Dom4jWithXPath.class.getClassLoader().getResourceAsStream("xpathtest.xml"));
        // c、检索全部的名称
        List<Node> nameNodes = document.selectNodes("/contactList/contact/name");
        for (Node nameNode : nameNodes) {
            Element  nameEle = (Element) nameNode;
            System.out.println(nameEle.getTextTrim());
        }
    }

在这里插入图片描述
测试相对路径:

    /**
     2.相对路径: ./子元素/子元素。 (.代表了当前元素)
     */
    @Test
    public void parse02() throws Exception {
        // a、创建解析器对象
        SAXReader saxReader = new SAXReader();
        // b、把XML加载成Document文档对象
        Document document =
                saxReader.read(Dom4jWithXPath.class.getClassLoader().getResourceAsStream("xpathtest.xml"));
        Element root = document.getRootElement();
        // c、检索全部的名称
        List<Node> nameNodes = root.selectNodes("./contact/name");
        for (Node nameNode : nameNodes) {
            Element  nameEle = (Element) nameNode;
            System.out.println(nameEle.getTextTrim());
        }
    }

结果和上面一样

测试全文搜索:

    /**
     3.全文搜索:
     //元素  在全文找这个元素
     //元素1/元素2  在全文找元素1下面的一级元素2
     //元素1//元素2  在全文找元素1下面的全部元素2
     */
    @Test
    public void parse03() throws Exception {
        // a、创建解析器对象
        SAXReader saxReader = new SAXReader();
        // b、把XML加载成Document文档对象
        Document document =
                saxReader.read(Dom4jWithXPath.class.getClassLoader().getResourceAsStream("xpathtest.xml"));
        // c、检索数据
        //List<Node> nameNodes = document.selectNodes("//name");
        // List<Node> nameNodes = document.selectNodes("//contact/name");
        List<Node> nameNodes = document.selectNodes("//contact//name");
        for (Node nameNode : nameNodes) {
            Element  nameEle = (Element) nameNode;
            System.out.println(nameEle.getTextTrim());
        }
    }

在这里插入图片描述

测试属性查找:

    /**
     4.属性查找。
     //@属性名称  在全文检索属性对象。
     //元素[@属性名称]  在全文检索包含该属性的元素对象。
     //元素[@属性名称=值]  在全文检索包含该属性的元素且属性值为该值的元素对象。
     */
    @Test
    public void parse04() throws Exception {
        // a、创建解析器对象
        SAXReader saxReader = new SAXReader();
        // b、把XML加载成Document文档对象
        Document document =
                saxReader.read(Dom4jWithXPath.class.getClassLoader().getResourceAsStream("xpathtest.xml"));
        // c、检索数据
        List<Node> nodes = document.selectNodes("//@id");
        for (Node node : nodes) {
            Attribute attr = (Attribute) node;
            System.out.println(attr.getName() + "===>" + attr.getValue());
        }

        // 查询name元素(包含id属性的)
//      Node node = document.selectSingleNode("//name[@id]");
        Node node = document.selectSingleNode("//name[@id=888]");
        Element ele = (Element) node;
        System.out.println(ele.getTextTrim());
    }

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/763553.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构——绪论

基本概念 数据&#xff1a;数据是信息的载体&#xff0c;对客观事物的字符表示。 数据元素&#xff1a;数据的基本单位&#xff0c;通常作为一个整体进行考虑和处理。 数据项&#xff1a; 一个数据元素由多个数据项组成&#xff0c;数据项是数据元素不可分割的最小单位。 数据…

流程图如何制作?几个流程图实用制作方法教给你

流程图如何制作&#xff1f;流程图是一种重要的图表类型&#xff0c;通常用于描绘系统、流程或程序的步骤和关系。它们在各种领域都有广泛的应用&#xff0c;包括工程、科学、商业和教育等。本文将介绍一些制作流程图的实用方法&#xff0c;以及一些快速、易于使用的工具。 制作…

k8s之Pod容器资源限制

目录 一、Pod 容器的资源限制二、CPU 资源单位三、内存资源单位四、为本地临时性存储设置请求和限制五、总结 一、Pod 容器的资源限制 当定义 Pod 时可以选择性地为每个容器设定所需要的资源数量。 最常见的可设定资源是 CPU 和内存大小&#xff0c;以及其他类型的资源。 当为…

MySQL索引事务与存储引擎

MySQL索引事务与存储引擎 索引概念索引作用副作用索引场景创建索引原则索引分类 事务概念:特性事务隔离级别 MYSQL存储引擎概念常用的存储引擎MyISAMInnoDB 索引 概念 是一个排序的列表&#xff0c;存储着索引值和这个值所对应的物理地址无须对整个表进行扫描&#xff0c;通过…

Vant安装及必坑

vant官网地址 Vant 4 - A lightweight, customizable Vue UI library for mobile web apps. 1.通过npm安装&#xff1a; 注意vue2和vue3不同&#xff0c;版本过高会报错 vue2 npm i vantlatest-v2或者npm i vant -Svue3 npm i vant或者npm i vantnext -S 备注&#xff1a…

为什么信创国产化替代 必备 “开放式ETL产品“(下篇)

信创国产化通俗来讲&#xff0c;就是在核心芯片、基础硬件、操作系统、中间件、数据服务器等领域实现信创产业的国产替代。ETL技术 属于基础软件类中间件技术。发展自己研制的安全可靠的能够保证国家信息安全的设备&#xff0c;随着信息安全问题日益突出&#xff0c;信息安全已…

小程序 点击view内部元素 不传参

点击 内部图片和文字 type 得到的是空 无法传递参数 解决办法: 用 currentTarget 代替 target

【LangChain】数据连接(Data connection)

概要 许多LLM申请需要特定于用户的数据&#xff0c;这些数据不属于模型训练集的一部分。 LangChain 为您提供了通过以下方式加载、转换、存储和查询数据的构建块&#xff1a; Document loaders &#xff1a; 从许多不同来源加载文档Document transformers&#xff1a;拆分文档…

怎么把文档翻译成英文?这几款文档翻译工具都能实现

听说你正在寻找免费的文档翻译软件&#xff0c;我来给你一些建议吧&#xff01;翻译软件的确是个很有用的工具&#xff0c;能够帮助我们快速翻译各种语言的文档。而且现在有很多免费的选择&#xff0c;真是再好不过了&#xff01;但是随着市面上文档翻译软件数量的增多&#xf…

车载测试:车联网功能组件及安全测试策略

目录 一、车联网功能组件 车域网 IVI TBOX ECU TSP APP 通信及密码特殊指标 车端特殊指标 APP特殊指标 测试用例 一、车联网功能组件 车联网是以汽车智能化、网联化为基础&#xff0c;广泛应用新一代通信技术、人工智能技术构建起的新型基础设施。在整体架构上&…

单据小票打印模板自定义设计,手机收银软件APP搭配蓝牙便携打印机,移动便携打印零售单单据小票

单据小票打印模板自定义设计&#xff0c;手机收银软件APP搭配蓝牙便携打印机&#xff0c;移动便携打印零售单单据小票&#xff0c;轻松实现仓库条码管理&#xff0c;扫码入库出库盘点_哔哩哔哩_bilibili单据小票打印模板自定义设计&#xff0c;手机收银软件APP搭配蓝牙便携打印…

突破平凡:创造独特而吸引人的登陆页UI设计灵感

今天&#xff0c;我们从移动APP产品经理或者UI设计师的角度再来聊一聊APP登录设计方式和如何去设计这些有意思的APP登录模块。 1、熟悉目前常见的手机APP登陆方式 ① 账号登陆&#xff08;手机、邮箱&#xff09; ② 第三方登陆&#xff08;微信&#xff0c;QQ&#xff0c;微博…

Java编程-IDEA中Java的main方法、sout快捷键设置

目的 我打出psvm这四个字母时&#xff0c;可快速打出main方法 我打出syso,sout时&#xff0c;可快速打出System.out.println(); 步骤&#xff1a; 1、打开IDEA&#xff0c;点击文件&#xff0c;选择Editor中的 Live Templates选项&#xff0c;点击右侧边栏中的 号 2、选中…

quartus工具篇——Signal Tap

文章目录 quartus工具篇——Signal Tap1、Signal Tap简介2、操作步骤3、查看波形结果4、总结 quartus工具篇——Signal Tap 1、Signal Tap简介 Quartus中的Signal Tap是一种用于FPGA设计调试和分析的工具。它可以捕获和显示设计中的信号波形&#xff0c;帮助设计人员验证设计…

安卓:表示日期的控件

一、日期控件 &#xff08;一&#xff09;、DatePicker DatePicker是一种安卓平台上常用的控件&#xff0c;用于让用户选择日期。它通常以日历的形式显示&#xff0c;并允许用户通过滑动或点击来选择年、月和日。 常用属性&#xff1a; android:calendarViewShown&#xff1…

第一阶段-第十二章 Python基础的综合案例(数据可视化-动态柱状图)

目录 引、案例效果一、基础柱状图的构建  1.学习目标  2.通过Bar构建基础柱状图  3.反转x和y轴  4.数值标签在右侧  5.本节的演示  6.本小节的总结 二、基础时间线柱状图  1.学习目标  2.时间线  3. 自动播放  4.时间线的主题  5.本节的代码演示  6.本…

MSP432自主开发笔记3:串口__编写自定义printf发送函数、编写发送字节字符串函数编写

之前其实对于串口在收发字节、收发字符串方面的介绍已经挺完全了&#xff0c; 但今日无意间发现漏了些什么&#xff0c;之前有讲到过串口的printf()发送问题&#xff0c;但也仅仅教大家如何重定向printf&#xff08;&#xff09;&#xff1b;来决定向哪个串口发送数据. print…

代码随想录算法训练营第57天 | 动态规划 part17 ● 647 回文子串 ●516最长回文子序列 ●动归总结

#647 回文子串 自己不会做。 之前遇到的大部分题目是&#xff0c;我们求什么dp里面就放什么。但这道回文的题不是&#xff1a;" 本题如果我们定义&#xff0c;dp[i] 为 下标i结尾的字符串有 dp[i]个回文串的话&#xff0c;我们会发现很难找到递归关系。dp[i] 和 dp[i-1]…

自监督语义分割面模型——Masked Autoencoders Are Scalable Vision Learners(MAE)论文阅读

1、摘要 This paper shows that masked autoencoders (MAE) are scalable self-supervised learners for computer vision. Our MAE approach is simple: we mask random patches of the input image and reconstruct the missing pixels. It is based on two core designs. F…

实现二分搜索函数,设计脚手架程序进行自动测试。

1. 设计思路   二分搜索算法每次将数组中间值与目标值相比较&#xff0c;若相同&#xff0c;则该元素就是要寻找的元素&#xff0c;若不相同&#xff0c;二分搜索法通过一定的方法抛弃一半的待搜索区间&#xff0c;在剩余的区间中继续以相同方法搜索目标值. 2.源代码 #incl…