XML语法和DOM4j及DOM4j的源码分析和增删改查xml

165 阅读7分钟

XML 语法

一个 XML 文件分为如下几部分内容
1、文档声明
2、元素
3、属性
4、注释
5、CDATA 区 、特殊字符, 后面会说

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

1、XML 声明放在 XML 文档的第一行
2、XML 声明由以下几个部分组成:
3、version - -文档符合 XML1.0 规范,我们学习 1.0
4、encoding - -文档字符编码,比如"utf-8" 

元素 

1. 元素语法要求

  1. 每个XML文档必须有且只有一个根元素。
  2. 根元素是一个完全包括文档中其他所有元素的元素。
  3. 根元素的起始标记要放在所有其他元素的起始标记之前。
  4. 根元素的结束标记要放在所有其他元素的结束标记之后。
<?xml version="1.0" encoding="utf-8" ?>
<!--
1.每个 XML 文档必须有且只有一个根元素。
2.根元素是一个完全包括文档中其他所有元素的元素。
3.根元素的起始标记要放在所有其他元素的起始标记之前。
4.根元素的结束标记要放在所有其他元素的结束标记之后
5.XML 元素指 XML 文件中出现的标签,一个标签分为开始标签和结束标签,一
个标签有如下几种书写形式
包含标签体:<a>www.sohu.cn</a>
不含标签体的:<a></a>, 简写为:<a/>
6.一个标签中也可以嵌套若干子标签。但所有标签必须合理的嵌套,绝对不允许
交叉嵌套
7. 叫法 student 元素,节点,标签
-->
<students>
    <student id="200">
        <name>123</name>
        <age>10</age>
        <gender></gender>
    </student>
    <student id="200">
        <name>66</name>
        <age>18</age>
        <gender></gender>
    </student>
    <school>大学</school>
    <city/>
</students>

2. 出现的标签

XML 元素指 XML 文件中出现的标签,一个标签分为开始标签和结束标签,一个标签有如
下几种书写形式,例如:

  1.  包含标签体:<a>www.sohu.cn</a>
  2. 不含标签体的:<a></a>, 简写为:<a/>
  3.  一个标签中也可以嵌套若干子标签。但所有标签必须合理的嵌套,绝对不允许交叉嵌套 ,

例如:<a>welcome to <b>www.sohu.org</a></b>

提示:在很多时候,说 标签、元素、节点是相同的

4. XML 元素命名规则

  1. 区分大小写,例如,<P>和<p>是两个不同的标记。
  2. 不能以数字开头。
  3. 不能包含空格。
  4. 名称中间不能包含冒号(:)。
  5. 如果标签单词需要间隔,建议使用下划线 比如 <book_title>hello</book_title>
<?xml version="1.0" encoding="utf-8" ?>
<!--解读
1.区分大小写,例如,<P>和<p>是两个不同的标记。
2.不能以数字开头。
3.不能包含空格。
4.名称中间不能包含冒号(:)。
5.如果标签单词需要间隔,建议使用下划线 比如 <book_title>hello</book_title>
-->
<students>
    <student id="10">
        <name>www</name>
        <age>10</age>
        <gender></gender>
        <email>@</email>
        <Email>@</Email>
        <job>java</job>
    </student>
    <student id="11">
        <name>mary</name>
        <age>33</age>
        <gender></gender>
    </student>
</students>

属性

1. 属性介绍

<Student ID="100">
<Name>TOM</Name>
</Student>


2. 属性值用双引号(")或单引号(')分隔(如果属性值中有',用"分隔;有",用'分隔)
3. 一个元素可以有多个属性,它的基本格式为:<元素名 属性名="属性值">
4. 特定的属性名称在同一个元素标记中只能出现一次
5. 属性值不能包括& 字符
6. 属性应用实例 修改 students04.xml        

<?xml version="1.0" encoding="utf-8" ?>
<!-- 解读
1.属性值用双引号(")或单引号(')分隔(如果属性值中有',用"分隔;有",
用'分隔)
2.一个元素可以有多个属性,它的基本格式为:<元素名 属性名="属性值">
3.特定的属性名称在同一个元素标记中只能出现一次
4.属性值不能包括& 字符
-->
<students>
    <!-- 举例:
    id='01' 也是正确写法
    如果属性值有" 则使用' 包括属性 比如 id="xxx'yyy" 如果属性值有' 则使用" 包括属性 比如 id='xxx"yyy' 属性名在同一个元素标记只能出现一次 <stduent id="01" id="03"> 错误
    的
    属性值不能包括& 字符 比如: <stduent id="0&1"> 是错误的
    -->
    <student id="100">
        <name>1</name>
        <age>15</age>
        <gender></gender>
    </student>
    <student id="200">
        <name>2</name>
        <age>15</age>
        <gender></gender>
    </student>
</students>

注释

  1. <!--这是一个注释- ->
  2. 注释内容中不要出现- -;
  3. 不要把注释放在标记中间;错误写法 <Name <!--the name-->>TOM</Name>
  4. 注释不能嵌套;
  5. 可以在除标记以外的任何地方放注释

CDATA 节!

说明: 有些内容不想让解析引擎执行,而是当作原始内容处理(即当做普通文本),可
以使用 CDATA 包括起来,CDATA 节中的所有字符都会被当作简单文本,而不是 XML 标记。

1. 语法:
<![CDATA[
这里可以把你输入的字符原样显示,不会解析 xml
]]>
2. 可以输入任意字符(除]]>外)
3. 不能嵌

<?xml version="1.0" encoding="utf-8"?>
<!-- 解读
<![CDATA[
这里可以把你输入的字符原样显示,不会解析 xml
]]>
-->
<students>
    <stduent id="01">
        <name>tom</name>
        <gender></gender>
        <age>18</age>
        <!-- 举例说明:
        下面是一段 js 的代码片段. 直接放在<code></code>标签间,语法错误
        使用 CDATA 节来处理即可. <script data-compress=strip>
        function h(obj){
        obj.style.behavior='url(#default#homepage)';
        var a = obj.setHomePage('//www.baidu.com/');
        }
        </script>
        -->
    </stduent>
    <stduent id="02">
        <name>scott</name>
        <gender></gender>
        <age>17</age>
        <code>
            <!--如果希望把某些字符串,当做普通文本,使用 CDATA 包括 -->
            <![CDATA[
                        <script data-compress=strip>
                        function h(obj){
                        obj.style.behavior='url(#default#homepage)';
                        var a = obj.setHomePage('//www.baidu.com/');

                        }
                        </script>
                    ]]>
        </code>
    </stduent>
</students>

转义字符

1. 对于一些单个字符,若想显示其原始样式,也可以使用转义的形式予以处理

转义符符号
<<
>
&&
""
&apos

小结

遵循如下规则的 XML 文档称为格式正规的 XML 文档:

  1. XML 声明语句 <?xml version="1.0" encoding="utf-8"?>
  2. 必须有且仅有一个根元素
  3. 标记大小,区分大小写的.
  4. 属性值用引号
  5. 标记成对
  6. 空标记关闭
  7. 元素正确嵌套

DOM4j

文档: dom4j.github.io/javadoc/1.6…

本地文档: dom4j-1.6.1\docs\index.html

XML 解析技术原理

  1. 不管是 html 文件还是 xml 文件它们都是标记型文档,都可以使用 w3c 组织制定的dom 技术来解析
  2. document 对象表示的是整个文档(可以是 html 文档,也可以是 xml 文档)

XML 解析技术介绍


● 早期 JDK 为我们提供了两种 xml 解析技术 DOM 和 Sax 简介

  1. dom 解析技术是 W3C 组织制定的,而所有的编程语言都对这个解析技术使用了自己语言的特点进行实现。 Java 对 dom 技术解析也做了实现
  2. sun 公司在 JDK5 版本对 dom 解析技术进行升级:SAX( Simple API forXML)SAX解析,它是以类似事件机制通过回调告诉用户当前正在解析的内容。 是一行一行的读取 xml 文件进行解析的不会创建大量的 dom 对象。 所以它在解析 xml 的时候,在性能上优于 Dom 解析
  3. 这两种技术已经过时,知道有这两种技术即可

● 第三方的 XML 解析技术

  1. jdom 在 dom 基础上进行了封装
  2. dom4j 又对 jdom 进行了封装。
  3. pull 主要用在 Android 手机开发,是在跟 sax 非常类似都是事件机制解析 xml 文件

DOM4J 介绍

  1. Dom4j 是一个简单、灵活的开放源代码的库(用于解析/处理 XML 文件)。Dom4j 是由早期开发JDOM 的人分离出来而后独立开发的。
  2. 与 JDOM 不同的是,dom4j 使用接口和抽象基类,虽然 Dom4j 的 API 相对要复杂一些,但它提供了比 JDOM 更好的灵活性。
  3.  Dom4j 是一个非常优秀的 Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的 Dom4j。

DOM4j 中,获得 Document 对象的方式有三种

● 开发 dom4j 要导入 dom4j 的包
1、读取 XML 文件,获得 document 对象
SAXReader reader = new SAXReader(); //创建一个解析器
Document document = reader.read(new File("src/input.xml"));//XML Document

2、解析 XML 形式的文本,得到 document 对象
String text = "<members></members>";
Document document = DocumentHelper.parseText(text);

3.主动创建 document 对象. 
Document document = DocumentHelper.createDocument(); //创建根节点
Element root = document.addElement("members");

DOM4j 应用实列

源码

 增删改查代码

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.jupiter.api.Test;

import java.io.File;

import java.io.FileOutputStream;
import java.util.List;

public class Dom4j_ {

    /**
     * 指定读取第一个学生的信息 就是 dom4j+xpath
     */
    @Test
    public void readOne() throws DocumentException {
        //得到一个解析器
        SAXReader reader = new SAXReader();
        //代码技巧->debug 看看 document 对象的属性
        //分析了 document 对象的底层结构
        Document document = reader.read(new File("src/students.xml"));

        //1. 得到 rootElement, 你是 OOP
        Element rootElement = document.getRootElement();
        //2. 获取第一个学生
        Element student = (Element) rootElement.elements("student").get(1);
        //3. 输出该信息
        System.out.println("该学生的信息= " + student.element("name").getText() + " " +
                student.element("age").getText() + " " +
                student.element("resume").getText() +
                student.element("gender").getText());
        //4. 获取 student 元素的属性
        System.out.println("id= " + student.attributeValue("id"));
    }

    /**
     * 加元素(要求: 添加一个学生到 xml 中) [不要求,使用少,了解]
     *
     * @throws Exception
     */
    @Test
    public void add() throws Exception {
        //1.得到解析器
        SAXReader saxReader = new SAXReader();
        //2.指定解析哪个 xml 文件
        Document document = saxReader.read(new File("src/students.xml"));
        //首先我们来创建一个学生节点对象
        Element newStu = DocumentHelper.createElement("student");
        Element newStu_name = DocumentHelper.createElement("name");
        //如何给元素添加属性
        newStu.addAttribute("id", "04");
        newStu_name.setText("宋江");
        //创建 age 元素
        Element newStu_age = DocumentHelper.createElement("age");
        newStu_age.setText("23");
        //创建 resume 元素
        Element newStu_intro = DocumentHelper.createElement("resume");
        newStu_intro.setText("梁山老大");

        //把三个子元素(节点)加到 newStu 下
        newStu.add(newStu_name);
        newStu.add(newStu_age);
        newStu.add(newStu_intro);
        //再把 newStu 节点加到根元素
        document.getRootElement().add(newStu);
        //直接输出会出现中文乱码:
        OutputFormat output = OutputFormat.createPrettyPrint();
        output.setEncoding("utf-8");//输出的编码 utf-8
        //把我们的 xml 文件更新
        // lets write to a file
        //new FileOutputStream(new File("src/myClass.xml"))
        //使用到 io 编程 FileOutputStream 就是文件字节输出流
        XMLWriter writer = new XMLWriter(
                new FileOutputStream(new File("src/students.xml")), output);
        writer.write(document);
        writer.close();
    }
    
/**
 * //删除元素(要求:删除第一个学生) 使用少,了解
 * @throws Exception
 */
    @Test

    public void del() throws Exception {
        //1.得到解析器
        SAXReader saxReader = new SAXReader();
        //2.指定解析哪个 xml 文件
        Document document = saxReader.read(new File("src/students.xml"));
        //找到该元素第一个学生
        Element stu = (Element)
                document.getRootElement().elements("student").get(2);
        //删除元素
        stu.getParent().remove(stu);
        // //删除元素的某个属性
        // stu.remove(stu.attribute("id"));
        //更新 xml
        //直接输出会出现中文乱码:
        OutputFormat output = OutputFormat.createPrettyPrint();
        韩顺平 Java 工程师
        output.setEncoding("utf-8");//输出的编码 utf-8
        //把我们的 xml 文件更新
        XMLWriter writer = new XMLWriter(
                new FileOutputStream(new File("src/students.xml")), output);
        writer.write(document);
        writer.close();
        System.out.println("删除成功~");
    }

    /**
     * //更新元素(要求把所有学生的年龄+3) 使用少,了解
     *
     * @throws Exception
     */
    @Test
    public void update() throws Exception {
        //1.得到解析器
        SAXReader saxReader = new SAXReader();
        //2.指定解析哪个 xml 文件
        Document document = saxReader.read(new File("src/students.xml"));
     
        //得到所有学生的年龄
        List<Element> students = document.getRootElement().elements("student");
        //遍历, 所有的学生元素的 age+3
        for (Element student : students) {
            //取出年龄
            Element age = student.element("age");
            age.setText((Integer.parseInt(age.getText()) + 3) + "");
        }
        //更新
        //直接输出会出现中文乱码:
        OutputFormat output = OutputFormat.createPrettyPrint();
        output.setEncoding("utf-8");//输出的编码 utf-8
        //把我们的 xml 文件更新
        XMLWriter writer = new XMLWriter(
                new FileOutputStream(new File("src/students.xml")), output);
        writer.write(document);
        writer.close();
        System.out.println("更新成功~");
    }
}