二、XML
2.1 XML 简介
XML 即可扩展标记语言,一种简单的数据存储语言,使用一系列简单的标记来描述结构化数据
XML 的特点
- XML 与操作系统,编程语言的开发平台无关
- 规范统一,实现不同系统之间的数据交互
2.1.1 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 文档结构
2.1.2 XML 声明
<?xml version="1.0" encoding="UTF-8"?>
表示 XML 声明,用于标明这是一个 XML 文件- XML 声明主要有以下部分组成
- version 文档符合 XML 1.0 规范
- encoding 文档字符编码,默认为 UTF-8
- 对于任何一个 XML 文档,都是固定格式
2.1.3 标签
- XML 中,通过用尖括号
<>
括起来的各种标签来标记数据 - 标签必须成对使用,必须有开始标签
<>
和 结束标签</>
- 标签之间是标签描述的内容
- 例如
<author>王珊</author>
则表示作者信息
2.1.4 元素
-
XML 文档的主要部分是元素
-
元素由开始标签、结束标签和元素内容注册
-
元素内容指开始标签和结束标签之间的内容,可以包含子元素,字符数据等
-
元素的命名规则如下
- 名称中可以包含字母、数字或其他的字符
- 名称不能以数字或标点符号开始
- 名称不能以字符
xml
、XML
等开始 - 名称中不能包含空格
- 元素允许是空元素,如
<title></title>
、<title/>
-
根元素
- 每个 XML 文档必须有且仅有一个根元素,如
<books></books>
- 根元素是一个完全包括文档中其他所有元素的元素
- 根元素的起始标签要放在所有其他元素的起始标签之前
- 根元素的结束标签要放在所有其他元素的结束标签之后
- 每个 XML 文档必须有且仅有一个根元素,如
-
属性
<book id="bk101">
标签中使用 id 属性描述图书的编号信息- 属性的定义语法如下
xml<元素名 属性名="属性值">
- 属性值用双引号包裹
- 一个元素可以有多个属性,多个属性之间用空格隔开
- 元素中不能直接包含
<
、"
、&
- 属性只能加在元素的起始标签上
-
XML 中的特殊字符的处理
- 在 XML 中,有时在元素的文本中会涉及一些特殊字符
<
>
'
"
&
- 使用这些字符,需要用到 XML 中的预定义实体代替
- XML 中的预定义实体和特殊字符的对应关系
特殊字符 实体名称 < < > > & &
" "
' '
- 在 XML 中,有时在元素的文本中会涉及一些特殊字符
-
CDATA - (未解析)字符数据
-
术语 CDATA 是不应该由 XML 解析器解析的文本数据。
-
像
<
和&
字符在 XML 元素中都是非法的。 -
<
会产生错误,因为解析器会把该字符解释为新元素的开始。 -
&
会产生错误,因为解析器会把该字符解释为字符实体的开始。 -
CDATA 部分中的所有内容都会被解析器忽略
-
-
CDATA 语法格式如下
xml<![CDATA[要显示的字符]]>
2.2 解析 XML 概述
在实际应用当中,经常需要对 XML 文档进行各种操作
如在应用程序启动时去读取 XML 配置文件信息
或把数据库中的内容读取出来转为 XML 文档形式
这种情况就要运用到 XML 文档的解析技术
目前常用的 XML 解析技术有 4 种
2.2.1 DOM
- DOM 是基于 XML 的树结构来完成解析的
- DOM 解析 XML 文档时,会根据读取的文档,构建一个驻留内存的树结构
- 使用 DOM API 可以操作这个树结构
- 支持删除、修改、重新排列等多种功能
- 但 DOM 解析同时也比较消耗资源
2.2.2 SAZ
- SAZ 是基于事件的解析,为了解决 DMO 解析的资源消耗而出现的
- SAZ 是通过事件处理器完成对文档的解析
- SAZ 不用事先调入整个文档,所以它的优势就是占用资源少,内存消耗小
- 在解析数据量较大的 XML 文档时会采用这种方式
2.2.3 JDOM
- JDOM 是针对 Java 的特定文档模型
- 它简化了与 XML 的交互并且币使用 DOM 更快
- JDOM 仅使用具体类而不使用接口,在某方面简化了 API
- 但是也限制了灵活性
- API 大量使用了 Java 集合类型,对于属性这类的 Java 开发者而简化了使用
2.2.4 DOM4J
- DOM4J 是一个非常优秀的 Java XML API
- 具有性能优异、功能强大、易用的特点
- DOM4J 用于在 Java 平台上使用 Java 集合框架处理 XML、XPath 和 XSLT
- DOM4J 大量使用接口,面向接口编程使它币 JDOM 更加灵活
2.3 使用 DOM 读取 XML 数据
2.3.1 DOM 概念
- DOM 即文档对象模型
- DOM 把 XML 文件映射成一课倒挂的 "树"
- 以根元素为根节点,每个节点都以对象形式存在
- 通过存取这些对象就能存取 XML 文档的内容
- 例如,创建文件 book.xml 并保存,book.xml 内容如下
xml
<?xml version="1.0" encoding="UTF-8"?>
<book id="bk101">
<title>三国演义</title>
<author>罗贯中</author>
<price>30元</price>
</book>
- book.xml 对应的 DOM 树结构
2.3.2 使用 DOM 读取手机收藏信息
- 可以使用 JAXP 来解析 XML
- JAXP 包含 3 个包,这 3 个包都在 JDK 中
- org.w3c.dom:W3C 推荐的用于使用 DOM 解析 XML 文档的接口
- org.xml.sax:用于使用 SAZ 解析 XML 文档的接口
- javax.xml.parsers:解析其工厂工具,获得并配置特殊的解析器
- 使用 DOM 解析 XML 时需要导入这些包中相关的类
- JAXP 会把 XML 文档转换成一个 DOM 树
- 使用 DOM 解析 XML 文档的步骤如下
- 创建解析器工厂对象,即 DocumentBuilderFactory 对象
- 由解析器工厂对象创建解析器对象,即 DocumentBuilder 对象
- 由解析器对象对指定的 XML 文件进行解析,构建相应的 DOM 数,创建 Document 对象
- 以 Document 对象为起点,对DOM 树的节点进行增加、删除、修改、查询等操作
2.3.3 使用 DOM 读取 XML 数据,使用 DOM 读取手机收藏信息中的品牌和型号信息 示例
XML 文档代码如下
xml
<?xml version="1.0" encoding="UTF-8"?>
<PhoneInfo>
<Brand name="华为">
<Type name="P90"/>
</Brand>
<Brand>
<Type name="iPhone Z"/>
<Type name="iPhone ZL"/>
</Brand>
</PhoneInfo>
手机收藏信息的 XML 文档对应的 DOM 树主要结构
根据使用 DOM 解析 XML 的文档步骤,关键代码如下
java
package Test01;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
public class Test01 {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
//得到 DOM 解析器的工厂实例
DocumentBuilderFactory dbf=DocumentBuilderFactory.newDefaultInstance();
//从 DOM 工厂获取 DOM 解析器
DocumentBuilder db=dbf.newDocumentBuilder();
//解析 XML 文档,等到一个 Document 对象,即DOM数
//xml 文件位置,从 src包下开始
Document doc= db.parse("src/main/java/Test01/收藏信息.xml");
//等到所有的 Brand 节点列表信息
NodeList brandList=doc.getElementsByTagName("Brand");
//循环 Brand 信息
for (int i=0; i<brandList.getLength();i++){
//获取第 i 个 Brand 元素信息
Node brand=brandList.item(i);
//获取第 i 个 Brand 元素的 name属性
Element element= (Element) brand;
String attrValue=element.getAttribute("name");
//获取第 i 个 Brand 元素的所有子元素的 name 属性值
NodeList types=element.getChildNodes();
for (int j = 0; j <types.getLength() ; j++) {
Node node=types.item(j);
if (node.getNodeType()==Node.ELEMENT_NODE){
Element typeElement= ((Element) types.item(j));
String type=typeElement.getAttribute("name");
System.out.println("手机"+attrValue+type);
}
}
}
}
}
2.3.4 使用 DOM 解析 XML 时主要使用以下对象
Node 对象
- Node 对象是 DOM 结构中的基本对象,代表了文档树中的一个抽象节点
- Node 对象的主要方法如下
方法名 | 说明 |
---|---|
getChildNodes() | 返回包含此节点所有子节点 NodeList |
getFirstChild() | 如果节点存在子节点,则返回第一个子节点 |
getLastChild() | 如果节点存在子节点,则返回最后一个子节点 |
getNextSibling() | 返回在 DOM 树中这个节点的下一个兄弟节点 |
getPreviousSibling() | 返回在 DOM 树中这个节点的上一个兄弟节点 |
getNodeName() | 返回节点的名称 |
getNodeValue() | 返回节点的值 |
getNodeType() | 返回节点的类型 |
NodeList 对象
- NodeList 对象是指包含了一个或多个节点 (Node) 列表
- 可以通过方法来获取列表中的元素
- NodeList 对象的常用方法
方法名 | 说明 |
---|---|
getLength() | 返回列表长度 |
item(int idnex) | 返回指定位置的 Node 对象 |
Document 对象
- Document 对象代表整个 XML 文档
- 所有其他的 Node 都以一定的顺序包含在 Document 对象之内
- 它是对 XML 文档进行操作的起点,先通过解析 XML 源文件获取 Document 对象然后来执行后续的操作
- Document 对象的主要方法
方法名 | 说明 |
---|---|
getElementsByTagName(String name) | 返回一个 NodeList 对象,包含所有给定标签名的标签 |
getDocumentElement() | 返回一个代表这个 DOM 树的根节点的 Element 对象 |
Element 对象
- Element 对象代表 XML了文档中的 标签元素
- 在标签中可以包含属性,因而 Element 对象中也有存取属性的方法
- Element 对象方法如下
方法名 | 说明 |
---|---|
getAttribute(String attributename) | 返回标签中给定属性名称的属性的值 |
getElementsByTagName(String name) | 返回具有给定标签名称的所有后代 Elements 的 NodeList |
注意事项
- XML 文档中的空白符也会被作为对象映射在 DOM 树中
- 所以直接调用 Node 对象的 getChildNodes() 方法有时会出现一些问题
- 解决方案如下
- 使用 Element 的 getElementByTagName(String name),返回的 NodeList 对象就是所期待的对象
- 调用 Node 的 getChildNodes() 方法得到 NodeList 对象,每次通过 item() 方法提取 Node 对象然后判断
- 判断
node.getNodeType()==Node.ELEMENT_NODE
即判断是否为元素节点
2.4 使用 DOM4J 解析 XML
2.4.1 DOM4J API 概述
- 使用 DOM4J 只要了解 XML-DOM 模型就能使用
- DOM4J 主要接口都在 org.dom4j 这个包里定义
类 | 说明 |
---|---|
Attribute | 定义了 XML 属性 |
Branch | 为能够包含子节点的节点,定义了一个公共行为 |
CDATA | 定义了 XML CDATA 区域 |
CharacterData | 是一个标识接口,标识基于字符的节点,如 CDATA、Comment 和 Text |
Comment | 定义了 XML 注释的行为 |
Document | 定义了 XML 文档 |
DocumentType | 定义 XML DOCTYPE 声明 |
Element | 定义了 XML 元素 |
ElementHandler | 定义了 Element 对象的处理器 |
ElementPath | 被 ElementHandler 使用,用于取得当前正在处理的路径层次信息 |
Entity | 定义 XML 实体 |
Node | 为 dom4j 中所有的 XML 节点定义了多态行为 |
NodeFilter | 定义了在 dom4j 节点中产生的一个滤镜或谓词的行为 |
ProcessingInstruction | 定义 XML 处理指令 |
Text | 定义了 XML 文本节点 |
Visitor | 用于实现 Visitor 模式 |
XPath | 通过分析一个字符串提供一个 XPath 表达式 |
- 使用这些需要提前导入一个 dom4j 的包
xml
<!-- https://mvnrepository.com/artifact/org.dom4j/dom4j -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
</dependency>
2.4.2 使用 DOM4J 操作 XML 数据
1、Document 对象相关
- 读取 XML 文件,获得 Document 对象
java
SAXReader reader=new SAXReader();
Document document=reader.read(new File("input.xml"));
2、节点相关
- 获得文档的根元素
java
Element rootElm=document.getRootElement();
- 取得某节点的单个子节点
java
Element memberElm=rootElm.element("member"); //member 是节点名
- 取得节点的文字
java
String text=emeberElm.getText();
//或者用下面这种方式
//取得根元素下的 name 子节点的文字
String text=rootElm.elementText("name");
- 在某个节点下添加子节点,newMemberElm 是某个已存在的节点
java
Element ageElm=newMemberElm.addELment("age");
- 设置文字节点
java
ageElm.setText("29");
- 删除某节点
java
parentElm.remove(childElm);// childElm 是待删除的节点,parentElm是其父节点
3、属性相关
- 取得某节点下的某属性
java
Element root=document.getRootElement();
Attribute attribute=toor.attribute("size"); //属性名 size
- 取得属性的值
java
String text=attribute.getText();
//也可以使用
String text2=root.element("name").attributeValue("firstname");
- 为某节点添加属性
java
newMemberElm.addAttribute("name","learningdom4j");
- 设置属性的值
java
Attribute attribute=root.attribute("name");
attribute.setText("learningdom4j");
- 删除某属性
java
Attribute attribute=root.attribute("size"); //属性名saize
root.remove(attribute)
e attribute=toor.attribute("size"); //属性名 size
- 取得属性的值
~~~java
String text=attribute.getText();
//也可以使用
String text2=root.element("name").attributeValue("firstname");
- 为某节点添加属性
java
newMemberElm.addAttribute("name","learningdom4j");
- 设置属性的值
java
Attribute attribute=root.attribute("name");
attribute.setText("learningdom4j");
- 删除某属性
java
Attribute attribute=root.attribute("size"); //属性名saize
root.remove(attribute)