java解析XML文件

B站相关课程链接:https://www.bilibili.com/video/BV1hJ411C7Zd?t=2.2

一.XML是什么

1.什么是XML:

​ extensible matkup language (可拓展的 标记 语言)

​ html 超文本标记语言 做网页 -> 目的:表现和展示数据

2.XML语言(文件)的作用:

①存储数据:xml文件

手机中的单机游戏中的等级,装备等数据记录在哪?

数据库太大,一般用于网络游戏中,例如将数据打包并通过远程访问将数据包传到服务器的数据库里面

普通文件,io流的读取速度太慢

所以,采用xml文件保存软件的数据

②传输数据:网络上传递数据

网络游戏一般通过数据包传递数据,并发量比较小,数据比较少

而像一些购物平台,比如京东,淘宝等,在双11的时候有很多的人访问,这些庞大的数据量就不能够通过数据包来传递数据,而是采用xml文件的方式

③配置文件

在之前java学习过程中,我们通常写配置文件如下: *.properties

也可以使用xml来写配置文件:*.xml

二.XML的特点

  1. 跨平台性(window linux都可以使用)

  2. 90%的语言都支持xml,不支持xml的10%的语言发布的时候,还没有xml

  3. xml具有自我描述性(内容自定义)

    (1)html文件中,所有元素(标签)都是官方定义好的,我们直接引用

    (2)xml文件中,所有元素自定义

三.XML的语法规则

(1)xml文件必须有根元素,它是所有其他元素的父元素。以下实例中 root 就是根元素

<root>
  <child>
    <subchild>.....</subchild>
  </child>
</root> 	

(2)xml元素(标签)有开必有合(结束标签)。

html不一样,html有些标签可以不写结束标签

<p>This is a paragraph.
<br>

在 XML 中,省略关闭标签是非法的。所有元素都必须有关闭标签

<p>This is a paragraph.</p>
<br />

(3)xml元素对大小写敏感,必须使用相同的大小写来编写打开标签和关闭标签:

<Message>这是错误的</message>
<message>这是正确的</message>

(4)xml元素必须正确的嵌套

在 HTML 中,常会看到没有正确嵌套的元素:

<b><i>This text is bold and italic</b></i>

在 XML 中,所有元素都必须彼此正确地嵌套:

<b><i>This text is bold and italic</i></b>

(5)xml元素的属性必须加引号(单引双引都可以)

<note date=12/11/2007> // 错误,属性必须加引号 正确写法:<note date="12/11/2007"></note>
<to>Tove</to>
<from>Jani</from>
</note>

XML 声明:

XML 声明文件的可选部分,如果存在需要放在文档的第一行,如下所示:

<?xml version="1.0" encoding="utf-8"?>

XML注释:与html的注释相同

XML中的实体引用:

​ 在 XML 中,一些字符拥有特殊的意义。如果您把字符 “<” 放在 XML 元素中,会发生错误,这 是因为解析器会把它当作新元素的开始。这样会产生 XML 错误:

<message>if salary < 1000 then</message>

为了避免这个错误,请用实体引用来代替 “<” 字符:

<message>if salary &lt; 1000 then</message>

在 XML 中,有 5 个预定义的实体引用:

&lt; <

&gt; >

&amp; &

&apos; ’

&quot; "

还有一种方式:CDATA区

语法:<![CDATA[xxxx]]> xxxx为需要转转义的字符

<student>
    <!-- 报错 <compare> 10 < 5 </compare>   -->
    <compare> <![CDATA[10 > 5]]> </compare>
</student>

在 XML 中,空格会被保留:

​ HTML 会把多个连续的空格字符裁减(合并)为一个;

​ 在 XML 中,文档中的空格不会被删减。

四.DTD文件(DTD File)

了解即可

1.什么是DTD?

  • ​ DTD : document Type Definition (文档类型定义)

2.DTD的目的?

​ 帮助你编写合法的代码,按照DTD文件的规定书写xml中的元素,即DTD文件可以规定标签的定义。如果不按照该文件的规定而自定义标签,代码就会报错。这些文件一般都是官方写好了的,我们只需要直接引用即可。

在MyBatis中会接触到该文件

3.DTD和XML之间的关系

  • ​ 类似于类和对象的关系,DTD定义了XML中要包含的属性,就像类规范了对象的行为
  • ​ 数据库表和行(一条记录)

dtd有专门的语法,跟xml的语法不一样,也不支持数据类型。比如字符串在它的定义是 #PCDATA

五. XSD文件(XML Schemas File)

了解即可

1.什么是XSD文件?

  • xsd 是 xml 结构定义 (XML Schemas Definitiom)
  • xsd 是 dtd 的替代品,比 dtd 高端。在spring中也会看到该文件
  • xsd 优点:
    • xsd 的代码基于 xml,没有专门的语法。和xml一样的解析和处理
    • xsd 支持一系列的数据类型

学会解析XML

1.解析 xml 共有四种方式:
  • DOM 解析(不咋地)
  • SAX 解析(老二)
  • JDOM 解析(不咋地)
  • DO4J 解析(最吊的)

前两种属于基础方法,是官方提供的与平台无关的解析方式。后两种属于拓展方法,他们是在基础方法之上拓展出来的,只适用于java平台。

DOM 解析

  • dom解析的原理是解析xml的时候,把文档中的所有元素按照其出现的层次关系,在内存中构造出树形结构。

    (根元素作为根节点)

  • dom 的优点:可以遍历和修改节点的内容

  • dom 的缺点:内存压力较大,解析较慢

SAX 解析

  • 是一种 xml 解析的替代方法
  • 相对比 dom 方式,sax 是一种速度更快,更有效的方法
  • 缺点:不能修改节点内容

JDOM 解析(不常用)

  • 仅适用具体的类,而不用接口,不灵活

DOM4J 解析(重点掌握)

  • JDOM 的一种智能的分支,合并了许多超出基本 xml 文档的功能
  • hibernate框架就是用 dom4j 来解析的(ssh已经寄了,现在一般用的是MyBatis框架 )

dom4j 性能最高,其次是SAX, dom 和 jdom 表现不好(解析10mb的 xml 文件,就内存溢出了)

2.java解析xml文件

使用的是 dom4j 解析。需要导jar包(放在该笔记的同级目录下)

导入jar包

在idea中导入jar包有两种方式:

方式一:

依次 右击 " 项目名 -> New -> Directory " 新建目录lib(名字随意,最好固定下来), 然后将 jar 包复制到该目录下面,右击该 jar 包,点击 “Add as Library” 将该 jar 包导入该项目

方式二:

点击 “ File -> Project Structure -> Modules -> Dependencies -> 下方的 + 号 "

并选择第一个 ” JARS or Directories “,然后选择本机上的 jar 包,勾选前面的 “方框”,点击ok,Apply

到此,就可以将该jar包导入该项目

dom4j.jar包的版本选择1.6.1,不然的话后续Xpath中有些方法不能用

编写xml文件

右键src, 选择 XML File 创建 xml 文件。(这里我写的是test.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<students>
    <student type="usa" color="black">
        <id>1</id>
        <name>科比</name>
        <age>38</age>
    </student>
    <student type="england" color="write">
        <id>2</id>
        <name>乔丹</name>
        <age>30</age>
    </student>
</students>

补充:idea没有直接创建xml文件的选项,需要自己配置。步骤如下

  • 点击 File -> Setting -> Editor -> File and Code Templates
  • 点击 右侧 files ,再点击下方的 + 号。将右侧的 Name 选项填入 XML File, Extension 选项填入 xml

这样就可以通过new 来创建xml文件了

编写java代码解析xml文件中的内容

下面代码包含的东西很多:

​ 主要涉及反射,io流,集合。

​ java获取xml文件的根节点students,java获取xml文件根节点的下一层节点 student, java 遍历 student 节点下一层的所有元素, java获取 student 的 属性

package com;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.List;

public class TestXML_1 {
    /**
     * 常见错误:
     *文件位置错误:xml文件要放在src下
     * 类型引用错误:import 导包导错了
     */
    public static void main(String[] args) throws DocumentException {
        //1.加载xml文件到jvm中,形成数据流
        InputStream is =TestXML_1.class.getClassLoader().getResourceAsStream("test.xml");

        //2.创建解析对象
        SAXReader sax = new SAXReader();

        //3.获得文档对象(整个xml文件, 即上面的test.xml文件), 将数据流转换成一个xml 文件对象
        Document doc = sax.read(is);

        //4.获得根元素(root即上面的 students)
        Element root = doc.getRootElement();

        //5.获得根元素下的所有子节点(即 所有的 student)
        List<Element> list = root.elements();
        System.out.println(list.size());

        //lambada 表达式遍历list(即遍历 student)
        list.forEach(s -> System.out.println(s));

        //遍历节点
        for(Element e1: list){
            //使用增强for循环遍历list
           // System.out.println(e1.getName());
            List<Element> list2 = e1.elements(); //得到list的下一层元素(即 id name, age)
            for(Element e2 : list2){
                System.out.println(e2.getName() + ":"+ e2.getData());
            }
        }

        System.out.println("================");

        // 获取 student 标签的 相关属性(访问节点属性)
        for (Element e3 : list){
            Attribute type = e3.attribute("type");
            System.out.println(type.getValue());
        }
    }
}
使用java程序添加XML文件
package com;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import java.io.*;

public class TestXML_2 {
    public static void main(String[] args) throws DocumentException, IOException {
        
        InputStream is= TestXML_2.class.getClassLoader().getResourceAsStream("test.xml");
        SAXReader sax= new SAXReader();
        Document doc = sax.read(is);
        Element root = doc.getRootElement();

        //创建元素(节点)-> 对应 xml 文件中根节点的下一层级 student
        Element student = root.addElement("student");

        //在节点下创建 -> 对应xml文件中 student 层级的下一层级。这个操作是在内存中进行的
        Element id = student.addElement("id");
        id.setText("3");
        Element name = student.addElement("name");
        name.setText("姚明");
        Element age = student.addElement("age");
        age.setText("32");

        //写入xml文件中
        FileOutputStream out = new FileOutputStream(new File("D:/xx.xml"));
        OutputFormat format = new OutputFormat("\t",true, "UTF-8");
        XMLWriter xw = new XMLWriter(out,format);
        //将整个文档对象写入到文件中
        xw.write(doc);

        System.out.println("写入成功");
        xw.close();
    }
}

Xpath

xml 文件 path 路径

  • xpath 是一门在 xml 文档中快速查找信息的方式
  • 单纯的使用 dom4j 访问节点时, 需要一层一层的处理。如果有了xpath,范文层级的节点就简单了
  • 使用 xpath 需要导包: jaxen-1.1-beta-7.jar
package com;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.List;

public class TestXML_3 {
    public static void main(String[] args) throws Exception {
        InputStream is = TestXML_3.class.getClassLoader().getResourceAsStream("test.xml");
        SAXReader sax = new SAXReader();
        Document doc = sax.read(is);
        Element root = doc.getRootElement();

        //获得所有学生
//        List<Element> list= root.selectNodes("student");
//        list.forEach(s -> System.out.println(s));

        //查询所有学生的名字
        List<Element> list = root.selectNodes("student/name");
//        list.forEach(System.out::println);  //获得所有学生
        list.forEach(s -> System.out.println(s.getData()));

        //当xml文件中第二个层级有不同的标签(即不止有student,还有别的),如何获取他们下一层级相同的属性呢?
        // 将 "student/name" 改为 "//name"

        //获得第一个学生的名字
//        List<Element> list = root.selectNodes("student[1]/name");
//        list.forEach(s -> System.out.println(s.getData()));

        //获取前两个学生的名字
//        List<Element> list = root.selectNodes("student[position() < 3]/name");
//        list.forEach(s -> System.out.println(s.getData()));

        //获取最后一个学生的名字. 获得倒数第二个学生将 last() 改为 last() -1 即可
//        List<Element> list = root.selectNodes("student[last()]/name");
//        list.forEach(s -> System.out.println(s.getData()));


        //获取所有带 type 属性的学生
//        List<Element> list = root.selectNodes("student[@type]/name");
//        list.forEach(s -> System.out.println(s.getData()));

        //获取所有type属性等于 usa 的学生。usa必须加单引号,否则会跟前面的双引号冲突
//        List<Element> list = root.selectNodes("student[@type = ‘usa’]/name");
//        list.forEach(s -> System.out.println(s.getData()));

        //获取年龄大于32的学生
//        List<Element> list = root.selectNodes("student[age > 32]/name");
//        list.forEach(s -> System.out.println(s.getData()));

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值