Java 框架基础技术之 02-XML
AI 摘要
XML 概述
XML 简介
XML 即可扩展标记语言,是一种简单的数据存储语言,使用一系列简单的标记来描述结构化数据。
XML 的特点:
- XML 与操作系统、编程语言的开发平台都无关。
- 规范统一,实现不同系统之间的数据交互。
XML 的作用:数据存储、数据交换、数据配置等。
XML 文档的基本结构:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<!-- 图书信息 -->
<book id="bk101">
<title>.NET高级编程</title>
<author>王姗</author>
<description>包含C#框架和网络编程等</description>
</book>
<book id="bk102">
<title>XML基础编程</title>
<author>李明明</author>
<description>包含XML基础概念和基本用法</description>
</book>
</books>XML 文档由声明、用于构建内容结构的元素、为元素补充特性的属性以及包含实际数据的文本内容等组成。
XML 声明
XML 声明即 XML 代码的第一行,用于标明该文件是一个 XML 文档,其定义了 XML 的版本和所使用的编码信息。
对于任何一个 XML 文档,其声明部分都是固定格式。
<?xml version="1.0" encoding="UTF-8"?>XML 标签
在 XML 中,通过尖括号括起来的各种标签来标记数据,标签成对使用来界定字符数据。
XML 标签必须正确结束并且正确嵌套。
<元素名>...</元素名>XML 元素
XML 元素由开始标签、结束标签和元素内容组成。
XML 元素的基本命名规则:
- 名称中可以包含字母、数字或者其他的字符。
- 名称不能以数字或者标点符号开始。
- 名称不能以字符 xml、XML、Xml 开始。
- 名称中不能含空格。
XML 根元素
每个 XML 文档必须有且只有一个根元素,根元素是一个完全包括文档中其他所有元素的元素。
<?xml version="1.0" encoding="UTF-8"?>
<book>
<!-- ... -->
</book>XML 属性
XML 元素可以指定属性信息。
<元素名 属性名="属性值" 属性名="属性值">...</元素名>XML 特殊字符处理
在 XML 中,无法解析一些特殊字符,如“\<、\>、'、"、&”,在使用时可以对特殊字符进行转义。
在 XML 中解析特殊字符,还可以使用 CDATA 进行处理。
CDATA 的基本用法:
<![CDATA[...]]>示例:XML 特殊字符处理
衣服尺码 XML 数据(classpath:ClothesSize.xml):
<?xml version="1.0" encoding="UTF-8"?>
<clothesSize>
<size range="height<165">S</size>
<size range="165<height<170">M</size>
<size range="110<height<175">L</size>
<size range="175<height<180">XL</size>
<size range="180<height<185">XXL</size>
</clothesSize>XML 解析技术
目前主流的 XML 解析技术:
- DOM:基于 XML 文档树结构来完成解析,适用于多次访问的 XML 文档,但是比较消耗资源。
- SAX:基于事件的解析,适用于大数据量的 XML 文档,占用资源少,内存消耗小。
- JDOM:针对 Java 的特定文档模型,API 大量使用了 Java 集合类型。
- DOM4J:非常优秀的开源 Java XML API,比 JDOM 更加灵活,使用范围更广。
使用 DOM 解析 XML
DOM 概述
DOM 即文档对象模型(Document Object Model),DOM 把 XML 文件映射成一颗倒挂的 “树”,以根元素为根节点,每个节点都以对象的形式存在。
<book>
<title>三国演义</title>
<author>罗贯中</author>
<price>30元</price>
</book>DOM 结构:
DOM API 概述
在 Java 中,可以使用 Oracle 公司提供的 JAXP(Java API for XML Processing)来解析 XML。
JAXP 包含三个包,这三个包都在 JDK 中。
- org.w3c.dom:W3C 推荐的用于使用 DOM 解析 XML 文档的接口。
- org.xml.sax:用于使用 SAX 解析 XML 文档的接口。
- javax.xml.parsers:解析器工厂工具,获得并配置特殊的分析器。
使用 DOM 操作 XML 时主要使用 Document、NodeList、Node、Element 对象。
Document 对象代表整个 XML 文档,它是 DOM 树的根节点,提供了访问和操作 XML 文档的入口点。
Document 对象的基本方法:
| 名称 | 描述 |
|---|---|
| NodeList getElementsByTagName(String tagName) | 根据标签名称返回节点列表 |
| Element getDocumentElement() | 返回 XML 文档根元素对象 |
| Element createElement(String tagName) | 创建元素 |
NodeList 对象是一个节点的集合。
NodeList 对象的基本方法:
| 名称 | 描述 |
|---|---|
| int getLength() | 返回节点集合的长度 |
| Node item(int index) | 返回指定位置的节点对象 |
Node 对象是 DOM 树中的基本抽象节点类型,代表 XML 文档中的一个节点,可以是元素、属性、文本、注释、空白符等。
Node 对象的基本方法:
| 名称 | 描述 |
|---|---|
| NodeList getChildNodes() | 返回包含此节点所有子节点的节点集合 |
| Node getFirstChild() | 返回第一个子节点 |
| Node getLastChild() | 返回最后一个子节点 |
| Node getNextSibling() | 返回当前节点的下一个兄弟节点 |
| Node getPreviousSibling() | 返回当前节点的上一个兄弟节点 |
| Node appendChild(Node child) | 将 child 节点追加到节点的末尾 |
| String getNodeName() | 返回节点名称 |
| String getNodeValue() | 返回节点的值 通常用于获取文本节点的文本值或属性节点的值,对元素节点返回 null |
| short getNodeType() | 返回节点的类型 |
| String getTextContent() | 返回节点的值 通常用于获取元素节点及其子节点的所有文本内容 |
| void setTextContent(String value) | 设置节点的值 |
Element 对象表示 XML 文档中的元素节点,Element 对象继承了 Node 对象。
通常在处理 XML 文档的结构和数据时,使用 Element 对象来操作具体的元素节点,进行数据提取、修改等操作。
Element 对象的基本方法:
| 名称 | 描述 |
|---|---|
| String getAttribute(String name) | 返回 name 属性的属性值 |
| NodeList getElementsByTagName(String tagName) | 根据标签名称返回节点列表 |
使用 DOM 读取数据
在 Java 中使用 DOM 解析 XML 文档的基本步骤:
- 创建解析器工厂 DocumentBuilderFactory 对象。
- 由解析器工厂对象创建解析器 DocumentBuilder 对象。
- 由解析器对象对 XML 文件进行解析、构建 DOM 树,创建相应的 Document 对象。
- 以 Document 对象为起点对 DOM 树的节点进行增加、删除、修改、查询等操作。
示例:使用 DOM 读取数据
手机 XML 数据(classpath:phone.xml):
<?xml version="1.0" encoding="UTF-8"?>
<PhoneInfo>
<Brand name="华为">
<type name="Mate X5">
<price>14999.00</price>
</type>
<type name="Mate 60">
<price>8999.00</price>
</type>
</Brand>
<Brand name="苹果">
<type name="iPhone 15">
<price>9999.00</price>
</type>
<type name="iPhone 14">
<price>7999.00</price>
</type>
</Brand>
</PhoneInfo>测试类(cn.duozai.TestMain):
public class TestMain {
public static void main(String[] args) throws Exception {
// 读取并解析XML
// 创建解析器工厂DocumentBuilderFactory对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 创建解析器DocumentBuilder对象
DocumentBuilder db = dbf.newDocumentBuilder();
// 解析XML文档
Documentdocument = db.parse("resources/phone.xml");
// 获取手机品牌Brand节点列表
NodeList brandList = document.getElementsByTagName("Brand");
// 遍历手机品牌Brand节点列表
for (int i = 0; i < brandList.getLength(); i++) {
// 获取遍历的手机品牌Brand节点对象
Node brandNode = brandList.item(i);
// 将手机品牌Brand节点对象转换成元素对象
Element brandElement = (Element) brandNode;
// 获取手机品牌Brand元素对象的name属性的值
String brandName = brandElement.getAttribute("name");
// 获取手机品牌Brand元素对象的手机型号type子节点列表
NodeList typeList = brandElement.getElementsByTagName("type");
// 遍历手机型号type节点列表
for (int j = 0; j < typeList.getLength(); j++) {
// 获取遍历的手机型号type节点对象
Node typeNode = typeList.item(j);
// 将手机型号type节点对象转换成元素对象
Element typeElement = (Element) typeNode;
// 获取手机型号type元素对象的name属性的值
String typeName = typeElement.getAttribute("name");
// 获取手机型号type元素对象的型号价格price子节点列表
NodeList priceNodeList = typeElement.getElementsByTagName("price");
// 将第一个型号价格price节点对象转换成元素对象
Element priceElement = (Element) priceNodeList.item(0);
// 获取型号价格price元素对象的文本内容
String price = priceElement.getTextContent();
// 输出手机品牌名称+手机型号名称+型号价格
System.out.println(brandName + typeName + "的价格是" + price);
}
}
}
}示例效果:
使用 DOM 添加数据
使用 DOM 添加数据的基本步骤:
- 为 XML 文档构建 DOM 树。
- 创建新节点,并设置节点属性。
- 把节点添加到其所属父节点上。
- 保存 XML 文档。
保存 XML 文档的基本步骤:
- 获得 TransformerFactory 对象。
- 通过 TransformerFactory 对象创建 Transformer 对象。
- 创建 DOMSource 对象,将 Document 对象转换成 DOMSource 对象。
- 创建 StreamResult 对象和 FileOutputStream 对象,包含保存文件的信息。
- 调用 Transformer 对象中的方法将 XML 保存到指定文件中。
示例:使用 DOM 添加数据
测试类(cn.duozai.TestMain):
public class TestMain {
public static void main(String[] args) throws Exception {
// 读取并解析XML
// ...
// 创建手机品牌Brand元素对象
Element brandElement = document.createElement("Brand");
// 设置手机品牌Brand元素对象的name属性
brandElement.setAttribute("name", "小米");
// 创建手机型号type元素对象
Element mi15Element = document.createElement("type");
// 设置手机型号type元素对象的name属性
mi15Element.setAttribute("name", "Mi 15");
// 创建型号价格price元素对象
Element priceElement = document.createElement("price");
// 设置型号价格price元素对象的文本内容
priceElement.setTextContent("4999");
// 将型号价格price元素对象追加到手机型号type元素对象中
mi15Element.appendChild(priceElement);
// 将手机型号type元素对象追加到手机品牌Brand元素对象
brandElement.appendChild(mi15Element);
// 将手机品牌Brand元素对象追加到根节点PhoneInfo中
NodeList phoneInfoList = document.getElementsByTagName("PhoneInfo");
Node phoneInfo = phoneInfoList.item(0);
phoneInfo.appendChild(brandElement);
// 保存XML
// 创建转换器工厂TransformerFactory
TransformerFactory tff = TransformerFactory.newInstance();
// 创建转换器对象Transformer
Transformer tf = tff.newTransformer();
// 创建DOMSource对象,将文档对象转换成DOM源对象
DOMSource domSource = new DOMSource(document);
// 创建输出流对象
StreamResult sr = new StreamResult(new FileOutputStream("resources/phone.xml"));
// 将DOM源对象转换成文件
tf.transform(domSource, sr);
}
}示例效果:
使用 DOM 修改数据
使用 DOM 修改数据的基本步骤:
- 为 XML 文档构建 DOM 树。
- 找到符合修改条件的节点。
- 设置该节点的属性为修改值。
- 保存 XML 文档。
示例:使用 DOM 修改数据
测试类(cn.duozai.TestMain):
public class TestMain {
public static void main(String[] args) throws Exception {
// 读取并解析XML
// ...
// 获取手机品牌Brand节点列表
NodeList nodeList = document.getElementsByTagName("Brand");
// 遍历手机品牌Brand节点列表
for (int i = 0; i < nodeList.getLength(); i++) {
// 获取遍历的手机品牌Brand节点对象
// 将手机品牌Brand节点对象转换成元素对象
Element element = (Element) nodeList.item(i);
// 如果手机品牌Brand元素对象的name属性的值等于华为,则修改其属性值
if ("华为".equals(element.getAttribute("name"))) {
element.setAttribute("name", "HUAWEI");
}
}
// 保存XML
// ...
}
}示例效果:
使用 DOM 删除数据
使用 DOM 删除数据的基本步骤:
- 为 XML 文档构建 DOM 树。
- 找到符合删除条件的节点。
- 获取该节点的父节点,从父节点中删除该节点。
- 保存 XML 文档。
示例:使用 DOM 删除数据
测试类(cn.duozai.TestMain):
public class TestMain {
public static void main(String[] args) throws Exception {
// 读取并解析XML
// ...
// 获取手机品牌Brand节点列表
NodeList nodeList = document.getElementsByTagName("Brand");
// 遍历手机品牌Brand节点列表
for (int i = 0; i < nodeList.getLength(); i++) {
// 获取遍历的手机品牌Brand节点对象
// 将手机品牌Brand节点对象转换成元素对象
Element element = (Element) nodeList.item(i);
// 如果手机品牌Brand元素对象的name属性的值等于苹果,则删除该元素对象
if ("苹果".equals(element.getAttribute("name"))) {
// 获取当前元素对象的父节点对象,再从父节点对象中把当前元素对象移除
element.getParentNode().removeChild(element);
}
}
// 保存XML
// ...
}
}示例效果:
使用 DOM4J 解析 XML
DOM4J API 概述
DOM4J 是一个易用、功能强大且开源的 Java XML 处理 API。
使用 DOM4J 操作 XML 时主要使用 Document、Element、Branch、Attribute 对象。
Document 对象代表整个 XML 文档,是 DOM4J 中操作 XML 文档的入口点。
Document 对象的基本方法:
| 名称 | 描述 |
|---|---|
| Element getRootElement() | 获取文档的根元素 |
Element 对象对应 XML 文档中的具体元素标签。
Element 对象的基本方法:
| 名称 | 描述 |
|---|---|
| Element element(String name) | 根据节点名称获取某个节点的单个子节点 |
| List elements() | 获取某个节点的子节点列表 |
| List elements(String name) | 根据节点名称获取某个节点的子节点列表 |
| Attribute attribute(String name) | 根据属性名获取某个节点下的属性 |
| String attributeValue(String name) | 根据属性名获取某个节点下的属性值 |
| Element addAttribute(String name, String value) | 为某个节点添加属性 |
| String getText() | 获取节点文字 |
| void setText(String value) | 设置节点文字 |
Branch 对象是 Element 对象和 Document 对象的抽象父类,定义了一些公共的、用于处理树形结构节点相关的通用方法。
Branch 对象的基本方法:
| 名称 | 描述 |
|---|---|
| Element addElement(String name) | 在某个节点下添加子节点 |
| boolean remove(Node node) | 从父节点中删除某个子节点 |
Attribute 对象表示 XML 元素的属性。
Attribute 对象的基本方法:
| 名称 | 描述 |
|---|---|
| String getText() | 获取属性的值 |
| void setText(String value) | 设置属性的值 |
使用 DOM4J 操作数据
使用 DOM4J 操作 XML 的基本步骤:
- 下载 dom4j 依赖 jar 文件:https://dom4j.github.io/
- 在项目中导入 dom4j 依赖 jar 文件。
- 创建 SAXReader 对象读取 XML 文件。
- 调用 Document、Element 等对象的相关方法操作 XML。
示例:使用 DOM4J 操作数据
导入相关依赖 JAR 文件,并添加为库。
示例效果:
测试类(cn.duozai.TestMain):
public class TestMain {
public static void main(String[] args) throws Exception {
// 创建SAXReader对象读取XML
SAXReader reader = new SAXReader();
Document document = reader.read("resources/phone.xml");
// 获取根元素对象
Element rootElement = document.getRootElement();
// 获取手机品牌Brand子元素列表
List<Element> brandList = rootElement.elements("Brand");
// 遍历手机品牌Brand子元素列表
for (Element brandElement : brandList) {
// 获取手机品牌Brand元素对象的name属性的值
String brandName = brandElement.attributeValue("name");
// 获取手机品牌Brand元素对象的手机型号type子元素列表
List<Element> typeList = brandElement.elements("type");
// 手机型号type元素列表
for (Element typeElement : typeList) {
// 获取手机型号type元素对象的name属性的值
String typeName = typeElement.attributeValue("name");
// 获取手机型号type元素对象的型号价格price子元素对象
Element priceElement = typeElement.element("price");
// 获取型号价格price元素对象的文本内容
String price = priceElement.getText();
// 输出品牌名称+手机类型+价格
// 输出手机品牌名称+手机型号名称+型号价格
System.out.println(brandName + typeName + "的价格是" + price);
}
}
}
}示例效果: