【JavaEE学习笔记】XML_概述,DOM4J解析器,Pull解析器,DOM4J增删改,xPath

本文介绍XML的基本概念、功能及语法,详细讲解了DOM4J和Pull两种常用的XML解析方法,包括解析步骤、封装数据的方式以及如何利用DOM4J实现XML文档的增删改等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

XML

A.概述

1.起源

W3C万维网联盟,先定义出来的是HTML,XML推出初衷是为了替换HTML

因为HTML语法太过松散,为了规范,推出了XML语言

后来,XML语言用做配置文件,封装数据,版本只有一个v1.0

2.概念

可扩展标记语言:标签可以自定义

命名规范:不能用数字开头,不能使用纯数字,区分大小写

3.功能

a.用做配置文件

b.用做网络数据传输的载体

4.语法

新建一个文本文件,后缀名必须为.xml

5.组成部分

a.文档声明:<?xml version="1.0" encoding="utf-8"?>

encoding告诉浏览用什么编码去解析

文档声明必须在第一行,顶格

b.根标签:有且仅有一个根标签

c.其他标签:有开始标签,一定要有结束标签

d.文本:CDATA区:该区域的文本,会按照纯文本解析

格式:<![CDATA[内容]]>

<?xml version="1.0" encoding="UTF-8"?>
<students>
	<student id="s001">
		<name>张三</name>
		<age>23</age>
		<tel>110</tel>
	</student>
	<student id="s002">
		<name>李四</name>
		<age>24</age>
		<tel>119</tel>
	</student>
</students>

6.解析xml

a.DOM

将文档的各个组成部分 抽取一个对象

Element 标签对象

Attribute 属性对象

Text 文本对象

Comment 注释对象

Node 节点对象

Doucment 文档对象

解析过程:将文档一次性,加载进内存,然后将文档各个组成不封抽取为对象

优点:能够对文档进行增删改查

缺点:耗内存,适用于PC端

b.SAX

基于事件,逐行解析,一次读取一行,释放一行

优点:不占内存,适用于移动端

缺点:只能查,不能增删改

7.常用解析器

a.DOM4J:第三方jar包,实现了DOM思想


b.Pull解析器:第三方jar包,实现了SAX思想


B.DOM4J解析器

1.步骤

a.导入DOM4J jar包

b.将上一条的students.xml文件,放入工程根目录

<?xml version="1.0" encoding="UTF-8"?>
<students>	<!-- 根标签 -->
	<student id = "s001">	<!-- 子标签 -->
		<name>张三</name>
		<age>23</age>
		<tel>110</tel>
	</student>
	<student id = "s002">
		<name>李四</name>
		<age>24</age>
		<tel>120</tel>
	</student>
</students>

c.代码实现


2.获取标签对象

创建解析器对象

SAXReader reader = new SAXReader();

具体方法在代码中注释

package org.xxxx.dom4j;

import java.io.FileInputStream;
import java.util.Iterator;
import java.util.List;

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

public class DOM4JDemo {
	public static void main(String[] args) throws Exception {
		// 导入DOM4J jar包
		// 创建解析器对象
		SAXReader reader = new SAXReader();
		
		// 加载xml文件
		Document doc = reader.read(new FileInputStream("students.xml"));
		
		// 获取根标签对象 getRootElement();
		Element rootElement = doc.getRootElement();
		
		// 获取根标签下的子标签,默认获取的是第一个子标签 element();
		Element stuElement = rootElement.element("student");
		System.out.println("根标签下的子标签(默认第一个):" + stuElement.getName());
		
		System.out.println("----------获取所有子标签----------");
		
		// 1)elements();返回结果集
		List<Element> ele = rootElement.elements();
		for (Element e : ele) {
			System.out.println(e.getName());
		}
		
		// 2)迭代器获取 elementIterator();
		System.out.println("----------迭代器获取所有子标签----------");
		Iterator<Element> elementIterator = rootElement.elementIterator();
		while (elementIterator.hasNext()) {
			Element element = elementIterator.next();
			System.out.println(element.getName());
		}
	}
}

3.获取属性对象和标签之间的文本

三种方式,代码中实现

package org.xxxx.dom4j;

import java.io.FileInputStream;
import java.util.Iterator;
import java.util.List;

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

public class DOM4JDemo {
	public static void main(String[] args) throws Exception {
		// 导入DOM4J jar包
		// 创建解析器对象
		SAXReader reader = new SAXReader();
		
		// 加载xml文件
		Document doc = reader.read(new FileInputStream("students.xml"));
		
		// 方式1:分布获取属性对象
		// 获取跟标签对象
		Element rootElement = doc.getRootElement();
		
		// 获取属性对象
		Element element = rootElement.element("student");
		
		// 获取属性id attribute("id");
		Attribute attribute = element.attribute("id");
		
		// 获取值
		String value = attribute.getValue();
		String name = attribute.getName();
		System.out.println(name + "---" + value);
		
		// 方式2:直接获取属性值
		System.out.println("--------------------------");
		String value2 = rootElement.element("student").attributeValue("id");
		System.out.println(value2);
		
		// 方式3:获取所有属性对象 attributes();
		System.out.println("------------------");
		List<Attribute> attributes = rootElement.element("student").attributes();
		for (Attribute attr : attributes) {
			String name2 = attr.getName();
			String value3 = attr.getValue();
			System.out.println(name2 + "---" + value3);
		}
		
		// 通过迭代器获取所有属性对象
		System.out.println("------------------");
		Iterator<Attribute> attributeIterator = rootElement.element("student").attributeIterator();
		while (attributeIterator.hasNext()) {
			Attribute attribute2 = attributeIterator.next();
			System.out.println(attribute2.getName() + "---" + attribute2.getValue());
		}
		
		// 获取标签之间的文本
		System.out.println("------------------");
		// 方式1:层层往下拿
		String text1 = doc.getRootElement().element("student").element("name").getText();
		System.out.println(text1);
		
		// 方式2:一步到位
		String text2 = doc.getRootElement().element("student").elementText("name");
		System.out.println(text2);
		
	}
}

4.获取所有节点

a.node():获取单个节点对象;nodeIterator(); 获取多个节点对象,只能获取子节点

b.获取根标签对象 getRootElement()

c.Element()获取第一个子标签

   Elements() 获取所有的子标签 

   elememtesIterator() 获取所有子标签对象

d.attribute() 获取单个属性对象  getName()获取属性的键  getValue()获取属性的值

   attributes()获取所有的属性对象 

   attributeIterator() 获取所有的属性对象

   直接获取属性对象的值 attributeValue()

e.先获取到文本所在的标签对象 通过getText()拿出这个标签直接的文本elementText("name");

package org.xxxx.dom4j;

import java.io.FileInputStream;
import java.util.Iterator;

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

public class DOM4JDemo {
	public static void main(String[] args) throws Exception {
		// 导入DOM4J jar包
		// 创建解析器对象
		SAXReader reader = new SAXReader();
		
		// 加载xml文件
		Document doc = reader.read(new FileInputStream("students.xml"));
		
		// 方式1:分布获取属性对象
		// 获取跟标签对象
		Element rootElement = doc.getRootElement();
		
		// 使用递归获取所有节点
		getNodes(rootElement);
		
	}

	private static void getNodes(Element ele) {
		// 输出当前节点
		System.out.println(ele.getName());
		
		// 迭代器获取所有子节点
		Iterator<Node> iterator = ele.nodeIterator();
		
		// 遍历
		while (iterator.hasNext()) {
			Node nodes = iterator.next();
			// 判断节电是否属于标签
			if (nodes instanceof Element) {
				Element eles = (Element) nodes;
				
				// 调用递归
				getNodes(eles);
			}
		}
	}
}

5.封装数据

把从xml中解析的数据封装起来

a.创建javabean存放对象

package org.xxxx.dom4j.bean;

import java.io.Serializable;

public class Student implements Serializable {

	private static final long serialVersionUID = 1L;

	private String id;
	private String name;
	private String age;
	private String tel;

	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Student(String id, String name, String age, String tel) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
		this.tel = tel;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	public String getTel() {
		return tel;
	}

	public void setTel(String tel) {
		this.tel = tel;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", age=" + age + ", tel=" + tel + "]";
	}

}

b.测试类

package org.xxxx.dom4j;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Iterator;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xxxx.dom4j.bean.Student;

public class FZStudent {
	public static void main(String[] args) throws Exception {
		// 创建集合存储对象
		ArrayList<Student> list = new ArrayList<>();

		// 创建解析器
		SAXReader reader = new SAXReader();

		// 加载xml文件
		Document doc = reader.read(new FileInputStream("students.xml"));

		// 获取根标签对象
		Element rootElement = doc.getRootElement();

		// 获取所有的子标签对象
		Iterator<Element> elementIterator = rootElement.elementIterator();

		// 遍历取出数据并封装
		while (elementIterator.hasNext()) {
			Element element = elementIterator.next();

			// 直接获取属性的值
			String id = element.attributeValue("id");

			// 获取标签之间的文本
			String name = element.elementText("name");
			String age = element.elementText("age");
			String tel = element.elementText("tel");

			// 封装到对象中
			Student stu = new Student(id, name, age, tel);

			// 添加到集合中
			list.add(stu);
		}

		// 遍历集合
		for (Student s : list) {
			System.out.println(s.getId() + "---" + s.getName() + "---" + s.getAge() + "---" + s.getTel());
		}
	}
}

C.Pull解析器

1.概述

SAX:逐行解析,读取一行,释放一行,不占内存

2.需求(序列化与反序列化)

将students.xml文件读取到内存中(反序列化),然后保存到stu.xml文件中去(序列化)

主要方法在代码中注释

注意:写入文档,标签要成对的写

serializer.startDocument("utf-8", true);       // standalone='yes' 文档是否独立

在此写根标签,子标签,都是成对写

serializer.endDocument();     // 文档结束

package org.xxxx.pull;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
import org.xxxx.pull.bean.Student;

public class PullParseDemo {
	// 创建集合,存放对象
	private static ArrayList<Student> list;
	private static Student student;

	public static void main(String[] args) throws Exception {
		// 导入jar包
		// 获取解析器工厂对象
		XmlPullParserFactory factory = XmlPullParserFactory.newInstance();

		// 获取解析器
		XmlPullParser parser = factory.newPullParser();

		// 读取文件内容到内存中:反序列化
		// 加载文件
		// 参数1:要解析的文件 参数2:编码格式
		parser.setInput(new FileInputStream("students.xml"), "utf-8");

		// 获取事件类型
		// 指针默认的位置在文档开始
		// 从硬盘中把文件数据读取到内存中,即反序列化
		// 获取起始位置
		int type = parser.getEventType();

		// 一次读取,当判断条件为1,则表示读取到最后一行,结束循环
		// 使用XmlPullParse.END_DOCUMENT结束标记,不要直接写1
		while (type != XmlPullParser.END_DOCUMENT) {
			// 获取标签名称
			String tagName = parser.getName();

			// 判断
			switch (type) {
			case XmlPullParser.START_TAG: // 标签开始事件
				if ("students".equals(tagName)) {
					// 是根标签,创建集合
					list = new ArrayList<>();

				} else if ("student".equals(tagName)) {
					// 子标签,创建javabean对象
					student = new Student();

					// 获取id
					String id = parser.getAttributeValue(0); // 从0开始

					// 写入对象
					student.setId(id);

				} else if ("name".equals(tagName)) {
					// 获取标签之间的文本
					// String name = parser.getText(); 这个获取不到,注意
					String name = parser.nextText();

					// 写入对象
					student.setName(name);

				} else if ("age".equals(tagName)) {
					// 获取年龄
					String age = parser.nextText();
					student.setAge(age);

				} else if ("tel".equals(tagName)) {
					String tel = parser.nextText();
					student.setTel(tel);
				}
				break;

			case XmlPullParser.END_TAG: // 结束标签时间
				if ("student".equals(tagName)) {
					list.add(student);
				}
				break;

			}
			type = parser.next(); // 让指针下移,获取新的事件类型,并重新赋值,防止死循环
		}
		// 遍历集合,查看是否读取完毕
		for (Student stu : list) {
			System.out.println(stu.getId() + "---" + stu.getName() + "---" + stu.getAge() + "---" + stu.getTel());
		}

		System.out.println("--------------------------------");
		// 接下来,开始存储数据到stu.xml文件中,也就是序列化
		// 抽取一个方法
		SavaDataToXML(factory);

	}

	private static void SavaDataToXML(XmlPullParserFactory factory) throws XmlPullParserException, IllegalArgumentException, IllegalStateException, FileNotFoundException, IOException {
		// 获取序列化器
		XmlSerializer serializer = factory.newSerializer();
		
		// 设置输出流关联文件
		serializer.setOutput(new FileOutputStream("stu.xml"), "utf-8");
		
		// 写入文档声明
		// 参数1:编码    参数2:文档是否独立
		// 文档开始,也要有文档结束,成对去写
		serializer.startDocument("utf-8", true);	// standalone='yes' 文档是否独立
		
		// 写入根标签
		// 参数1 命名空间,一般给null   参数2 标签名称
		serializer.startTag(null, "students");	// 写入开始标签
		
		// 遍历集合,写子标签
		for (Student stu : list) {
			// 写入student标签
			serializer.startTag(null, "student");
			
			// 写入id属性 参数1 命名空间   参数2 属性名 参数3 属性值
			serializer.attribute(null, "id", stu.getId());
			
			// 写入name标签
			serializer.startTag(null, "name");
			
			// 写入文本name
			serializer.text(stu.getName());
			
			serializer.endTag(null, "name");
			
			// 写入age标签
			serializer.startTag(null, "age");
			
			// 写入文本age
			serializer.text(stu.getAge());
			
			serializer.endTag(null, "age");

			// 写入tel标签
			serializer.startTag(null, "tel");
			
			// 写入文本tel
			serializer.text(stu.getTel());
			
			serializer.endTag(null, "tel");
			
			// studeng结束标签
			serializer.endTag(null, "student");
		}
		
		serializer.endTag(null, "students");	// 写入结束标签
		
		serializer.endDocument();	// 文档结束
	}
}

运行完毕,刷新工程,查看stu.xml文件




D.DOM4J解析实现增删改

1.修改删除

a.先读取到内存中,进行修改

主要方法

setText();就是设置文本

detach();删除标签

b.重新写入硬盘覆盖掉源文件

XMLWriter 类

c.代码实现

修改以下xml文件

<?xml version="1.0" encoding="UTF-8"?>
<students>
  <student id="s001">
    <name>张三</name>
    <gender>男</gender>
  </student>
  <student id="s002">
    <name>李四</name>
    <gender>女</gender>
  </student>
</students>
修改张三的姓名为王五,性别为空

删除id="002"的属性

package org.xxxx.xml;

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

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

public class Demo01 {
	public static void main(String[] args) throws Exception {
		// 读取xml文件
		SAXReader reader = new SAXReader();
		Document doc = reader.read(new FileInputStream("students.xml"));

		// 修改文本
		// 第一个标签,直接获取
		doc.getRootElement().element("student").element("name").setText("王五");
		doc.getRootElement().element("student").element("gender").setText("");
		
		// 删除属性
		// 获取根标签
		Element rootElement = doc.getRootElement();
		
		// 获取属性集
		List<Element> elements = rootElement.elements();
		
		// 遍历
		for (Element ele : elements) {
			// 获取属性
			String value = ele.attributeValue("id");
			
			if (value.equals("s002")) {
				ele.attribute("id").detach();
			}
		}
		
		// 重新写入硬盘
		XMLWriter writer = new XMLWriter(new FileOutputStream("students.xml"));
		writer.write(doc);
		writer.close();
	}
}

2.增加属性

添加标签:用文档帮助类DocumentHelper,创建一个文档,最后记得XMLWriter 写到硬盘

添加标签:addElement("标签名");

添加属性:addAtrriburte("属性","属性值")

添加文本:addText("文本");

package org.xxxx.xml;

import java.io.FileOutputStream;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;

public class Demo02 {
	public static void main(String[] args) throws Exception {
		// 用代码写一个xml
		// 文档帮助类写一个声明
		Document doc = DocumentHelper.createDocument();
		
		// 添加一个根标签
		Element rootEle = doc.addElement("students");
		
		// 添加一个子标签
		// 根标签的子标签,用根标签调,后面同理
		Element stuELe = rootEle.addElement("student");
		
		// 添加属性
		stuELe.addAttribute("id", "s001");
		
		// 添加名字标签
		Element name = stuELe.addElement("name");
		
		// 添加名字
		name.addText("张三");
		
		// 添加年龄
		Element age = stuELe.addElement("age");
		age.addText("20");
		
		// 添加电话
		Element tel = stuELe.addElement("tel");
		tel.addText("110");
		
		// 写到硬盘上
		XMLWriter writer = new XMLWriter(new FileOutputStream("mydoc.xml"));
		writer.write(doc);
		writer.close();
	}
}
运行程序,刷新工程


E.xPath

1.概述

路径规则书写的一门技术,它的作用是用来快速找到

XML文档中一个或多个标签,不需要一层一层标签去获取

直接通过标签的特征检索

2.步骤

a.导入DOM4J jar包和支持xPath技术的jar包


b.定义path语句

比如寻找id="s002"的student标签

String path = "//student[@id='s002']";

寻找name为王五的人标签

String path = "//name[text()='王五']";

c.配合xPath找到单个节点对象

		Element selectSingleNode = (Element) doc.selectSingleNode(path);
		System.out.println(selectSingleNode.getName());

d.找到根标签下的所有标签 selectNodes(path);配合xPath 找到多个节点

		String path = "//student";
		List<Node> selectNodes = doc.selectNodes(path);
		for (Node node : selectNodes) {
			System.out.println(node.getName());
		}

3.还有很多方法,可以查阅官方文档


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值